Blame SOURCES/0005-vhost-add-support-for-non-contiguous-indirect-descs-.patch

c7ffa4
From 9fc3d1245bec49e29013b8120340e87adeaaf11a Mon Sep 17 00:00:00 2001
c7ffa4
From: Maxime Coquelin <maxime.coquelin@redhat.com>
c7ffa4
Date: Mon, 23 Apr 2018 11:33:42 +0200
c7ffa4
Subject: [PATCH 05/11] vhost: add support for non-contiguous indirect descs
c7ffa4
 tables
c7ffa4
c7ffa4
This patch adds support for non-contiguous indirect descriptor
c7ffa4
tables in VA space.
c7ffa4
c7ffa4
When it happens, which is unlikely, a table is allocated and the
c7ffa4
non-contiguous content is copied into it.
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/virtio_net.c | 108 +++++++++++++++++++++++++++++++++++++++---
c7ffa4
 1 file changed, 101 insertions(+), 7 deletions(-)
c7ffa4
c7ffa4
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
c7ffa4
index 79bac59..13252e6 100644
c7ffa4
--- a/lib/librte_vhost/virtio_net.c
c7ffa4
+++ b/lib/librte_vhost/virtio_net.c
c7ffa4
@@ -46,4 +46,5 @@
c7ffa4
 #include <rte_arp.h>
c7ffa4
 #include <rte_spinlock.h>
c7ffa4
+#include <rte_malloc.h>
c7ffa4
 
c7ffa4
 #include "iotlb.h"
c7ffa4
@@ -60,4 +61,44 @@
c7ffa4
 }
c7ffa4
 
c7ffa4
+static __rte_always_inline struct vring_desc *
c7ffa4
+alloc_copy_ind_table(struct virtio_net *dev, struct vhost_virtqueue *vq,
c7ffa4
+					 struct vring_desc *desc)
c7ffa4
+{
c7ffa4
+	struct vring_desc *idesc;
c7ffa4
+	uint64_t src, dst;
c7ffa4
+	uint64_t len, remain = desc->len;
c7ffa4
+	uint64_t desc_addr = desc->addr;
c7ffa4
+
c7ffa4
+	idesc = rte_malloc(__func__, desc->len, 0);
c7ffa4
+	if (unlikely(!idesc))
c7ffa4
+		return 0;
c7ffa4
+
c7ffa4
+	dst = (uint64_t)(uintptr_t)idesc;
c7ffa4
+
c7ffa4
+	while (remain) {
c7ffa4
+		len = remain;
c7ffa4
+		src = vhost_iova_to_vva(dev, vq, desc_addr, &len,
c7ffa4
+				VHOST_ACCESS_RO);
c7ffa4
+		if (unlikely(!src || !len)) {
c7ffa4
+			rte_free(idesc);
c7ffa4
+			return 0;
c7ffa4
+		}
c7ffa4
+
c7ffa4
+		rte_memcpy((void *)(uintptr_t)dst, (void *)(uintptr_t)src, len);
c7ffa4
+
c7ffa4
+		remain -= len;
c7ffa4
+		dst += len;
c7ffa4
+		desc_addr += len;
c7ffa4
+	}
c7ffa4
+
c7ffa4
+	return idesc;
c7ffa4
+}
c7ffa4
+
c7ffa4
+static __rte_always_inline void
c7ffa4
+free_ind_table(struct vring_desc *idesc)
c7ffa4
+{
c7ffa4
+	rte_free(idesc);
c7ffa4
+}
c7ffa4
+
c7ffa4
 static __rte_always_inline void
c7ffa4
 do_flush_shadow_used_ring(struct virtio_net *dev, struct vhost_virtqueue *vq,
c7ffa4
@@ -376,4 +417,5 @@
c7ffa4
 	rte_prefetch0(&vq->desc[desc_indexes[0]]);
c7ffa4
 	for (i = 0; i < count; i++) {
c7ffa4
+		struct vring_desc *idesc = NULL;
c7ffa4
 		uint16_t desc_idx = desc_indexes[i];
c7ffa4
 		int err;
c7ffa4
@@ -385,10 +427,22 @@
c7ffa4
 						vq, vq->desc[desc_idx].addr,
c7ffa4
 						&dlen, VHOST_ACCESS_RO);
c7ffa4
-			if (unlikely(!descs ||
c7ffa4
-					dlen != vq->desc[desc_idx].len)) {
c7ffa4
+			if (unlikely(!descs)) {
c7ffa4
 				count = i;
c7ffa4
 				break;
c7ffa4
 			}
c7ffa4
 
c7ffa4
+			if (unlikely(dlen < vq->desc[desc_idx].len)) {
c7ffa4
+				/*
c7ffa4
+				 * The indirect desc table is not contiguous
c7ffa4
+				 * in process VA space, we have to copy it.
c7ffa4
+				 */
c7ffa4
+				idesc = alloc_copy_ind_table(dev, vq,
c7ffa4
+							&vq->desc[desc_idx]);
c7ffa4
+				if (unlikely(!idesc))
c7ffa4
+					break;
c7ffa4
+
c7ffa4
+				descs = idesc;
c7ffa4
+			}
c7ffa4
+
c7ffa4
 			desc_idx = 0;
c7ffa4
 			sz = vq->desc[desc_idx].len / sizeof(*descs);
c7ffa4
@@ -401,4 +455,5 @@
c7ffa4
 		if (unlikely(err)) {
c7ffa4
 			count = i;
c7ffa4
+			free_ind_table(idesc);
c7ffa4
 			break;
c7ffa4
 		}
c7ffa4
@@ -406,4 +461,7 @@
c7ffa4
 		if (i + 1 < count)
c7ffa4
 			rte_prefetch0(&vq->desc[desc_indexes[i+1]]);
c7ffa4
+
c7ffa4
+		if (unlikely(!!idesc))
c7ffa4
+			free_ind_table(idesc);
c7ffa4
 	}
c7ffa4
 
c7ffa4
@@ -446,4 +504,5 @@
c7ffa4
 	uint64_t dlen;
c7ffa4
 	struct vring_desc *descs = vq->desc;
c7ffa4
+	struct vring_desc *idesc = NULL;
c7ffa4
 
c7ffa4
 	*desc_chain_head = idx;
c7ffa4
@@ -455,13 +514,27 @@
c7ffa4
 						&dlen,
c7ffa4
 						VHOST_ACCESS_RO);
