Blame SOURCES/0002-vhost-check-all-range-is-mapped-when-translating-GPA.patch

c7ffa4
From 575ed8c576daebf38494aa3a10ef95ab806ea97a Mon Sep 17 00:00:00 2001
c7ffa4
From: Maxime Coquelin <maxime.coquelin@redhat.com>
c7ffa4
Date: Mon, 23 Apr 2018 11:33:39 +0200
c7ffa4
Subject: [PATCH 02/11] vhost: check all range is mapped when translating GPAs
c7ffa4
c7ffa4
There is currently no check done on the length when translating
c7ffa4
guest addresses into host virtual addresses. Also, there is no
c7ffa4
guanrantee that the guest addresses range is contiguous in
c7ffa4
the host virtual address space.
c7ffa4
c7ffa4
This patch prepares vhost_iova_to_vva() and its callers to
c7ffa4
return and check the mapped size. If the mapped size is smaller
c7ffa4
than the requested size, the caller handle it as an error.
c7ffa4
c7ffa4
This issue has been assigned CVE-2018-1059.
c7ffa4
c7ffa4
Reported-by: Yongji Xie <xieyongji@baidu.com>
c7ffa4
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
c7ffa4
---
c7ffa4
 lib/librte_vhost/vhost.c      | 39 +++++++++++++++-----------
c7ffa4
 lib/librte_vhost/vhost.h      |  6 ++--
c7ffa4
 lib/librte_vhost/virtio_net.c | 64 +++++++++++++++++++++++++++----------------
c7ffa4
 3 files changed, 67 insertions(+), 42 deletions(-)
c7ffa4
c7ffa4
diff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c
c7ffa4
index 51ea720..a8ed40b 100644
c7ffa4
--- a/lib/librte_vhost/vhost.c
c7ffa4
+++ b/lib/librte_vhost/vhost.c
c7ffa4
@@ -59,15 +59,15 @@
c7ffa4
 uint64_t
c7ffa4
 __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
c7ffa4
-		    uint64_t iova, uint64_t size, uint8_t perm)
c7ffa4
+		    uint64_t iova, uint64_t *size, uint8_t perm)
c7ffa4
 {
c7ffa4
 	uint64_t vva, tmp_size;
c7ffa4
 
c7ffa4
-	if (unlikely(!size))
c7ffa4
+	if (unlikely(!*size))
c7ffa4
 		return 0;
c7ffa4
 
c7ffa4
-	tmp_size = size;
c7ffa4
+	tmp_size = *size;
c7ffa4
 
c7ffa4
 	vva = vhost_user_iotlb_cache_find(vq, iova, &tmp_size, perm);
c7ffa4
-	if (tmp_size == size)
c7ffa4
+	if (tmp_size == *size)
c7ffa4
 		return vva;
c7ffa4
 
c7ffa4
@@ -159,30 +159,37 @@ struct virtio_net *
c7ffa4
 vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
c7ffa4
 {
c7ffa4
-	uint64_t size;
c7ffa4
+	uint64_t req_size, size;
c7ffa4
 
c7ffa4
 	if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
c7ffa4
 		goto out;
c7ffa4
 
c7ffa4
-	size = sizeof(struct vring_desc) * vq->size;
c7ffa4
+	req_size = sizeof(struct vring_desc) * vq->size;
c7ffa4
+	size = req_size;
c7ffa4
 	vq->desc = (struct vring_desc *)(uintptr_t)vhost_iova_to_vva(dev, vq,
c7ffa4
 						vq->ring_addrs.desc_user_addr,
c7ffa4
-						size, VHOST_ACCESS_RW);
c7ffa4
-	if (!vq->desc)
c7ffa4
+						&size, VHOST_ACCESS_RW);
c7ffa4
+	if (!vq->desc || size != req_size)
c7ffa4
 		return -1;
c7ffa4
 
c7ffa4
-	size = sizeof(struct vring_avail);
c7ffa4
-	size += sizeof(uint16_t) * vq->size;
c7ffa4
+	req_size = sizeof(struct vring_avail);
c7ffa4
+	req_size += sizeof(uint16_t) * vq->size;
c7ffa4
+	if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))
c7ffa4
+		req_size += sizeof(uint16_t);
c7ffa4
+	size = req_size;
c7ffa4
 	vq->avail = (struct vring_avail *)(uintptr_t)vhost_iova_to_vva(dev, vq,
c7ffa4
 						vq->ring_addrs.avail_user_addr,
c7ffa4
-						size, VHOST_ACCESS_RW);
c7ffa4
-	if (!vq->avail)
c7ffa4
+						&size, VHOST_ACCESS_RW);
c7ffa4
+	if (!vq->avail || size != req_size)
c7ffa4
 		return -1;
