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

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