vhost: check all range is mapped when translating GPAs
[dpdk.git] / lib / librte_vhost / virtio_net.c
index 108f4de..2be3e7a 100644 (file)
@@ -180,6 +180,7 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq,
        uint32_t desc_avail, desc_offset;
        uint32_t mbuf_avail, mbuf_offset;
        uint32_t cpy_len;
+       uint64_t dlen;
        struct vring_desc *desc;
        uint64_t desc_addr;
        /* A counter to avoid desc dead loop chain */
@@ -189,14 +190,16 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq,
        int error = 0;
 
        desc = &descs[desc_idx];
+       dlen = desc->len;
        desc_addr = vhost_iova_to_vva(dev, vq, desc->addr,
-                                       desc->len, VHOST_ACCESS_RW);
+                                       &dlen, VHOST_ACCESS_RW);
        /*
         * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid
         * performance issue with some versions of gcc (4.8.4 and 5.3.0) which
         * otherwise stores offset on the stack instead of in a register.
         */
-       if (unlikely(desc->len < dev->vhost_hlen) || !desc_addr) {
+       if (unlikely(dlen != desc->len || desc->len < dev->vhost_hlen) ||
+                       !desc_addr) {
                error = -1;
                goto out;
        }
@@ -234,10 +237,11 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq,
                        }
 
                        desc = &descs[desc->next];
+                       dlen = desc->len;
                        desc_addr = vhost_iova_to_vva(dev, vq, desc->addr,
-                                                       desc->len,
+                                                       &dlen,
                                                        VHOST_ACCESS_RW);
