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
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
Hello Philippe,
I think you don't need root privileges to craft such a highly
fragmented packet from within the guest (tools like hping3 or nmap
come to mind). Right? If so, we may consider allocating a CVE for this
bug. If not, this is not CVE worthy - root does not need an assertion
failure to cause damage to the system.
On Mon, Jul 5, 2021 at 10:40 AM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> 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
>
--
Mauro Matteo Cascella
Red Hat Product Security
PGP-Key ID: BB3410B0
Hi Mauro,
On 7/6/21 11:00 AM, Mauro Matteo Cascella wrote:
> Hello Philippe,
>
> I think you don't need root privileges to craft such a highly
> fragmented packet from within the guest (tools like hping3 or nmap
> come to mind). Right? If so, we may consider allocating a CVE for this
> bug. If not, this is not CVE worthy - root does not need an assertion
> failure to cause damage to the system.
Thanks for worrying about CVE. I have no clue, so I'll
defer that question to Andrew, Dmitry and Jason.
Regards,
Phil.
> On Mon, Jul 5, 2021 at 10:40 AM Philippe Mathieu-Daudé
> <philmd@redhat.com> wrote:
>>
>> 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,
On 05/07/2021 10.40, Philippe Mathieu-Daudé wrote: > 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 Reviewed-by: Thomas Huth <thuth@redhat.com> Jason, I think this would even still qualify for QEMU v6.1 ?
On 8/3/21 11:33 AM, Thomas Huth wrote: > On 05/07/2021 10.40, Philippe Mathieu-Daudé wrote: >> 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 > > Reviewed-by: Thomas Huth <thuth@redhat.com> > > Jason, I think this would even still qualify for QEMU v6.1 ? Yes, easy one for 6.1.
在 2021/8/3 下午5:51, Philippe Mathieu-Daudé 写道: > On 8/3/21 11:33 AM, Thomas Huth wrote: >> On 05/07/2021 10.40, Philippe Mathieu-Daudé wrote: >>> 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 >> Reviewed-by: Thomas Huth <thuth@redhat.com> >> >> Jason, I think this would even still qualify for QEMU v6.1 ? > Yes, easy one for 6.1. Yes, this will be included for rc3. Thanks >
在 2021/8/4 上午9:43, Jason Wang 写道: > > 在 2021/8/3 下午5:51, Philippe Mathieu-Daudé 写道: >> On 8/3/21 11:33 AM, Thomas Huth wrote: >>> On 05/07/2021 10.40, Philippe Mathieu-Daudé wrote: >>>> 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 >>> Reviewed-by: Thomas Huth <thuth@redhat.com> >>> >>> Jason, I think this would even still qualify for QEMU v6.1 ? >> Yes, easy one for 6.1. > > > Yes, this will be included for rc3. > > Thanks For some reasons it misses rc3. I will include it for 6.2. Sorry. > > >>
On 11/08/2021 06.08, Jason Wang wrote: > > 在 2021/8/4 上午9:43, Jason Wang 写道: >> >> 在 2021/8/3 下午5:51, Philippe Mathieu-Daudé 写道: >>> On 8/3/21 11:33 AM, Thomas Huth wrote: >>>> On 05/07/2021 10.40, Philippe Mathieu-Daudé wrote: >>>>> 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 >>>> Reviewed-by: Thomas Huth <thuth@redhat.com> >>>> >>>> Jason, I think this would even still qualify for QEMU v6.1 ? >>> Yes, easy one for 6.1. >> >> >> Yes, this will be included for rc3. >> >> Thanks > > For some reasons it misses rc3. > > I will include it for 6.2. > > Sorry. Hi Jason, looks like this fell through the cracks again ... could you maybe pick it up now for QEMU 7.1 ? Thomas
© 2016 - 2026 Red Hat, Inc.