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

a6040a
From 93f522ef2aa3e61bd44d374c5fb92ede0ac1b58f Mon Sep 17 00:00:00 2001
a6040a
From: Maxime Coquelin <maxime.coquelin@redhat.com>
a6040a
Date: Mon, 23 Apr 2018 11:33:45 +0200
a6040a
Subject: [PATCH 08/11] vhost: handle virtually non-contiguous buffers in
a6040a
 Rx-mrg
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 are 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 | 115 ++++++++++++++++++++++++++++++++----------
a6040a
 1 file changed, 87 insertions(+), 28 deletions(-)
a6040a
a6040a
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
a6040a
index 5bd4e58..a013c07 100644
a6040a
--- a/lib/librte_vhost/virtio_net.c
a6040a
+++ b/lib/librte_vhost/virtio_net.c
a6040a
@@ -669,12 +669,13 @@
a6040a
 {
a6040a
 	uint32_t vec_idx = 0;
a6040a
-	uint64_t desc_addr;
a6040a
+	uint64_t desc_addr, desc_gaddr;
a6040a
 	uint32_t mbuf_offset, mbuf_avail;
a6040a
 	uint32_t desc_offset, desc_avail;
a6040a
 	uint32_t cpy_len;
a6040a
-	uint64_t dlen;
a6040a
+	uint64_t desc_chunck_len;
a6040a
 	uint64_t hdr_addr, hdr_phys_addr;
a6040a
 	struct rte_mbuf *hdr_mbuf;
a6040a
 	struct batch_copy_elem *batch_copy = vq->batch_copy_elems;
a6040a
+	struct virtio_net_hdr_mrg_rxbuf tmp_hdr, *hdr = NULL;
a6040a
 	uint16_t copy_nb = vq->batch_copy_nb_elems;
a6040a
 	int error = 0;
a6040a
@@ -685,10 +686,11 @@
a6040a
 	}
a6040a
 
