[dpdk-dev,v2,7/7] vhost: do sanity check for desc->next

Message ID 1455803352-5518-8-git-send-email-yuanhan.liu@linux.intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Commit Message

Yuanhan Liu Feb. 18, 2016, 1:49 p.m. UTC
  A malicious guest may easily forge some illegal vring desc buf.
To make our vhost robust, we need make sure desc->next will not
go beyond the vq->desc[] array.

Suggested-by: Rich Lane <rich.lane@bigswitch.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 lib/librte_vhost/vhost_rxtx.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
  

Comments

Huawei Xie March 7, 2016, 3:10 a.m. UTC | #1
On 2/18/2016 9:48 PM, Yuanhan Liu wrote:
> +			if (unlikely(desc->next >= vq->size))
> +				goto fail;

desc chains could be forged into a loop then vhost runs the dead loop
until it exhaust all mbuf memory.
  
Yuanhan Liu March 7, 2016, 6:57 a.m. UTC | #2
On Mon, Mar 07, 2016 at 03:10:43AM +0000, Xie, Huawei wrote:
> On 2/18/2016 9:48 PM, Yuanhan Liu wrote:
> > +			if (unlikely(desc->next >= vq->size))
> > +				goto fail;
> 
> desc chains could be forged into a loop then vhost runs the dead loop
> until it exhaust all mbuf memory.

Good point. Any elegant solution to avoid that?

	--yliu
  

Patch

diff --git a/lib/librte_vhost/vhost_rxtx.c b/lib/librte_vhost/vhost_rxtx.c
index c2adcd9..b0c0c94 100644
--- a/lib/librte_vhost/vhost_rxtx.c
+++ b/lib/librte_vhost/vhost_rxtx.c
@@ -148,6 +148,8 @@  copy_mbuf_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq,
 				/* Room in vring buffer is not enough */
 				return -1;
 			}
+			if (unlikely(desc->next >= vq->size))
+				return -1;
 
 			desc = &vq->desc[desc->next];
 			desc_addr   = gpa_to_vva(dev, desc->addr);
@@ -302,7 +304,7 @@  fill_vec_buf(struct vhost_virtqueue *vq, uint32_t avail_idx,
 	uint32_t len    = *allocated;
 
 	while (1) {
-		if (vec_id >= BUF_VECTOR_MAX)
+		if (unlikely(vec_id >= BUF_VECTOR_MAX || idx >= vq->size))
 			return -1;
 
 		len += vq->desc[idx].len;
@@ -671,6 +673,8 @@  copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
 	while (desc_avail || (desc->flags & VRING_DESC_F_NEXT) != 0) {
 		/* This desc reachs to its end, get the next one */
 		if (desc_avail == 0) {
+			if (unlikely(desc->next >= vq->size))
+				goto fail;
 			desc = &vq->desc[desc->next];
 
 			desc_addr = gpa_to_vva(dev, desc->addr);
@@ -691,9 +695,7 @@  copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
 			if (unlikely(!cur)) {
 				RTE_LOG(ERR, VHOST_DATA, "Failed to "
 					"allocate memory for mbuf.\n");
-				if (head)
-					rte_pktmbuf_free(head);
-				return NULL;
+				goto fail;
 			}
 			if (!head) {
 				head = cur;
@@ -729,6 +731,11 @@  copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
 	}
 
 	return head;
+
+fail:
+	if (head)
+		rte_pktmbuf_free(head);
+	return NULL;
 }
 
 uint16_t