-                       if (unlikely(!desc_addr)) {
+                       if (unlikely(!desc_addr || dlen != desc->len)) {
                                error = -1;
                                goto out;
                        }
@@ -351,12 +355,13 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,
                int err;
 
                if (vq->desc[desc_idx].flags & VRING_DESC_F_INDIRECT) {
+                       uint64_t dlen = vq->desc[desc_idx].len;
                        descs = (struct vring_desc *)(uintptr_t)
                                vhost_iova_to_vva(dev,
                                                vq, vq->desc[desc_idx].addr,
-                                               vq->desc[desc_idx].len,
-                                               VHOST_ACCESS_RO);
-                       if (unlikely(!descs)) {
+                                               &dlen, VHOST_ACCESS_RO);
+                       if (unlikely(!descs ||
+                                       dlen != vq->desc[desc_idx].len)) {
                                count = i;
                                break;
                        }
@@ -408,16 +413,18 @@ fill_vec_buf(struct virtio_net *dev, struct vhost_virtqueue *vq,
        uint16_t idx = vq->avail->ring[avail_idx & (vq->size - 1)];
        uint32_t vec_id = *vec_idx;
        uint32_t len    = 0;
+       uint64_t dlen;
        struct vring_desc *descs = vq->desc;
 
        *desc_chain_head = idx;
 
        if (vq->desc[idx].flags & VRING_DESC_F_INDIRECT) {
+               dlen = vq->desc[idx].len;
                descs = (struct vring_desc *)(uintptr_t)
                        vhost_iova_to_vva(dev, vq, vq->desc[idx].addr,
-                                               vq->desc[idx].len,
+                                               &dlen,
                                                VHOST_ACCESS_RO);
-               if (unlikely(!descs))
+               if (unlikely(!descs || dlen != vq->desc[idx].len))
                        return -1;
 
                idx = 0;
@@ -500,6 +507,7 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
        uint32_t mbuf_offset, mbuf_avail;
        uint32_t desc_offset, desc_avail;
        uint32_t cpy_len;
+       uint64_t dlen;
        uint64_t hdr_addr, hdr_phys_addr;
        struct rte_mbuf *hdr_mbuf;
        struct batch_copy_elem *batch_copy = vq->batch_copy_elems;
@@ -511,10 +519,12 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
                goto out;
        }
 
+       dlen = buf_vec[vec_idx].buf_len;
        desc_addr = vhost_iova_to_vva(dev, vq, buf_vec[vec_idx].buf_addr,
-                                               buf_vec[vec_idx].buf_len,
-                                               VHOST_ACCESS_RW);
-       if (buf_vec[vec_idx].buf_len < dev->vhost_hlen || !desc_addr) {
+                                               &dlen, VHOST_ACCESS_RW);
+       if (dlen != buf_vec[vec_idx].buf_len ||
+                       buf_vec[vec_idx].buf_len < dev->vhost_hlen ||
+                       !desc_addr) {
                error = -1;
                goto out;
        }
@@ -536,12 +546,14 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
                /* done with current desc buf, get the next one */
                if (desc_avail == 0) {
                        vec_idx++;
+                       dlen = buf_vec[vec_idx].buf_len;
                        desc_addr =
                                vhost_iova_to_vva(dev, vq,
                                        buf_vec[vec_idx].buf_addr,
-                                       buf_vec[vec_idx].buf_len,
+                                       &dlen,
                                        VHOST_ACCESS_RW);
-                       if (unlikely(!desc_addr)) {
+                       if (unlikely(!desc_addr ||
+                                       dlen != buf_vec[vec_idx].buf_len)) {
                                error = -1;
                                goto out;
                        }
@@ -847,6 +859,7 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
        uint32_t desc_avail, desc_offset;
        uint32_t mbuf_avail, mbuf_offset;
        uint32_t cpy_len;
+       uint64_t dlen;
        struct rte_mbuf *cur = m, *prev = m;
        struct virtio_net_hdr *hdr = NULL;
        /* A counter to avoid desc dead loop chain */
@@ -862,11 +875,12 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
                goto out;
        }
 
+       dlen = desc->len;
        desc_addr = vhost_iova_to_vva(dev,
                                        vq, desc->addr,
-                                       desc->len,
+                                       &dlen,
                                        VHOST_ACCESS_RO);
-       if (unlikely(!desc_addr)) {
+       if (unlikely(!desc_addr || dlen != desc->len)) {
                error = -1;
                goto out;
        }
@@ -889,11 +903,12 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
                        goto out;
                }
 
+               dlen = desc->len;
                desc_addr = vhost_iova_to_vva(dev,
                                                        vq, desc->addr,
-                                                       desc->len,
+                                                       &dlen,
                                                        VHOST_ACCESS_RO);
-               if (unlikely(!desc_addr)) {
+               if (unlikely(!desc_addr || dlen != desc->len)) {
                        error = -1;
                        goto out;
                }
@@ -977,11 +992,11 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
                                goto out;
                        }
 
+                       dlen = desc->len;
                        desc_addr = vhost_iova_to_vva(dev,
                                                        vq, desc->addr,
-                                                       desc->len,
-                                                       VHOST_ACCESS_RO);
-                       if (unlikely(!desc_addr)) {
+                                                       &dlen, VHOST_ACCESS_RO);
+                       if (unlikely(!desc_addr || dlen != desc->len)) {
                                error = -1;
                                goto out;
                        }
@@ -1252,18 +1267,21 @@ rte_vhost_dequeue_burst(int vid, uint16_t queue_id,
        for (i = 0; i < count; i++) {
                struct vring_desc *desc;
                uint16_t sz, idx;
+               uint64_t dlen;
                int err;
 
                if (likely(i + 1 < count))
                        rte_prefetch0(&vq->desc[desc_indexes[i + 1]]);
 
                if (vq->desc[desc_indexes[i]].flags & VRING_DESC_F_INDIRECT) {
+                       dlen = vq->desc[desc_indexes[i]].len;
                        desc = (struct vring_desc *)(uintptr_t)
                                vhost_iova_to_vva(dev, vq,
                                                vq->desc[desc_indexes[i]].addr,
-                                               vq->desc[desc_indexes[i]].len,
+                                               &dlen,
                                                VHOST_ACCESS_RO);
-                       if (unlikely(!desc))
+                       if (unlikely(!desc ||
+                                       dlen != vq->desc[desc_indexes[i]].len))
                                break;
 
                        rte_prefetch0(desc);