c7ffa4
 
c7ffa4
-	size = sizeof(struct vring_used);
c7ffa4
-	size += sizeof(struct vring_used_elem) * vq->size;
c7ffa4
+	req_size = sizeof(struct vring_used);
c7ffa4
+	req_size += sizeof(struct vring_used_elem) * vq->size;
c7ffa4
+	if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))
c7ffa4
+		req_size += sizeof(uint16_t);
c7ffa4
+	size = req_size;
c7ffa4
 	vq->used = (struct vring_used *)(uintptr_t)vhost_iova_to_vva(dev, vq,
c7ffa4
 						vq->ring_addrs.used_user_addr,
c7ffa4
-						size, VHOST_ACCESS_RW);
c7ffa4
-	if (!vq->used)
c7ffa4
+						&size, VHOST_ACCESS_RW);
c7ffa4
+	if (!vq->used || size != req_size)
c7ffa4
 		return -1;
c7ffa4
 
c7ffa4
diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h
c7ffa4
index c8f2a81..de300c1 100644
c7ffa4
--- a/lib/librte_vhost/vhost.h
c7ffa4
+++ b/lib/librte_vhost/vhost.h
c7ffa4
@@ -382,5 +382,5 @@ struct virtio_net {
c7ffa4
 
c7ffa4
 uint64_t __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
c7ffa4
-			uint64_t iova, uint64_t size, uint8_t perm);
c7ffa4
+			uint64_t iova, uint64_t *len, uint8_t perm);
c7ffa4
 int vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq);
c7ffa4
 void vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq);
c7ffa4
@@ -388,10 +388,10 @@ uint64_t __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
c7ffa4
 static __rte_always_inline uint64_t
c7ffa4
 vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
c7ffa4
-			uint64_t iova, uint64_t size, uint8_t perm)
c7ffa4
+			uint64_t iova, uint64_t *len, uint8_t perm)
c7ffa4
 {
c7ffa4
 	if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
c7ffa4
 		return rte_vhost_gpa_to_vva(dev->mem, iova);
c7ffa4
 
c7ffa4
-	return __vhost_iova_to_vva(dev, vq, iova, size, perm);
c7ffa4
+	return __vhost_iova_to_vva(dev, vq, iova, len, perm);
c7ffa4
 }
c7ffa4
 
c7ffa4
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
c7ffa4
index cb1d0cf..79bac59 100644
c7ffa4
--- a/lib/librte_vhost/virtio_net.c
c7ffa4
+++ b/lib/librte_vhost/virtio_net.c
c7ffa4
@@ -205,4 +205,5 @@
c7ffa4
 	uint32_t mbuf_avail, mbuf_offset;
c7ffa4
 	uint32_t cpy_len;
c7ffa4
+	uint64_t dlen;
c7ffa4
 	struct vring_desc *desc;
c7ffa4
 	uint64_t desc_addr;
c7ffa4
@@ -214,6 +215,7 @@
c7ffa4
 
c7ffa4
 	desc = &descs[desc_idx];
c7ffa4
+	dlen = desc->len;
c7ffa4
 	desc_addr = vhost_iova_to_vva(dev, vq, desc->addr,
c7ffa4
-					desc->len, VHOST_ACCESS_RW);
c7ffa4
+					&dlen, VHOST_ACCESS_RW);
c7ffa4
 	/*
c7ffa4
 	 * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid
c7ffa4
@@ -221,5 +223,6 @@
c7ffa4
 	 * otherwise stores offset on the stack instead of in a register.
c7ffa4
 	 */
