All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] hw/net: Discard overly fragmented packets
@ 2021-07-05  8:40 Philippe Mathieu-Daudé
  2021-07-06  9:00 ` Mauro Matteo Cascella
  2021-08-03  9:33 ` Thomas Huth
  0 siblings, 2 replies; 8+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-07-05  8:40 UTC (permalink / raw)
  To: qemu-devel
  Cc: Mauro Matteo Cascella, Dmitry Fleytman, Jason Wang, Li Qiang,
	Andrew Melnychenko, Prasad J Pandit, Alexander Bulekov,
	Thomas Huth, qemu-stable, Philippe Mathieu-Daudé

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



^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-08-05 14:53 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-05  8:40 [PATCH] hw/net: Discard overly fragmented packets Philippe Mathieu-Daudé
2021-07-06  9:00 ` 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

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.