All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <philmd@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Mauro Matteo Cascella" <mcascell@redhat.com>,
	"Dmitry Fleytman" <dmitry.fleytman@gmail.com>,
	"Jason Wang" <jasowang@redhat.com>, "Li Qiang" <liq3ea@gmail.com>,
	"Andrew Melnychenko" <andrew@daynix.com>,
	"Prasad J Pandit" <ppandit@redhat.com>,
	"Alexander Bulekov" <alxndr@bu.edu>,
	"Thomas Huth" <thuth@redhat.com>,
	qemu-stable@nongnu.org,
	"Philippe Mathieu-Daudé" <philmd@redhat.com>
Subject: [PATCH] hw/net: Discard overly fragmented packets
Date: Mon,  5 Jul 2021 10:40:11 +0200	[thread overview]
Message-ID: <20210705084011.814175-1-philmd@redhat.com> (raw)

Our infrastructure can handle fragmented packets up to
NET_MAX_FRAG_SG_LIST (64) pieces. This hard limit has
been proven enough in production for years. If it is
reached, it is likely an evil crafted packet. Discard it.

Include the qtest reproducer provided by Alexander Bulekov:

  $ make check-qtest-i386
  ...
  Running test qtest-i386/fuzz-vmxnet3-test
  qemu-system-i386: net/eth.c:334: void eth_setup_ip4_fragmentation(const void *, size_t, void *, size_t, size_t, size_t, _Bool):
  Assertion `frag_offset % IP_FRAG_UNIT_SIZE == 0' failed.

Cc: qemu-stable@nongnu.org
Reported-by: OSS-Fuzz (Issue 35799)
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/460
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/net/net_tx_pkt.c             |   8 ++
 tests/qtest/fuzz-vmxnet3-test.c | 195 ++++++++++++++++++++++++++++++++
 MAINTAINERS                     |   1 +
 tests/qtest/meson.build         |   1 +
 4 files changed, 205 insertions(+)
 create mode 100644 tests/qtest/fuzz-vmxnet3-test.c

diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 1f9aa59eca2..77e9729a7ba 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -590,6 +590,14 @@ static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt,
         fragment_len = net_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset,
             fragment, &dst_idx);
 
+        if (dst_idx == NET_MAX_FRAG_SG_LIST && fragment_len > 0) {
+            /*
+             * The packet is too fragmented for our infrastructure
+             * (not enough iovec), don't even try to send.
+             */
+            return false;
+        }
+
         more_frags = (fragment_offset + fragment_len < pkt->payload_len);
 
         eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base,
diff --git a/tests/qtest/fuzz-vmxnet3-test.c b/tests/qtest/fuzz-vmxnet3-test.c
new file mode 100644
index 00000000000..d69009bf5ce
--- /dev/null
+++ b/tests/qtest/fuzz-vmxnet3-test.c
@@ -0,0 +1,195 @@
+/*
+ * QTest testcase for vmxnet3 device generated by fuzzer
+ *
+ * Copyright Red Hat
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqos/libqtest.h"
+
+/*
+ * https://gitlab.com/qemu-project/qemu/-/issues/460
+ */
+static void test_oss_35799_eth_setup_ip4_fragmentation(void)
+{
+    QTestState *s;
+
+    s = qtest_init("-machine q35 -m 32M -display none -nodefaults "
+                   "-device vmxnet3,netdev=net0 -netdev user,id=net0");
+    qtest_outl(s, 0xcf8, 0x80000814);
+    qtest_outl(s, 0xcfc, 0xe0000000);
+    qtest_outl(s, 0xcf8, 0x80000804);
+    qtest_outw(s, 0xcfc, 0x06);
+    qtest_outl(s, 0xcf8, 0x80000812);
+    qtest_outl(s, 0xcfc, 0x2000);
+    qtest_outl(s, 0xcf8, 0x80000815);
+    qtest_outb(s, 0xcfc, 0x40);
+    qtest_bufwrite(s, 0x0, "\xe1", 0x1);
+    qtest_bufwrite(s, 0x1, "\xfe", 0x1);
+    qtest_bufwrite(s, 0x2, "\xbe", 0x1);
+    qtest_bufwrite(s, 0x3, "\xba", 0x1);
+    qtest_bufwrite(s, 0x28, "\xff", 0x1);
+    qtest_bufwrite(s, 0x29, "\xff", 0x1);
+    qtest_bufwrite(s, 0x2a, "\xff", 0x1);
+    qtest_bufwrite(s, 0x2b, "\xff", 0x1);
+    qtest_bufwrite(s, 0x2c, "\xff", 0x1);
+    qtest_bufwrite(s, 0x2d, "\xff", 0x1);
+    qtest_bufwrite(s, 0x2e, "\xff", 0x1);
+    qtest_bufwrite(s, 0x2f, "\xff", 0x1);
+    qtest_bufwrite(s, 0x37, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3e, "\x01", 0x1);
+    qtest_bufwrite(s, 0xe0004020, "\x00\x00\xfe\xca", 0x4);
+    qtest_bufwrite(s, 0x9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xd, "\x10", 0x1);
+    qtest_bufwrite(s, 0x12, "\x10", 0x1);
+    qtest_bufwrite(s, 0x19, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1b, "\x21", 0x1);
+    qtest_bufwrite(s, 0x1d, "\x0c", 0x1);
+    qtest_bufwrite(s, 0x2d, "\x00", 0x1);
+    qtest_bufwrite(s, 0x10000c, "\x08", 0x1);
+    qtest_bufwrite(s, 0x10000e, "\x45", 0x1);
+    qtest_bufwrite(s, 0x100017, "\x11", 0x1);
+    qtest_bufwrite(s, 0x20000600, "\x00", 0x1);
+    qtest_bufwrite(s, 0x38, "\x01", 0x1);
+    qtest_bufwrite(s, 0x39, "\x40", 0x1);
+    qtest_bufwrite(s, 0x48, "\x01", 0x1);
+    qtest_bufwrite(s, 0x49, "\x40", 0x1);
+    qtest_bufwrite(s, 0x58, "\x01", 0x1);
+    qtest_bufwrite(s, 0x59, "\x40", 0x1);
+    qtest_bufwrite(s, 0x68, "\x01", 0x1);
+    qtest_bufwrite(s, 0x69, "\x40", 0x1);
+    qtest_bufwrite(s, 0x78, "\x01", 0x1);
+    qtest_bufwrite(s, 0x79, "\x40", 0x1);
+    qtest_bufwrite(s, 0x88, "\x01", 0x1);
+    qtest_bufwrite(s, 0x89, "\x40", 0x1);
+    qtest_bufwrite(s, 0x98, "\x01", 0x1);
+    qtest_bufwrite(s, 0x99, "\x40", 0x1);
+    qtest_bufwrite(s, 0xa8, "\x01", 0x1);
+    qtest_bufwrite(s, 0xa9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xb8, "\x01", 0x1);
+    qtest_bufwrite(s, 0xb9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xc8, "\x01", 0x1);
+    qtest_bufwrite(s, 0xc9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xd8, "\x01", 0x1);
+    qtest_bufwrite(s, 0xd9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xe8, "\x01", 0x1);
+    qtest_bufwrite(s, 0xe9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xf8, "\x01", 0x1);
+    qtest_bufwrite(s, 0xf9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x108, "\x01", 0x1);
+    qtest_bufwrite(s, 0x109, "\x40", 0x1);
+    qtest_bufwrite(s, 0x118, "\x01", 0x1);
+    qtest_bufwrite(s, 0x119, "\x40", 0x1);
+    qtest_bufwrite(s, 0x128, "\x01", 0x1);
+    qtest_bufwrite(s, 0x129, "\x40", 0x1);
+    qtest_bufwrite(s, 0x138, "\x01", 0x1);
+    qtest_bufwrite(s, 0x139, "\x40", 0x1);
+    qtest_bufwrite(s, 0x148, "\x01", 0x1);
+    qtest_bufwrite(s, 0x149, "\x40", 0x1);
+    qtest_bufwrite(s, 0x158, "\x01", 0x1);
+    qtest_bufwrite(s, 0x159, "\x40", 0x1);
+    qtest_bufwrite(s, 0x168, "\x01", 0x1);
+    qtest_bufwrite(s, 0x169, "\x40", 0x1);
+    qtest_bufwrite(s, 0x178, "\x01", 0x1);
+    qtest_bufwrite(s, 0x179, "\x40", 0x1);
+    qtest_bufwrite(s, 0x188, "\x01", 0x1);
+    qtest_bufwrite(s, 0x189, "\x40", 0x1);
+    qtest_bufwrite(s, 0x198, "\x01", 0x1);
+    qtest_bufwrite(s, 0x199, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1a8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x1a9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1b8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x1b9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1c8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x1c9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1d8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x1d9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1e8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x1e9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x1f8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x1f9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x208, "\x01", 0x1);
+    qtest_bufwrite(s, 0x209, "\x40", 0x1);
+    qtest_bufwrite(s, 0x218, "\x01", 0x1);
+    qtest_bufwrite(s, 0x219, "\x40", 0x1);
+    qtest_bufwrite(s, 0x228, "\x01", 0x1);
+    qtest_bufwrite(s, 0x229, "\x40", 0x1);
+    qtest_bufwrite(s, 0x238, "\x01", 0x1);
+    qtest_bufwrite(s, 0x239, "\x40", 0x1);
+    qtest_bufwrite(s, 0x248, "\x01", 0x1);
+    qtest_bufwrite(s, 0x249, "\x40", 0x1);
+    qtest_bufwrite(s, 0x258, "\x01", 0x1);
+    qtest_bufwrite(s, 0x259, "\x40", 0x1);
+    qtest_bufwrite(s, 0x268, "\x01", 0x1);
+    qtest_bufwrite(s, 0x269, "\x40", 0x1);
+    qtest_bufwrite(s, 0x278, "\x01", 0x1);
+    qtest_bufwrite(s, 0x279, "\x40", 0x1);
+    qtest_bufwrite(s, 0x288, "\x01", 0x1);
+    qtest_bufwrite(s, 0x289, "\x40", 0x1);
+    qtest_bufwrite(s, 0x298, "\x01", 0x1);
+    qtest_bufwrite(s, 0x299, "\x40", 0x1);
+    qtest_bufwrite(s, 0x2a8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x2a9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x2b8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x2b9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x2c8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x2c9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x2d8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x2d9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x2e8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x2e9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x2f8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x2f9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x308, "\x01", 0x1);
+    qtest_bufwrite(s, 0x309, "\x40", 0x1);
+    qtest_bufwrite(s, 0x318, "\x01", 0x1);
+    qtest_bufwrite(s, 0x319, "\x40", 0x1);
+    qtest_bufwrite(s, 0x328, "\x01", 0x1);
+    qtest_bufwrite(s, 0x329, "\x40", 0x1);
+    qtest_bufwrite(s, 0x338, "\x01", 0x1);
+    qtest_bufwrite(s, 0x339, "\x40", 0x1);
+    qtest_bufwrite(s, 0x348, "\x01", 0x1);
+    qtest_bufwrite(s, 0x349, "\x40", 0x1);
+    qtest_bufwrite(s, 0x358, "\x01", 0x1);
+    qtest_bufwrite(s, 0x359, "\x40", 0x1);
+    qtest_bufwrite(s, 0x368, "\x01", 0x1);
+    qtest_bufwrite(s, 0x369, "\x40", 0x1);
+    qtest_bufwrite(s, 0x378, "\x01", 0x1);
+    qtest_bufwrite(s, 0x379, "\x40", 0x1);
+    qtest_bufwrite(s, 0x388, "\x01", 0x1);
+    qtest_bufwrite(s, 0x389, "\x40", 0x1);
+    qtest_bufwrite(s, 0x398, "\x01", 0x1);
+    qtest_bufwrite(s, 0x399, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3a8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x3a9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3b8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x3b9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3c8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x3c9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3d8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x3d9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3e8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x3e9, "\x40", 0x1);
+    qtest_bufwrite(s, 0x3f8, "\x01", 0x1);
+    qtest_bufwrite(s, 0x3f9, "\x40", 0x1);
+    qtest_bufwrite(s, 0xd, "\x10", 0x1);
+    qtest_bufwrite(s, 0x20000600, "\x00", 0x1);
+    qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qtest_add_func("fuzz/test_oss_35799_eth_setup_ip4_fragmentation",
+                       test_oss_35799_eth_setup_ip4_fragmentation);
+    }
+
+    return g_test_run();
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index cb8f3ea2c2e..43e5050ad96 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2001,6 +2001,7 @@ S: Maintained
 F: hw/net/vmxnet*
 F: hw/scsi/vmw_pvscsi*
 F: tests/qtest/vmxnet3-test.c
+F: tests/qtest/fuzz-vmxnet3-test.c
 
 Rocker
 M: Jiri Pirko <jiri@resnulli.us>
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index b03e8541700..42add92e9d4 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -66,6 +66,7 @@
   (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) +              \
   (config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) +   \
+  (config_all_devices.has_key('CONFIG_VMXNET3_PCI') ? ['fuzz-vmxnet3-test'] : []) +   \
   (config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) +                 \
   qtests_pci +                                                                              \
   ['fdc-test',
-- 
2.31.1



             reply	other threads:[~2021-07-05  8:41 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-05  8:40 Philippe Mathieu-Daudé [this message]
2021-07-06  9:00 ` [PATCH] hw/net: Discard overly fragmented packets Mauro Matteo Cascella
2021-07-06  9:09   ` Philippe Mathieu-Daudé
2021-08-03  9:33 ` Thomas Huth
2021-08-03  9:51   ` Philippe Mathieu-Daudé
2021-08-04  1:43     ` Jason Wang
2021-08-11  4:08       ` Jason Wang
2022-08-05 14:51         ` Thomas Huth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210705084011.814175-1-philmd@redhat.com \
    --to=philmd@redhat.com \
    --cc=alxndr@bu.edu \
    --cc=andrew@daynix.com \
    --cc=dmitry.fleytman@gmail.com \
    --cc=jasowang@redhat.com \
    --cc=liq3ea@gmail.com \
    --cc=mcascell@redhat.com \
    --cc=ppandit@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-stable@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.