Blame SOURCES/0006-vhost-handle-virtually-non-contiguous-buffers-in-Tx.patch

c7ffa4
From ee0d896b3c3ba2dbf5a7a2598a2d8dbe242a0aa7 Mon Sep 17 00:00:00 2001
c7ffa4
From: Maxime Coquelin <maxime.coquelin@redhat.com>
c7ffa4
Date: Mon, 23 Apr 2018 11:33:43 +0200
c7ffa4
Subject: [PATCH 06/11] vhost: handle virtually non-contiguous buffers in Tx
c7ffa4
c7ffa4
This patch enables the handling of buffers non-contiguous in
c7ffa4
process virtual address space in the dequeue path.
c7ffa4
c7ffa4
When virtio-net header doesn't fit in a single chunck, it is
c7ffa4
copied into a local variablei before being processed.
c7ffa4
c7ffa4
For packet content, the copy length is limited to the chunck
c7ffa4
size, next chuncks VAs being fetched afterward.
c7ffa4
c7ffa4
This issue has been assigned CVE-2018-1059.
c7ffa4
c7ffa4
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
c7ffa4
---
c7ffa4
 lib/librte_vhost/virtio_net.c | 117 ++++++++++++++++++++++++++++++++++--------
c7ffa4
 1 file changed, 95 insertions(+), 22 deletions(-)
c7ffa4
c7ffa4
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
c7ffa4
index 13252e6..47717a1 100644
c7ffa4
--- a/lib/librte_vhost/virtio_net.c
c7ffa4
+++ b/lib/librte_vhost/virtio_net.c
c7ffa4
@@ -996,10 +996,11 @@
c7ffa4
 {
c7ffa4
 	struct vring_desc *desc;
c7ffa4
-	uint64_t desc_addr;
c7ffa4
+	uint64_t desc_addr, desc_gaddr;
c7ffa4
 	uint32_t desc_avail, desc_offset;
c7ffa4
 	uint32_t mbuf_avail, mbuf_offset;
c7ffa4
 	uint32_t cpy_len;
c7ffa4
-	uint64_t dlen;
c7ffa4
+	uint64_t desc_chunck_len;
c7ffa4
 	struct rte_mbuf *cur = m, *prev = m;
c7ffa4
+	struct virtio_net_hdr tmp_hdr;
c7ffa4
 	struct virtio_net_hdr *hdr = NULL;
c7ffa4
 	/* A counter to avoid desc dead loop chain */
c7ffa4
@@ -1016,10 +1017,11 @@
c7ffa4
 	}
c7ffa4
 
c7ffa4
-	dlen = desc->len;
c7ffa4
+	desc_chunck_len = desc->len;
c7ffa4
+	desc_gaddr = desc->addr;
c7ffa4
 	desc_addr = vhost_iova_to_vva(dev,
c7ffa4
-					vq, desc->addr,
c7ffa4
-					&dlen,
c7ffa4
+					vq, desc_gaddr,
c7ffa4
+					&desc_chunck_len,
c7ffa4
 					VHOST_ACCESS_RO);
