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

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