c7ffa4
-		if (unlikely(!descs || dlen != vq->desc[idx].len))
c7ffa4
+		if (unlikely(!descs))
c7ffa4
 			return -1;
c7ffa4
 
c7ffa4
+		if (unlikely(dlen < vq->desc[idx].len)) {
c7ffa4
+			/*
c7ffa4
+			 * The indirect desc table is not contiguous
c7ffa4
+			 * in process VA space, we have to copy it.
c7ffa4
+			 */
c7ffa4
+			idesc = alloc_copy_ind_table(dev, vq, &vq->desc[idx]);
c7ffa4
+			if (unlikely(!idesc))
c7ffa4
+				return -1;
c7ffa4
+
c7ffa4
+			descs = idesc;
c7ffa4
+		}
c7ffa4
+
c7ffa4
 		idx = 0;
c7ffa4
 	}
c7ffa4
 
c7ffa4
 	while (1) {
c7ffa4
-		if (unlikely(vec_id >= BUF_VECTOR_MAX || idx >= vq->size))
c7ffa4
+		if (unlikely(vec_id >= BUF_VECTOR_MAX || idx >= vq->size)) {
c7ffa4
+			free_ind_table(idesc);
c7ffa4
 			return -1;
c7ffa4
+		}
c7ffa4
 
c7ffa4
 		len += descs[idx].len;
c7ffa4
@@ -480,4 +553,7 @@
c7ffa4
 	*vec_idx = vec_id;
c7ffa4
 
c7ffa4
+	if (unlikely(!!idesc))
c7ffa4
+		free_ind_table(idesc);
c7ffa4
+
c7ffa4
 	return 0;
c7ffa4
 }
c7ffa4
@@ -1333,5 +1409,5 @@
c7ffa4
 	rte_prefetch0(&vq->desc[desc_indexes[0]]);
c7ffa4
 	for (i = 0; i < count; i++) {
c7ffa4
-		struct vring_desc *desc;
c7ffa4
+		struct vring_desc *desc, *idesc = NULL;
c7ffa4
 		uint16_t sz, idx;
c7ffa4
 		uint64_t dlen;
c7ffa4
@@ -1348,8 +1424,20 @@
c7ffa4
 						&dlen,
c7ffa4
 						VHOST_ACCESS_RO);
c7ffa4
-			if (unlikely(!desc ||
c7ffa4
-					dlen != vq->desc[desc_indexes[i]].len))
c7ffa4
+			if (unlikely(!desc))
c7ffa4
 				break;
c7ffa4
 
c7ffa4
+			if (unlikely(dlen < vq->desc[desc_indexes[i]].len)) {
c7ffa4
+				/*
c7ffa4
+				 * The indirect desc table is not contiguous
c7ffa4
+				 * in process VA space, we have to copy it.
c7ffa4
+				 */
c7ffa4
+				idesc = alloc_copy_ind_table(dev, vq,
c7ffa4
+						&vq->desc[desc_indexes[i]]);
c7ffa4
+				if (unlikely(!idesc))
c7ffa4
+					break;
c7ffa4
+
c7ffa4
+				desc = idesc;
c7ffa4
+			}
c7ffa4
+
c7ffa4
 			rte_prefetch0(desc);
c7ffa4
 			sz = vq->desc[desc_indexes[i]].len / sizeof(*desc);
c7ffa4
@@ -1365,4 +1453,5 @@
c7ffa4
 			RTE_LOG(ERR, VHOST_DATA,
c7ffa4
 				"Failed to allocate memory for mbuf.\n");
c7ffa4
+			free_ind_table(idesc);
c7ffa4
 			break;
c7ffa4
 		}
c7ffa4
@@ -1372,4 +1461,5 @@
c7ffa4
 		if (unlikely(err)) {
c7ffa4
 			rte_pktmbuf_free(pkts[i]);
c7ffa4
+			free_ind_table(idesc);
c7ffa4
 			break;
c7ffa4
 		}
c7ffa4
@@ -1381,4 +1471,5 @@
c7ffa4
 			if (!zmbuf) {
c7ffa4
 				rte_pktmbuf_free(pkts[i]);
c7ffa4
+				free_ind_table(idesc);
c7ffa4
 				break;
c7ffa4
 			}
c7ffa4
@@ -1397,4 +1488,7 @@
c7ffa4
 			TAILQ_INSERT_TAIL(&vq->zmbuf_list, zmbuf, next);
c7ffa4
 		}
c7ffa4
+
c7ffa4
+		if (unlikely(!!idesc))
c7ffa4
+			free_ind_table(idesc);
c7ffa4
 	}
c7ffa4
 	vq->last_avail_idx += i;
c7ffa4
-- 
c7ffa4
1.8.3.1
c7ffa4