c7ffa4
-	if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
+	if (unlikely(!desc_addr)) {
c7ffa4
 		error = -1;
c7ffa4
 		goto out;
c7ffa4
@@ -1027,6 +1029,38 @@
c7ffa4
 
c7ffa4
 	if (virtio_net_with_host_offload(dev)) {
c7ffa4
-		hdr = (struct virtio_net_hdr *)((uintptr_t)desc_addr);
c7ffa4
-		rte_prefetch0(hdr);
c7ffa4
+		if (unlikely(desc_chunck_len < sizeof(struct virtio_net_hdr))) {
c7ffa4
+			uint64_t len = desc_chunck_len;
c7ffa4
+			uint64_t remain = sizeof(struct virtio_net_hdr);
c7ffa4
+			uint64_t src = desc_addr;
c7ffa4
+			uint64_t dst = (uint64_t)(uintptr_t)&tmp_hdr;
c7ffa4
+			uint64_t guest_addr = desc_gaddr;
c7ffa4
+
c7ffa4
+			/*
c7ffa4
+			 * No luck, the virtio-net header doesn't fit
c7ffa4
+			 * in a contiguous virtual area.
c7ffa4
+			 */
c7ffa4
+			while (remain) {
c7ffa4
+				len = remain;
c7ffa4
+				src = vhost_iova_to_vva(dev, vq,
c7ffa4
+						guest_addr, &len,
c7ffa4
+						VHOST_ACCESS_RO);
c7ffa4
+				if (unlikely(!src || !len)) {
c7ffa4
+					error = -1;
c7ffa4
+					goto out;
c7ffa4
+				}
c7ffa4
+
c7ffa4
+				rte_memcpy((void *)(uintptr_t)dst,
c7ffa4
+						   (void *)(uintptr_t)src, len);
c7ffa4
+
c7ffa4
+				guest_addr += len;
c7ffa4
+				remain -= len;
c7ffa4
+				dst += len;
c7ffa4
+			}
c7ffa4
+
c7ffa4
+			hdr = &tmp_hdr;
c7ffa4
+		} else {
c7ffa4
+			hdr = (struct virtio_net_hdr *)((uintptr_t)desc_addr);
c7ffa4
+			rte_prefetch0(hdr);
c7ffa4
+		}
c7ffa4
 	}
c7ffa4
 
c7ffa4
@@ -1044,10 +1078,11 @@
c7ffa4
 		}
c7ffa4
 
c7ffa4
-		dlen = desc->len;
c7ffa4
+		desc_chunck_len = desc->len;
c7ffa4
+		desc_gaddr = desc->addr;
c7ffa4
 		desc_addr = vhost_iova_to_vva(dev,
c7ffa4
-							vq, desc->addr,
c7ffa4
-							&dlen,
c7ffa4
+							vq, desc_gaddr,
c7ffa4
+							&desc_chunck_len,
c7ffa4
 							VHOST_ACCESS_RO);
c7ffa4
-		if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
+		if (unlikely(!desc_addr)) {
c7ffa4
 			error = -1;
c7ffa4
 			goto out;
c7ffa4
@@ -1059,10 +1094,28 @@
c7ffa4
 	} else {
c7ffa4
 		desc_avail  = desc->len - dev->vhost_hlen;
c7ffa4
-		desc_offset = dev->vhost_hlen;
c7ffa4
+
c7ffa4
+		if (unlikely(desc_chunck_len < dev->vhost_hlen)) {
c7ffa4
+			desc_chunck_len = desc_avail;
c7ffa4
+			desc_gaddr += dev->vhost_hlen;
c7ffa4
+			desc_addr = vhost_iova_to_vva(dev,
c7ffa4
+					vq, desc_gaddr,
c7ffa4
+					&desc_chunck_len,
c7ffa4
+					VHOST_ACCESS_RO);
c7ffa4
+			if (unlikely(!desc_addr)) {
c7ffa4
+				error = -1;
c7ffa4
+				goto out;
c7ffa4
+			}
c7ffa4
+
c7ffa4
+			desc_offset = 0;
c7ffa4
+		} else {
c7ffa4
+			desc_offset = dev->vhost_hlen;
c7ffa4
+			desc_chunck_len -= dev->vhost_hlen;
c7ffa4
+		}
c7ffa4
 	}
c7ffa4
 
c7ffa4
 	rte_prefetch0((void *)(uintptr_t)(desc_addr + desc_offset));
c7ffa4
 
c7ffa4
-	PRINT_PACKET(dev, (uintptr_t)(desc_addr + desc_offset), desc_avail, 0);
c7ffa4
+	PRINT_PACKET(dev, (uintptr_t)(desc_addr + desc_offset),
c7ffa4
+			desc_chunck_len, 0);
c7ffa4
 
c7ffa4
 	mbuf_offset = 0;
