All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHv2] virtio-net: correct packet length checks
@ 2010-06-24 15:29 Michael S. Tsirkin
  0 siblings, 0 replies; only message in thread
From: Michael S. Tsirkin @ 2010-06-24 15:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, alex.williamson, Juan Quintela

We were requesting too much when checking buffer
length: size already includes host header length.

Further, we should not exit if we get a packet that
is too long, since this might not be under control
of the guest. Just drop the packet.

Red Hat bz 591494 

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---

This supercedes the patch virtio-net: correct header length checks
Changes from v1:
	address review comments

 hw/virtio-net.c |   41 ++++++++++++++++++++++++++++-------------
 1 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 06ba481..e28d2bd 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -527,17 +527,18 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
 {
     VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
     struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
-    size_t hdr_len, offset, i;
+    size_t guest_hdr_len, offset, i, host_hdr_len;
 
     if (!virtio_net_can_receive(&n->nic->nc))
         return -1;
 
     /* hdr_len refers to the header we supply to the guest */
-    hdr_len = n->mergeable_rx_bufs ?
+    guest_hdr_len = n->mergeable_rx_bufs ?
         sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
 
 
-    if (!virtio_net_has_buffers(n, size + hdr_len))
+    host_hdr_len = n->has_vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
+    if (!virtio_net_has_buffers(n, size + guest_hdr_len - host_hdr_len))
         return 0;
 
     if (!receive_filter(n, buf, size))
@@ -552,13 +553,14 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         total = 0;
 
-        if ((i != 0 && !n->mergeable_rx_bufs) ||
-            virtqueue_pop(n->rx_vq, &elem) == 0) {
+        if (virtqueue_pop(n->rx_vq, &elem) == 0) {
             if (i == 0)
                 return -1;
-            fprintf(stderr, "virtio-net truncating packet: "
-                    "offset %zd, size %zd, hdr_len %zd\n",
-                    offset, size, hdr_len);
+            fprintf(stderr, "virtio-net unexpected empty queue: "
+                    "i %d mergeable %d offset %zd, size %zd, "
+                    "guest hdr len %zd, host hdr len %zd guest features 0x%x\n",
+                    i, n->mergeable_rx_bufs, offset, size,
+                    guest_hdr_len, host_hdr_len, n->vdev.guest_features);
             exit(1);
         }
 
@@ -567,7 +569,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
             exit(1);
         }
 
-        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {
+        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
             fprintf(stderr, "virtio-net header not in first element\n");
             exit(1);
         }
@@ -579,19 +581,32 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
                 mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
 
             offset += receive_header(n, sg, elem.in_num,
-                                     buf + offset, size - offset, hdr_len);
-            total += hdr_len;
+                                     buf + offset, size - offset, guest_hdr_len);
+            total += guest_hdr_len;
         }
 
         /* copy in packet.  ugh */
         len = iov_from_buf(sg, elem.in_num,
                            buf + offset, size - offset);
         total += len;
+        offset += len;
+        /* If buffers can't be merged, at this point we
+         * must have consumed the complete packet.
+         * Otherwise, drop it. */
+        if (!n->mergeable_rx_bufs && offset < size) {
+#if 0
+            fprintf(stderr, "virtio-net truncated non-mergeable packet: "
+
+                    "i %d mergeable %d offset %zd, size %zd, "
+                    "guest hdr len %zd, host hdr len %zd\n",
+                    i, n->mergeable_rx_bufs,
+                    offset, size, guest_hdr_len, host_hdr_len);
+#endif
+            return size;
+        }
 
         /* signal other side */
         virtqueue_fill(n->rx_vq, &elem, total, i++);
-
-        offset += len;
     }
 
     if (mhdr)
-- 
1.7.1.12.g42b7f

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2010-06-24 15:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-24 15:29 [Qemu-devel] [PATCHv2] virtio-net: correct packet length checks Michael S. Tsirkin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.