Blame SOURCES/0004-vhost-ensure-all-range-is-mapped-when-translating-QV.patch

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