c7ffa4
-	if (unlikely(desc->len < dev->vhost_hlen) || !desc_addr) {
c7ffa4
+	if (unlikely(dlen != desc->len || desc->len < dev->vhost_hlen) ||
c7ffa4
+			!desc_addr) {
c7ffa4
 		error = -1;
c7ffa4
 		goto out;
c7ffa4
@@ -259,8 +262,9 @@
c7ffa4
 
c7ffa4
 			desc = &descs[desc->next];
c7ffa4
+			dlen = desc->len;
c7ffa4
 			desc_addr = vhost_iova_to_vva(dev, vq, desc->addr,
c7ffa4
-							desc->len,
c7ffa4
+							&dlen,
c7ffa4
 							VHOST_ACCESS_RW);
c7ffa4
-			if (unlikely(!desc_addr)) {
c7ffa4
+			if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
 				error = -1;
c7ffa4
 				goto out;
c7ffa4
@@ -376,10 +380,11 @@
c7ffa4
 
c7ffa4
 		if (vq->desc[desc_idx].flags & VRING_DESC_F_INDIRECT) {
c7ffa4
+			uint64_t dlen = vq->desc[desc_idx].len;
c7ffa4
 			descs = (struct vring_desc *)(uintptr_t)
c7ffa4
 				vhost_iova_to_vva(dev,
c7ffa4
 						vq, vq->desc[desc_idx].addr,
c7ffa4
-						vq->desc[desc_idx].len,
c7ffa4
-						VHOST_ACCESS_RO);
c7ffa4
-			if (unlikely(!descs)) {
c7ffa4
+						&dlen, VHOST_ACCESS_RO);
c7ffa4
+			if (unlikely(!descs ||
c7ffa4
+					dlen != vq->desc[desc_idx].len)) {
c7ffa4
 				count = i;
c7ffa4
 				break;
c7ffa4
@@ -439,4 +444,5 @@
c7ffa4
 	uint32_t vec_id = *vec_idx;
c7ffa4
 	uint32_t len    = 0;
c7ffa4
+	uint64_t dlen;
c7ffa4
 	struct vring_desc *descs = vq->desc;
c7ffa4
 
c7ffa4
@@ -444,9 +450,10 @@
c7ffa4
 
c7ffa4
 	if (vq->desc[idx].flags & VRING_DESC_F_INDIRECT) {
c7ffa4
+		dlen = vq->desc[idx].len;
c7ffa4
 		descs = (struct vring_desc *)(uintptr_t)
c7ffa4
 			vhost_iova_to_vva(dev, vq, vq->desc[idx].addr,
c7ffa4
-						vq->desc[idx].len,
c7ffa4
+						&dlen,
c7ffa4
 						VHOST_ACCESS_RO);
c7ffa4
-		if (unlikely(!descs))
c7ffa4
+		if (unlikely(!descs || dlen != vq->desc[idx].len))
c7ffa4
 			return -1;
c7ffa4
 
c7ffa4
@@ -531,4 +538,5 @@
c7ffa4
 	uint32_t desc_offset, desc_avail;
c7ffa4
 	uint32_t cpy_len;
c7ffa4
+	uint64_t dlen;
c7ffa4
 	uint64_t hdr_addr, hdr_phys_addr;
c7ffa4
 	struct rte_mbuf *hdr_mbuf;
c7ffa4
@@ -542,8 +550,10 @@
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
-						buf_vec[vec_idx].buf_len,
c7ffa4
-						VHOST_ACCESS_RW);
c7ffa4
-	if (buf_vec[vec_idx].buf_len < dev->vhost_hlen || !desc_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
 		error = -1;
c7ffa4
 		goto out;
c7ffa4
@@ -567,10 +577,12 @@
c7ffa4
 		if (desc_avail == 0) {
c7ffa4
 			vec_idx++;
c7ffa4
+			dlen = buf_vec[vec_idx].buf_len;
c7ffa4
 			desc_addr =
c7ffa4
 				vhost_iova_to_vva(dev, vq,
c7ffa4
 					buf_vec[vec_idx].buf_addr,
c7ffa4
-					buf_vec[vec_idx].buf_len,
c7ffa4
+					&dlen,
c7ffa4
 					VHOST_ACCESS_RW);
c7ffa4
-			if (unlikely(!desc_addr)) {
c7ffa4
+			if (unlikely(!desc_addr ||
c7ffa4
+					dlen != buf_vec[vec_idx].buf_len)) {
c7ffa4
 				error = -1;
c7ffa4
 				goto out;
c7ffa4
@@ -912,4 +924,5 @@
c7ffa4
 	uint32_t mbuf_avail, mbuf_offset;
c7ffa4
 	uint32_t cpy_len;
c7ffa4
+	uint64_t dlen;
c7ffa4
 	struct rte_mbuf *cur = m, *prev = m;
c7ffa4
 	struct virtio_net_hdr *hdr = NULL;
c7ffa4
@@ -927,9 +940,10 @@
c7ffa4
 	}
c7ffa4
 
c7ffa4
+	dlen = desc->len;
c7ffa4
 	desc_addr = vhost_iova_to_vva(dev,
c7ffa4
 					vq, desc->addr,
c7ffa4
-					desc->len,
c7ffa4
+					&dlen,
c7ffa4
 					VHOST_ACCESS_RO);
c7ffa4
-	if (unlikely(!desc_addr)) {
c7ffa4
+	if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
 		error = -1;
c7ffa4
 		goto out;
c7ffa4
@@ -954,9 +968,10 @@
c7ffa4
 		}
c7ffa4
 
c7ffa4
+		dlen = desc->len;
c7ffa4
 		desc_addr = vhost_iova_to_vva(dev,
c7ffa4
 							vq, desc->addr,
c7ffa4
-							desc->len,
c7ffa4
+							&dlen,
c7ffa4
 							VHOST_ACCESS_RO);
c7ffa4
-		if (unlikely(!desc_addr)) {
c7ffa4
+		if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
 			error = -1;
c7ffa4
 			goto out;
c7ffa4
@@ -1042,9 +1057,9 @@
c7ffa4
 			}
c7ffa4
 
c7ffa4
+			dlen = desc->len;
c7ffa4
 			desc_addr = vhost_iova_to_vva(dev,
c7ffa4
 							vq, desc->addr,
c7ffa4
-							desc->len,
c7ffa4
-							VHOST_ACCESS_RO);
c7ffa4
-			if (unlikely(!desc_addr)) {
c7ffa4
+							&dlen, VHOST_ACCESS_RO);
c7ffa4
+			if (unlikely(!desc_addr || dlen != desc->len)) {
c7ffa4
 				error = -1;
c7ffa4
 				goto out;
c7ffa4
@@ -1320,4 +1335,5 @@
c7ffa4
 		struct vring_desc *desc;
c7ffa4
 		uint16_t sz, idx;
c7ffa4
+		uint64_t dlen;
c7ffa4
 		int err;
c7ffa4
 
c7ffa4
@@ -1326,10 +1342,12 @@
c7ffa4
 
c7ffa4
 		if (vq->desc[desc_indexes[i]].flags & VRING_DESC_F_INDIRECT) {
c7ffa4
+			dlen = vq->desc[desc_indexes[i]].len;
c7ffa4
 			desc = (struct vring_desc *)(uintptr_t)
c7ffa4
 				vhost_iova_to_vva(dev, vq,
c7ffa4
 						vq->desc[desc_indexes[i]].addr,
c7ffa4
-						vq->desc[desc_indexes[i]].len,
c7ffa4
+						&dlen,
c7ffa4
 						VHOST_ACCESS_RO);
c7ffa4
-			if (unlikely(!desc))
c7ffa4
+			if (unlikely(!desc ||
c7ffa4
+					dlen != vq->desc[desc_indexes[i]].len))
c7ffa4
 				break;
c7ffa4
 
c7ffa4
-- 
c7ffa4
1.8.3.1
c7ffa4