Blame SOURCES/0007-vhost-handle-virtually-non-contiguous-buffers-in-Rx.patch

c7ffa4
From 79587b5fcf7d09fbba9f05bbdc1edcc26060f80a Mon Sep 17 00:00:00 2001
c7ffa4
From: Maxime Coquelin <maxime.coquelin@redhat.com>
c7ffa4
Date: Mon, 23 Apr 2018 11:33:44 +0200
c7ffa4
Subject: [PATCH 07/11] vhost: handle virtually non-contiguous buffers in Rx
c7ffa4
c7ffa4
This patch enables the handling of buffers non-contiguous in
c7ffa4
process virtual address space in the enqueue path when mergeable
c7ffa4
buffers aren't used.
c7ffa4
c7ffa4
When virtio-net header doesn't fit in a single chunck, it is
c7ffa4
computed in a local variable and copied to the buffer chuncks
c7ffa4
afterwards.
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 | 95 +++++++++++++++++++++++++++++++++++--------
c7ffa4
 1 file changed, 77 insertions(+), 18 deletions(-)
c7ffa4
c7ffa4
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
c7ffa4
index 47717a1..5bd4e58 100644
c7ffa4
--- a/lib/librte_vhost/virtio_net.c
c7ffa4
+++ b/lib/librte_vhost/virtio_net.c
c7ffa4
@@ -246,7 +246,7 @@
c7ffa4
 	uint32_t mbuf_avail, mbuf_offset;
c7ffa4
 	uint32_t cpy_len;
c7ffa4
-	uint64_t dlen;
c7ffa4
+	uint64_t desc_chunck_len;
c7ffa4
 	struct vring_desc *desc;
c7ffa4
-	uint64_t desc_addr;
c7ffa4
+	uint64_t desc_addr, desc_gaddr;
c7ffa4
 	/* A counter to avoid desc dead loop chain */
c7ffa4
 	uint16_t nr_desc = 1;
c7ffa4
@@ -256,7 +256,8 @@
c7ffa4
 
c7ffa4
 	desc = &descs[desc_idx];
c7ffa4
-	dlen = desc->len;
c7ffa4
-	desc_addr = vhost_iova_to_vva(dev, vq, desc->addr,
c7ffa4
-					&dlen, VHOST_ACCESS_RW);
c7ffa4
+	desc_chunck_len = desc->len;
c7ffa4
+	desc_gaddr = desc->addr;
c7ffa4
+	desc_addr = vhost_iova_to_vva(dev, vq, desc_gaddr,
c7ffa4
+					&desc_chunck_len, VHOST_ACCESS_RW);
c7ffa4
 	/*
c7ffa4
 	 * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid
c7ffa4
@@ -264,6 +265,5 @@
c7ffa4
 	 * otherwise stores offset on the stack instead of in a register.
c7ffa4
 	 */