a6040a
-	dlen = buf_vec[vec_idx].buf_len;
a6040a
-	desc_addr = vhost_iova_to_vva(dev, vq, buf_vec[vec_idx].buf_addr,
a6040a
-						&dlen, VHOST_ACCESS_RW);
a6040a
-	if (dlen != buf_vec[vec_idx].buf_len ||
a6040a
-			buf_vec[vec_idx].buf_len < dev->vhost_hlen ||
a6040a
-			!desc_addr) {
a6040a
+	desc_chunck_len = buf_vec[vec_idx].buf_len;
a6040a
+	desc_gaddr = buf_vec[vec_idx].buf_addr;
a6040a
+	desc_addr = vhost_iova_to_vva(dev, vq,
a6040a
+					desc_gaddr,
a6040a
+					&desc_chunck_len,
a6040a
+					VHOST_ACCESS_RW);
a6040a
+	if (buf_vec[vec_idx].buf_len < dev->vhost_hlen || !desc_addr) {
a6040a
 		error = -1;
a6040a
 		goto out;
a6040a
@@ -697,5 +699,9 @@
a6040a
 	hdr_mbuf = m;
a6040a
 	hdr_addr = desc_addr;
a6040a
-	hdr_phys_addr = buf_vec[vec_idx].buf_addr;
a6040a
+	if (unlikely(desc_chunck_len < dev->vhost_hlen))
a6040a
+		hdr = &tmp_hdr;
a6040a
+	else
a6040a
+		hdr = (struct virtio_net_hdr_mrg_rxbuf *)(uintptr_t)hdr_addr;
a6040a
+	hdr_phys_addr = desc_gaddr;
a6040a
 	rte_prefetch0((void *)(uintptr_t)hdr_addr);
a6040a
 
a6040a
@@ -704,5 +710,22 @@
a6040a
 
a6040a
 	desc_avail  = buf_vec[vec_idx].buf_len - dev->vhost_hlen;
a6040a
-	desc_offset = dev->vhost_hlen;
a6040a
+	if (unlikely(desc_chunck_len < dev->vhost_hlen)) {
a6040a
+		desc_chunck_len = desc_avail;
a6040a
+		desc_gaddr += dev->vhost_hlen;
a6040a
+		desc_addr = vhost_iova_to_vva(dev, vq,
a6040a
+				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
 
a6040a
 	mbuf_avail  = rte_pktmbuf_data_len(m);
a6040a
@@ -712,12 +735,12 @@
a6040a
 		if (desc_avail == 0) {
a6040a
 			vec_idx++;
a6040a
-			dlen = buf_vec[vec_idx].buf_len;
a6040a
+			desc_chunck_len = buf_vec[vec_idx].buf_len;
a6040a
+			desc_gaddr = buf_vec[vec_idx].buf_addr;
a6040a
 			desc_addr =
a6040a
 				vhost_iova_to_vva(dev, vq,
a6040a
-					buf_vec[vec_idx].buf_addr,
a6040a
-					&dlen,
a6040a
+					desc_gaddr,
a6040a
+					&desc_chunck_len,
a6040a
 					VHOST_ACCESS_RW);
a6040a
-			if (unlikely(!desc_addr ||
a6040a
-					dlen != buf_vec[vec_idx].buf_len)) {
a6040a
+			if (unlikely(!desc_addr)) {
a6040a
 				error = -1;
a6040a
 				goto out;
a6040a
@@ -728,4 +751,15 @@
a6040a
 			desc_offset = 0;
a6040a
 			desc_avail  = buf_vec[vec_idx].buf_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, vq,
a6040a
+					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
@@ -739,19 +773,46 @@
a6040a
 
a6040a
 		if (hdr_addr) {
a6040a
-			struct virtio_net_hdr_mrg_rxbuf *hdr;
a6040a
-
a6040a
-			hdr = (struct virtio_net_hdr_mrg_rxbuf *)(uintptr_t)
a6040a
-				hdr_addr;
a6040a
 			virtio_enqueue_offload(hdr_mbuf, &hdr->hdr);
a6040a
 			ASSIGN_UNLESS_EQUAL(hdr->num_buffers, num_buffers);
a6040a
 
a6040a
-			vhost_log_write(dev, hdr_phys_addr, dev->vhost_hlen);
a6040a
-			PRINT_PACKET(dev, (uintptr_t)hdr_addr,
a6040a
-				     dev->vhost_hlen, 0);
a6040a
+			if (unlikely(hdr == &tmp_hdr)) {
a6040a
+				uint64_t len;
a6040a
+				uint64_t remain = dev->vhost_hlen;
a6040a
+				uint64_t src = (uint64_t)(uintptr_t)hdr, dst;
a6040a
+				uint64_t guest_addr = hdr_phys_addr;
a6040a
+
a6040a
+				while (remain) {
a6040a
+					len = remain;
a6040a
+					dst = vhost_iova_to_vva(dev, vq,
a6040a
+							guest_addr, &len,
a6040a
+							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,
a6040a
+							len);
a6040a
+
a6040a
+					PRINT_PACKET(dev, (uintptr_t)dst,
a6040a
+							len, 0);
a6040a
+					vhost_log_write(dev, guest_addr, len);
a6040a
+
a6040a
+					remain -= len;
a6040a
+					guest_addr += len;
a6040a
+					dst += len;
a6040a
+				}
a6040a
+			} else {
a6040a
+				PRINT_PACKET(dev, (uintptr_t)hdr_addr,
a6040a
+						dev->vhost_hlen, 0);
a6040a
+				vhost_log_write(dev, hdr_phys_addr,
a6040a
+						dev->vhost_hlen);
a6040a
+			}
a6040a
 
a6040a
 			hdr_addr = 0;
a6040a
 		}
a6040a
 
a6040a
-		cpy_len = RTE_MIN(desc_avail, mbuf_avail);
a6040a
+		cpy_len = RTE_MIN(desc_chunck_len, mbuf_avail);
a6040a
 
a6040a
 		if (likely(cpy_len > MAX_BATCH_LEN || copy_nb >= vq->size)) {
a6040a
@@ -760,7 +821,5 @@
a6040a
 				rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
a6040a
 				cpy_len);
a6040a
-			vhost_log_write(dev,
a6040a
-				buf_vec[vec_idx].buf_addr + desc_offset,
a6040a
-				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
@@ -770,6 +829,5 @@
a6040a
 			batch_copy[copy_nb].src =
a6040a
 				rte_pktmbuf_mtod_offset(m, void *, mbuf_offset);
a6040a
-			batch_copy[copy_nb].log_addr =
a6040a
-				buf_vec[vec_idx].buf_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
@@ -780,4 +838,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