c7ffa4
@@ -1071,5 +1124,5 @@
c7ffa4
 		uint64_t hpa;
c7ffa4
 
c7ffa4
-		cpy_len = RTE_MIN(desc_avail, mbuf_avail);
c7ffa4
+		cpy_len = RTE_MIN(desc_chunck_len, mbuf_avail);
c7ffa4
 
c7ffa4
 		/*
c7ffa4
@@ -1079,5 +1132,5 @@
c7ffa4
 		 */
c7ffa4
 		if (unlikely(dev->dequeue_zero_copy && (hpa = gpa_to_hpa(dev,
c7ffa4
-					desc->addr + desc_offset, cpy_len)))) {
c7ffa4
+					desc_gaddr + desc_offset, cpy_len)))) {
c7ffa4
 			cur->data_len = cpy_len;
c7ffa4
 			cur->data_off = 0;
c7ffa4
@@ -1094,5 +1147,6 @@
c7ffa4
 			if (likely(cpy_len > MAX_BATCH_LEN ||
c7ffa4
 				   copy_nb >= vq->size ||
c7ffa4
-				   (hdr && cur == m))) {
c7ffa4
+				   (hdr && cur == m) ||
c7ffa4
+				   desc->len != desc_chunck_len)) {
c7ffa4
 				rte_memcpy(rte_pktmbuf_mtod_offset(cur, void *,
c7ffa4
 								   mbuf_offset),
c7ffa4
@@ -1115,4 +1169,5 @@
c7ffa4
 		mbuf_offset += cpy_len;
c7ffa4
 		desc_avail  -= cpy_len;
c7ffa4
+		desc_chunck_len -= cpy_len;
c7ffa4
 		desc_offset += cpy_len;
c7ffa4
 
c7ffa4
@@ -1133,9 +1188,11 @@
c7ffa4
 			}
c7ffa4
 
c7ffa4
-			dlen = desc->len;
c7ffa4
+			desc_chunck_len = desc->len;
c7ffa4
+			desc_gaddr = desc->addr;
c7ffa4
 			desc_addr = vhost_iova_to_vva(dev,
c7ffa4
-							vq, desc->addr,
c7ffa4
-							&dlen, VHOST_ACCESS_RO);
c7ffa4
-			if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
+							vq, desc_gaddr,
c7ffa4
+							&desc_chunck_len,
c7ffa4
+							VHOST_ACCESS_RO);
c7ffa4
+			if (unlikely(!desc_addr)) {
c7ffa4
 				error = -1;
c7ffa4
 				goto out;
c7ffa4
@@ -1147,5 +1204,21 @@
c7ffa4
 			desc_avail  = desc->len;
c7ffa4
 
c7ffa4
-			PRINT_PACKET(dev, (uintptr_t)desc_addr, desc->len, 0);
c7ffa4
+			PRINT_PACKET(dev, (uintptr_t)desc_addr,
c7ffa4
+					desc_chunck_len, 0);
c7ffa4
+		} else if (unlikely(desc_chunck_len == 0)) {
c7ffa4
+			desc_chunck_len = desc_avail;
c7ffa4
+			desc_gaddr += desc_offset;
c7ffa4
+			desc_addr = vhost_iova_to_vva(dev, vq,
c7ffa4
+					desc_gaddr,
c7ffa4
+					&desc_chunck_len,
c7ffa4
+					VHOST_ACCESS_RO);
c7ffa4
+			if (unlikely(!desc_addr)) {
c7ffa4
+				error = -1;
c7ffa4
+				goto out;
c7ffa4
+			}
c7ffa4
+			desc_offset = 0;
c7ffa4
+
c7ffa4
+			PRINT_PACKET(dev, (uintptr_t)desc_addr,
c7ffa4
+					desc_chunck_len, 0);
c7ffa4
 		}
c7ffa4
 
c7ffa4
-- 
c7ffa4
1.8.3.1
c7ffa4