qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] hw/net: Discard overly fragmented packets


From: Philippe Mathieu-Daudé
Subject: [PATCH] hw/net: Discard overly fragmented packets
Date: Mon, 5 Jul 2021 10:40:11 +0200

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 via email to

[Prev in Thread] Current Thread [Next in Thread]