Blame SOURCES/0009-examples-vhost-move-to-safe-GPA-translation-API.patch

a6040a
From cbf70816520746639e6db436f356ba0cd36e0bb3 Mon Sep 17 00:00:00 2001
a6040a
From: Maxime Coquelin <maxime.coquelin@redhat.com>
a6040a
Date: Mon, 23 Apr 2018 11:33:46 +0200
a6040a
Subject: [PATCH 09/11] examples/vhost: move to safe GPA translation API
a6040a
a6040a
This patch uses the new rte_vhost_va_from_guest_pa() API
a6040a
to ensure the application doesn't perform out-of-bound
a6040a
accesses either because of a malicious guest providing an
a6040a
incorrect descriptor length, or because the buffer is
a6040a
contiguous in guest physical address space but not in the
a6040a
host process virtual address space.
a6040a
a6040a
This issue has been assigned CVE-2018-1059.
a6040a
a6040a
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
a6040a
---
a6040a
 examples/vhost/virtio_net.c | 94 +++++++++++++++++++++++++++++++++++++++------
a6040a
 1 file changed, 83 insertions(+), 11 deletions(-)
a6040a
a6040a
diff --git a/examples/vhost/virtio_net.c b/examples/vhost/virtio_net.c
a6040a
index 1ab57f5..31c3dd0 100644
a6040a
--- a/examples/vhost/virtio_net.c
a6040a
+++ b/examples/vhost/virtio_net.c
a6040a
@@ -86,8 +86,9 @@
a6040a
 {
a6040a
 	uint32_t desc_avail, desc_offset;
a6040a
+	uint64_t desc_chunck_len;
a6040a
 	uint32_t mbuf_avail, mbuf_offset;
a6040a
 	uint32_t cpy_len;
a6040a
 	struct vring_desc *desc;
a6040a
-	uint64_t desc_addr;
a6040a
+	uint64_t desc_addr, desc_gaddr;
a6040a
 	struct virtio_net_hdr virtio_hdr = {0, 0, 0, 0, 0, 0};
a6040a
 	/* A counter to avoid desc dead loop chain */
a6040a
@@ -95,5 +96,8 @@
a6040a
 
a6040a
 	desc = &vr->desc[desc_idx];
a6040a
-	desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
a6040a
+	desc_chunck_len = desc->len;
a6040a
+	desc_gaddr = desc->addr;
a6040a
+	desc_addr = rte_vhost_va_from_guest_pa(
a6040a
+			dev->mem, desc_gaddr, &desc_chunck_len);
a6040a
 	/*
a6040a
 	 * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid
a6040a
@@ -107,7 +111,40 @@
a6040a
 
a6040a
 	/* write virtio-net header */
a6040a
-	*(struct virtio_net_hdr *)(uintptr_t)desc_addr = virtio_hdr;
a6040a
+	if (likely(desc_chunck_len >= dev->hdr_len)) {
a6040a
+		*(struct virtio_net_hdr *)(uintptr_t)desc_addr = virtio_hdr;
a6040a
+		desc_offset = dev->hdr_len;
a6040a
+	} else {
a6040a
+		uint64_t len;
a6040a
+		uint64_t remain = dev->hdr_len;
a6040a
+		uint64_t src = (uint64_t)(uintptr_t)&virtio_hdr, dst;
a6040a
+		uint64_t guest_addr = desc_gaddr;
a6040a
+
a6040a
+		while (remain) {
a6040a
+			len = remain;
a6040a
+			dst = rte_vhost_va_from_guest_pa(dev->mem,
a6040a
+					guest_addr, &len;;
a6040a
+			if (unlikely(!dst || !len))
a6040a
+				return -1;
a6040a
+
a6040a
+			rte_memcpy((void *)(uintptr_t)dst,
a6040a
+					(void *)(uintptr_t)src,
a6040a
+					len);
a6040a
+
a6040a
+			remain -= len;
a6040a
+			guest_addr += len;
a6040a
+			dst += len;
a6040a
+		}
a6040a
+
a6040a
+		desc_chunck_len = desc->len - dev->hdr_len;
a6040a
+		desc_gaddr += dev->hdr_len;
a6040a
+		desc_addr = rte_vhost_va_from_guest_pa(
a6040a
+				dev->mem, desc_gaddr,
a6040a
+				&desc_chunck_len);
a6040a
+		if (unlikely(!desc_addr))
a6040a
+			return -1;
a6040a
+
a6040a
+		desc_offset = 0;
a6040a
+	}
a6040a
 
a6040a
-	desc_offset = dev->hdr_len;
a6040a
 	desc_avail  = desc->len - dev->hdr_len;
a6040a
 
a6040a
@@ -134,5 +171,8 @@
a6040a
 
a6040a
 			desc = &vr->desc[desc->next];
a6040a
-			desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
a6040a
+			desc_chunck_len = desc->len;
a6040a
+			desc_gaddr = desc->addr;
a6040a
+			desc_addr = rte_vhost_va_from_guest_pa(
a6040a
+					dev->mem, desc_gaddr, &desc_chunck_len);
a6040a
 			if (unlikely(!desc_addr))
a6040a
 				return -1;
a6040a
@@ -140,7 +180,17 @@
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 = rte_vhost_va_from_guest_pa(dev->mem,
a6040a
+					desc_gaddr,
a6040a
+					&desc_chunck_len);
a6040a
+			if (unlikely(!desc_addr))
a6040a
+				return -1;
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
 		rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
a6040a
 			rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
a6040a
@@ -151,4 +201,5 @@
a6040a
 		desc_avail  -= cpy_len;
a6040a
 		desc_offset += cpy_len;
a6040a
+		desc_chunck_len -= cpy_len;
a6040a
 	}
a6040a
 
a6040a
@@ -224,6 +275,7 @@
a6040a
 {
a6040a
 	struct vring_desc *desc;
a6040a
-	uint64_t desc_addr;
a6040a
+	uint64_t desc_addr, desc_gaddr;
a6040a
 	uint32_t desc_avail, desc_offset;
a6040a
+	uint64_t desc_chunck_len;
a6040a
 	uint32_t mbuf_avail, mbuf_offset;
a6040a
 	uint32_t cpy_len;
a6040a
@@ -237,5 +289,8 @@
a6040a
 		return -1;
a6040a
 
a6040a
-	desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
a6040a
+	desc_chunck_len = desc->len;
a6040a
+	desc_gaddr = desc->addr;
a6040a
+	desc_addr = rte_vhost_va_from_guest_pa(
a6040a
+			dev->mem, desc_gaddr, &desc_chunck_len);
a6040a
 	if (unlikely(!desc_addr))
a6040a
 		return -1;
a6040a
@@ -251,5 +306,8 @@
a6040a
 	 */
a6040a
 	desc = &vr->desc[desc->next];
a6040a
-	desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
a6040a
+	desc_chunck_len = desc->len;
a6040a
+	desc_gaddr = desc->addr;
a6040a
+	desc_addr = rte_vhost_va_from_guest_pa(
a6040a
+			dev->mem, desc_gaddr, &desc_chunck_len);
a6040a
 	if (unlikely(!desc_addr))
a6040a
 		return -1;
a6040a
@@ -263,5 +321,5 @@
a6040a
 	mbuf_avail  = m->buf_len - RTE_PKTMBUF_HEADROOM;
a6040a
 	while (1) {
a6040a
-		cpy_len = RTE_MIN(desc_avail, mbuf_avail);
a6040a
+		cpy_len = RTE_MIN(desc_chunck_len, mbuf_avail);
a6040a
 		rte_memcpy(rte_pktmbuf_mtod_offset(cur, void *,
a6040a
 						   mbuf_offset),
a6040a
@@ -273,4 +331,5 @@
a6040a
 		desc_avail  -= cpy_len;
a6040a
 		desc_offset += cpy_len;
a6040a
+		desc_chunck_len -= cpy_len;
a6040a
 
a6040a
 		/* This desc reaches to its end, get the next one */
a6040a
@@ -284,5 +343,8 @@
a6040a
 			desc = &vr->desc[desc->next];
a6040a
 
a6040a
-			desc_addr = rte_vhost_gpa_to_vva(dev->mem, desc->addr);
a6040a
+			desc_chunck_len = desc->len;
a6040a
+			desc_gaddr = desc->addr;
a6040a
+			desc_addr = rte_vhost_va_from_guest_pa(
a6040a
+					dev->mem, desc_gaddr, &desc_chunck_len);
a6040a
 			if (unlikely(!desc_addr))
a6040a
 				return -1;
a6040a
@@ -291,4 +353,14 @@
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 = rte_vhost_va_from_guest_pa(dev->mem,
a6040a
+					desc_gaddr,
a6040a
+					&desc_chunck_len);
a6040a
+			if (unlikely(!desc_addr))
a6040a
+				return -1;
a6040a
+
a6040a
+			desc_offset = 0;
a6040a
 		}
a6040a
 
a6040a
-- 
a6040a
1.8.3.1
a6040a