c7ffa4
-	if (unlikely(dlen != desc->len || desc->len < dev->vhost_hlen) ||
c7ffa4
-			!desc_addr) {
c7ffa4
+	if (unlikely(desc->len < dev->vhost_hlen) || !desc_addr) {
c7ffa4
 		error = -1;
c7ffa4
 		goto out;
c7ffa4
@@ -272,10 +272,56 @@
c7ffa4
 	rte_prefetch0((void *)(uintptr_t)desc_addr);
c7ffa4
 
c7ffa4
-	virtio_enqueue_offload(m, (struct virtio_net_hdr *)(uintptr_t)desc_addr);
c7ffa4
-	vhost_log_write(dev, desc->addr, dev->vhost_hlen);
c7ffa4
-	PRINT_PACKET(dev, (uintptr_t)desc_addr, dev->vhost_hlen, 0);
c7ffa4
+	if (likely(desc_chunck_len >= dev->vhost_hlen)) {
c7ffa4
+		virtio_enqueue_offload(m,
c7ffa4
+				(struct virtio_net_hdr *)(uintptr_t)desc_addr);
c7ffa4
+		PRINT_PACKET(dev, (uintptr_t)desc_addr, dev->vhost_hlen, 0);
c7ffa4
+		vhost_log_write(dev, desc_gaddr, dev->vhost_hlen);
c7ffa4
+	} else {
c7ffa4
+		struct virtio_net_hdr vnet_hdr;
c7ffa4
+		uint64_t remain = dev->vhost_hlen;
c7ffa4
+		uint64_t len;
c7ffa4
+		uint64_t src = (uint64_t)(uintptr_t)&vnet_hdr, dst;
c7ffa4
+		uint64_t guest_addr = desc_gaddr;
c7ffa4
+
c7ffa4
+		virtio_enqueue_offload(m, &vnet_hdr);
c7ffa4
+
c7ffa4
+		while (remain) {
c7ffa4
+			len = remain;
c7ffa4
+			dst = vhost_iova_to_vva(dev, vq, guest_addr,
c7ffa4
+					&len, VHOST_ACCESS_RW);
c7ffa4
+			if (unlikely(!dst || !len)) {
c7ffa4
+				error = -1;
c7ffa4
+				goto out;
c7ffa4
+			}
c7ffa4
+
c7ffa4
+			rte_memcpy((void *)(uintptr_t)dst,
c7ffa4
+					(void *)(uintptr_t)src, len);
c7ffa4
+
c7ffa4
+			PRINT_PACKET(dev, (uintptr_t)dst, len, 0);
c7ffa4
+			vhost_log_write(dev, guest_addr, len);
c7ffa4
+			remain -= len;
c7ffa4
+			guest_addr += len;
c7ffa4
+			dst += len;
c7ffa4
+		}
c7ffa4
+	}
c7ffa4
 
c7ffa4
-	desc_offset = dev->vhost_hlen;
c7ffa4
 	desc_avail  = desc->len - dev->vhost_hlen;
c7ffa4
+	if (unlikely(desc_chunck_len < dev->vhost_hlen)) {
c7ffa4
+		desc_chunck_len = desc_avail;
c7ffa4
+		desc_gaddr = desc->addr + dev->vhost_hlen;
c7ffa4
+		desc_addr = vhost_iova_to_vva(dev,
c7ffa4
+				vq, desc_gaddr,
c7ffa4
+				&desc_chunck_len,
c7ffa4
+				VHOST_ACCESS_RW);
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
 	mbuf_avail  = rte_pktmbuf_data_len(m);
c7ffa4
@@ -303,9 +349,10 @@
c7ffa4
 
c7ffa4
 			desc = &descs[desc->next];
c7ffa4
-			dlen = desc->len;
c7ffa4
-			desc_addr = vhost_iova_to_vva(dev, vq, desc->addr,
c7ffa4
-							&dlen,
c7ffa4
+			desc_chunck_len = desc->len;
c7ffa4
+			desc_gaddr = desc->addr;
c7ffa4
+			desc_addr = vhost_iova_to_vva(dev, vq, desc_gaddr,
c7ffa4
+							&desc_chunck_len,
c7ffa4
 							VHOST_ACCESS_RW);
c7ffa4
-			if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
+			if (unlikely(!desc_addr)) {
c7ffa4
 				error = -1;
c7ffa4
 				goto out;
c7ffa4
@@ -314,7 +361,18 @@
c7ffa4
 			desc_offset = 0;
c7ffa4
 			desc_avail  = desc->len;
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,
c7ffa4
+					vq, desc_gaddr,
c7ffa4
+					&desc_chunck_len, VHOST_ACCESS_RW);
c7ffa4
+			if (unlikely(!desc_addr)) {
c7ffa4
+				error = -1;
c7ffa4
+				goto out;
c7ffa4
+			}
c7ffa4
+			desc_offset = 0;
c7ffa4
 		}
c7ffa4
 
c7ffa4
-		cpy_len = RTE_MIN(desc_avail, mbuf_avail);
c7ffa4
+		cpy_len = RTE_MIN(desc_chunck_len, mbuf_avail);
c7ffa4
 		if (likely(cpy_len > MAX_BATCH_LEN || copy_nb >= vq->size)) {
c7ffa4
 			rte_memcpy((void *)((uintptr_t)(desc_addr +
c7ffa4
@@ -322,5 +380,5 @@
c7ffa4
 				rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
c7ffa4
 				cpy_len);
c7ffa4
-			vhost_log_write(dev, desc->addr + desc_offset, cpy_len);
c7ffa4
+			vhost_log_write(dev, desc_gaddr + desc_offset, cpy_len);
c7ffa4
 			PRINT_PACKET(dev, (uintptr_t)(desc_addr + desc_offset),
c7ffa4
 				     cpy_len, 0);
c7ffa4
@@ -330,5 +388,5 @@
c7ffa4
 			batch_copy[copy_nb].src =
c7ffa4
 				rte_pktmbuf_mtod_offset(m, void *, mbuf_offset);
c7ffa4
-			batch_copy[copy_nb].log_addr = desc->addr + desc_offset;
c7ffa4
+			batch_copy[copy_nb].log_addr = desc_gaddr + desc_offset;
c7ffa4
 			batch_copy[copy_nb].len = cpy_len;
c7ffa4
 			copy_nb++;
c7ffa4
@@ -339,4 +397,5 @@
c7ffa4
 		desc_avail  -= cpy_len;
c7ffa4
 		desc_offset += cpy_len;
c7ffa4
+		desc_chunck_len -= cpy_len;
c7ffa4
 	}
c7ffa4
 
c7ffa4
-- 
c7ffa4
1.8.3.1
c7ffa4