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