Message ID | 20210705084011.814175-1-philmd@redhat.com |
---|---|
State | New |
Headers | show |
Series | hw/net: Discard overly fragmented packets | expand |
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 >
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
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',
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