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

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