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

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