|
|
a6040a |
From 053e6774348c5a497a12b27d6120527c7af5e503 Mon Sep 17 00:00:00 2001
|
|
|
a6040a |
From: Maxime Coquelin <maxime.coquelin@redhat.com>
|
|
|
a6040a |
Date: Mon, 23 Apr 2018 11:33:41 +0200
|
|
|
a6040a |
Subject: [PATCH 04/11] vhost: ensure all range is mapped when translating QVAs
|
|
|
a6040a |
|
|
|
a6040a |
This patch ensures that all the address range is mapped when
|
|
|
a6040a |
translating addresses from master's addresses (e.g. QEMU host
|
|
|
a6040a |
addressess) to process VAs.
|
|
|
a6040a |
|
|
|
a6040a |
This issue has been assigned CVE-2018-1059.
|
|
|
a6040a |
|
|
|
a6040a |
Reported-by: Yongji Xie <xieyongji@baidu.com>
|
|
|
a6040a |
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
|
|
|
a6040a |
---
|
|
|
a6040a |
lib/librte_vhost/vhost_user.c | 58 +++++++++++++++++++++++++++----------------
|
|
|
a6040a |
1 file changed, 36 insertions(+), 22 deletions(-)
|
|
|
a6040a |
|
|
|
a6040a |
diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
|
|
|
a6040a |
index 3acaacf..50e654d 100644
|
|
|
a6040a |
--- a/lib/librte_vhost/vhost_user.c
|
|
|
a6040a |
+++ b/lib/librte_vhost/vhost_user.c
|
|
|
a6040a |
@@ -330,19 +330,24 @@
|
|
|
a6040a |
/* Converts QEMU virtual address to Vhost virtual address. */
|
|
|
a6040a |
static uint64_t
|
|
|
a6040a |
-qva_to_vva(struct virtio_net *dev, uint64_t qva)
|
|
|
a6040a |
+qva_to_vva(struct virtio_net *dev, uint64_t qva, uint64_t *len)
|
|
|
a6040a |
{
|
|
|
a6040a |
- struct rte_vhost_mem_region *reg;
|
|
|
a6040a |
+ struct rte_vhost_mem_region *r;
|
|
|
a6040a |
uint32_t i;
|
|
|
a6040a |
|
|
|
a6040a |
/* Find the region where the address lives. */
|
|
|
a6040a |
for (i = 0; i < dev->mem->nregions; i++) {
|
|
|
a6040a |
- reg = &dev->mem->regions[i];
|
|
|
a6040a |
+ r = &dev->mem->regions[i];
|
|
|
a6040a |
|
|
|
a6040a |
- if (qva >= reg->guest_user_addr &&
|
|
|
a6040a |
- qva < reg->guest_user_addr + reg->size) {
|
|
|
a6040a |
- return qva - reg->guest_user_addr +
|
|
|
a6040a |
- reg->host_user_addr;
|
|
|
a6040a |
+ if (qva >= r->guest_user_addr &&
|
|
|
a6040a |
+ qva < r->guest_user_addr + r->size) {
|
|
|
a6040a |
+
|
|
|
a6040a |
+ if (unlikely(*len > r->guest_user_addr + r->size - qva))
|
|
|
a6040a |
+ *len = r->guest_user_addr + r->size - qva;
|
|
|
a6040a |
+
|
|
|
a6040a |
+ return qva - r->guest_user_addr +
|
|
|
a6040a |
+ r->host_user_addr;
|
|
|
a6040a |
}
|
|
|
a6040a |
}
|
|
|
a6040a |
+ *len = 0;
|
|
|
a6040a |
|
|
|
a6040a |
return 0;
|
|
|
a6040a |
@@ -357,5 +362,5 @@
|
|
|
a6040a |
static uint64_t
|
|
|
a6040a |
ring_addr_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
|
|
|
a6040a |
- uint64_t ra, uint64_t size)
|
|
|
a6040a |
+ uint64_t ra, uint64_t *size)
|
|
|
a6040a |
{
|
|
|
a6040a |
if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)) {
|
|
|
a6040a |
@@ -363,5 +368,5 @@
|
|
|
a6040a |
|
|
|
a6040a |
vva = vhost_user_iotlb_cache_find(vq, ra,
|
|
|
a6040a |
- &size, VHOST_ACCESS_RW);
|
|
|
a6040a |
+ size, VHOST_ACCESS_RW);
|
|
|
a6040a |
if (!vva)
|
|
|
a6040a |
vhost_user_iotlb_miss(dev, ra, VHOST_ACCESS_RW);
|
|
|
a6040a |
@@ -370,5 +375,5 @@
|
|
|
a6040a |
}
|
|
|
a6040a |
|
|
|
a6040a |
- return qva_to_vva(dev, ra);
|
|
|
a6040a |
+ return qva_to_vva(dev, ra, size);
|
|
|
a6040a |
}
|
|
|
a6040a |
|
|
|
a6040a |
@@ -378,4 +383,5 @@
|
|
|
a6040a |
struct vhost_virtqueue *vq = dev->virtqueue[vq_index];
|
|
|
a6040a |
struct vhost_vring_addr *addr = &vq->ring_addrs;
|
|
|
a6040a |
+ uint64_t len;
|
|
|
a6040a |
|
|
|
a6040a |
/* The addresses are converted from QEMU virtual to Vhost virtual. */
|
|
|
a6040a |
@@ -383,9 +389,10 @@
|
|
|
a6040a |
return dev;
|
|
|
a6040a |
|
|
|
a6040a |
+ len = sizeof(struct vring_desc) * vq->size;
|
|
|
a6040a |
vq->desc = (struct vring_desc *)(uintptr_t)ring_addr_to_vva(dev,
|
|
|
a6040a |
- vq, addr->desc_user_addr, sizeof(struct vring_desc));
|
|
|
a6040a |
- if (vq->desc == 0) {
|
|
|
a6040a |
+ vq, addr->desc_user_addr, &len;;
|
|
|
a6040a |
+ if (vq->desc == 0 || len != sizeof(struct vring_desc) * vq->size) {
|
|
|
a6040a |
RTE_LOG(DEBUG, VHOST_CONFIG,
|
|
|
a6040a |
- "(%d) failed to find desc ring address.\n",
|
|
|
a6040a |
+ "(%d) failed to map desc ring.\n",
|
|
|
a6040a |
dev->vid);
|
|
|
a6040a |
return dev;
|
|
|
a6040a |
@@ -396,18 +403,24 @@
|
|
|
a6040a |
addr = &vq->ring_addrs;
|
|
|
a6040a |
|
|
|
a6040a |
+ len = sizeof(struct vring_avail) + sizeof(uint16_t) * vq->size;
|
|
|
a6040a |
vq->avail = (struct vring_avail *)(uintptr_t)ring_addr_to_vva(dev,
|
|
|
a6040a |
- vq, addr->avail_user_addr, sizeof(struct vring_avail));
|
|
|
a6040a |
- if (vq->avail == 0) {
|
|
|
a6040a |
+ vq, addr->avail_user_addr, &len;;
|
|
|
a6040a |
+ if (vq->avail == 0 ||
|
|
|
a6040a |
+ len != sizeof(struct vring_avail) +
|
|
|
a6040a |
+ sizeof(uint16_t) * vq->size) {
|
|
|
a6040a |
RTE_LOG(DEBUG, VHOST_CONFIG,
|
|
|
a6040a |
- "(%d) failed to find avail ring address.\n",
|
|
|
a6040a |
+ "(%d) failed to map avail ring.\n",
|
|
|
a6040a |
dev->vid);
|
|
|
a6040a |
return dev;
|
|
|
a6040a |
}
|
|
|
a6040a |
|
|
|
a6040a |
+ len = sizeof(struct vring_used) +
|
|
|
a6040a |
+ sizeof(struct vring_used_elem) * vq->size;
|
|
|
a6040a |
vq->used = (struct vring_used *)(uintptr_t)ring_addr_to_vva(dev,
|
|
|
a6040a |
- vq, addr->used_user_addr, sizeof(struct vring_used));
|
|
|
a6040a |
- if (vq->used == 0) {
|
|
|
a6040a |
+ vq, addr->used_user_addr, &len;;
|
|
|
a6040a |
+ if (vq->used == 0 || len != sizeof(struct vring_used) +
|
|
|
a6040a |
+ sizeof(struct vring_used_elem) * vq->size) {
|
|
|
a6040a |
RTE_LOG(DEBUG, VHOST_CONFIG,
|
|
|
a6040a |
- "(%d) failed to find used ring address.\n",
|
|
|
a6040a |
+ "(%d) failed to map used ring.\n",
|
|
|
a6040a |
dev->vid);
|
|
|
a6040a |
return dev;
|
|
|
a6040a |
@@ -1095,9 +1108,10 @@
|
|
|
a6040a |
struct vhost_iotlb_msg *imsg = &msg->payload.iotlb;
|
|
|
a6040a |
uint16_t i;
|
|
|
a6040a |
- uint64_t vva;
|
|
|
a6040a |
+ uint64_t vva, len;
|
|
|
a6040a |
|
|
|
a6040a |
switch (imsg->type) {
|
|
|
a6040a |
case VHOST_IOTLB_UPDATE:
|
|
|
a6040a |
- vva = qva_to_vva(dev, imsg->uaddr);
|
|
|
a6040a |
+ len = imsg->size;
|
|
|
a6040a |
+ vva = qva_to_vva(dev, imsg->uaddr, &len;;
|
|
|
a6040a |
if (!vva)
|
|
|
a6040a |
return -1;
|
|
|
a6040a |
@@ -1107,5 +1121,5 @@
|
|
|
a6040a |
|
|
|
a6040a |
vhost_user_iotlb_cache_insert(vq, imsg->iova, vva,
|
|
|
a6040a |
- imsg->size, imsg->perm);
|
|
|
a6040a |
+ len, imsg->perm);
|
|
|
a6040a |
|
|
|
a6040a |
if (is_vring_iotlb_update(vq, imsg))
|
|
|
a6040a |
--
|
|
|
a6040a |
1.8.3.1
|
|
|
a6040a |
|