From eb84ec128104b04861283adbc8b0fe7d11f638c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Nov 2021 12:17:31 +0100 Subject: [PATCH 1/4] hw/scsi/lsi53c895a: Do not abort when DMA requested and no data queued MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If asked for DMA request and no data is available, simply wait for data to be queued, do not abort. This fixes: $ cat << EOF | \ qemu-system-i386 -nographic -M q35,accel=qtest -serial none \ -monitor none -qtest stdio -trace lsi* \ -drive if=none,id=drive0,file=null-co://,file.read-zeroes=on,format=raw \ -device lsi53c895a,id=scsi0 -device scsi-hd,drive=drive0,bus=scsi0.0,channel=0,scsi-id=0,lun=0 lsi_reset Reset lsi_reg_write Write reg DSP2 0x2e = 0xff lsi_reg_write Write reg DSP3 0x2f = 0xff lsi_execute_script SCRIPTS dsp=0xffff0000 opcode 0x184a3900 arg 0x4a8b2d75 qemu-system-i386: hw/scsi/lsi53c895a.c:624: lsi_do_dma: Assertion `s->current' failed. (gdb) bt #5 0x00007ffff4e8a3a6 in __GI___assert_fail (assertion=0x5555560accbc "s->current", file=0x5555560acc28 "hw/scsi/lsi53c895a.c", line=624, function=0x5555560adb18 "lsi_do_dma") at assert.c:101 #6 0x0000555555aa33b9 in lsi_do_dma (s=0x555557805ac0, out=1) at hw/scsi/lsi53c895a.c:624 #7 0x0000555555aa5042 in lsi_execute_script (s=0x555557805ac0) at hw/scsi/lsi53c895a.c:1250 #8 0x0000555555aa757a in lsi_reg_writeb (s=0x555557805ac0, offset=47, val=255 '\377') at hw/scsi/lsi53c895a.c:1984 #9 0x0000555555aa875b in lsi_mmio_write (opaque=0x555557805ac0, addr=47, val=255, size=1) at hw/scsi/lsi53c895a.c:2095 Cc: qemu-stable@nongnu.org Cc: Gerd Hoffmann Cc: Vadim Rozenfeld Cc: Stefan Hajnoczi Reported-by: Jérôme Poulin Reported-by: Ruhr-University Reported-by: Gaoning Pan Reported-by: Cheolwoo Myung Fixes: b96a0da06bd ("lsi: move dma_len+dma_buf into lsi_request") BugLink: https://bugs.launchpad.net/qemu/+bug/697510 BugLink: https://bugs.launchpad.net/qemu/+bug/1905521 BugLink: https://bugs.launchpad.net/qemu/+bug/1908515 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/84 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/305 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/552 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20211123111732.83137-2-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/lsi53c895a.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 85e907a785..4c431adb77 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -621,8 +621,7 @@ static void lsi_do_dma(LSIState *s, int out) dma_addr_t addr; SCSIDevice *dev; - assert(s->current); - if (!s->current->dma_len) { + if (!s->current || !s->current->dma_len) { /* Wait until data is available. */ trace_lsi_do_dma_unavailable(); return; -- Gitee From 32e9fb62e900e94cb2e39e6bd9717983bb259d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Nov 2021 12:17:32 +0100 Subject: [PATCH 2/4] tests/qtest: Add fuzz-lsi53c895a-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without the previous commit, this test triggers: $ make check-qtest-x86_64 [...] Running test qtest-x86_64/fuzz-lsi53c895a-test qemu-system-x86_64: hw/scsi/lsi53c895a.c:624: lsi_do_dma: Assertion `s->current' failed. ERROR qtest-x86_64/fuzz-lsi53c895a-test - too few tests run (expected 1, got 0) Suggested-by: Alexander Bulekov Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20211123111732.83137-3-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + tests/qtest/fuzz-lsi53c895a-test.c | 52 ++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 3 files changed, 54 insertions(+) create mode 100644 tests/qtest/fuzz-lsi53c895a-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 7543eb4d59..fbd6d0b174 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1825,6 +1825,7 @@ F: hw/scsi/* F: tests/qtest/virtio-scsi-test.c F: tests/qtest/fuzz-virtio-scsi-test.c F: tests/qtest/am53c974-test.c +F: tests/qtest/fuzz-lsi53c895a-test.c T: git https://github.com/bonzini/qemu.git scsi-next SSI diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c new file mode 100644 index 0000000000..ba5d468970 --- /dev/null +++ b/tests/qtest/fuzz-lsi53c895a-test.c @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QTest fuzzer-generated testcase for LSI53C895A device + * + * Copyright (c) Red Hat + */ + +#include "qemu/osdep.h" +#include "libqos/libqtest.h" + +/* + * This used to trigger the assert in lsi_do_dma() + * https://bugs.launchpad.net/qemu/+bug/697510 + * https://bugs.launchpad.net/qemu/+bug/1905521 + * https://bugs.launchpad.net/qemu/+bug/1908515 + */ +static void test_lsi_do_dma_empty_queue(void) +{ + QTestState *s; + + s = qtest_init("-M q35 -nographic -monitor none -serial none " + "-drive if=none,id=drive0," + "file=null-co://,file.read-zeroes=on,format=raw " + "-device lsi53c895a,id=scsi0 " + "-device scsi-hd,drive=drive0," + "bus=scsi0.0,channel=0,scsi-id=0,lun=0"); + qtest_outl(s, 0xcf8, 0x80001814); + qtest_outl(s, 0xcfc, 0xe1068000); + qtest_outl(s, 0xcf8, 0x80001818); + qtest_outl(s, 0xcf8, 0x80001804); + qtest_outw(s, 0xcfc, 0x7); + qtest_outl(s, 0xcf8, 0x80002010); + + qtest_writeb(s, 0xe106802e, 0xff); /* Fill DSP bits 16-23 */ + qtest_writeb(s, 0xe106802f, 0xff); /* Fill DSP bits 24-31: trigger SCRIPT */ + + 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/lsi53c895a/lsi_do_dma_empty_queue", + test_lsi_do_dma_empty_queue); + } + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index c9d8458062..d2ce20d304 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -19,6 +19,7 @@ slow_qtests = { qtests_generic = \ (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ + (config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \ (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \ -- Gitee From 87d97af840d61122e801a37a89e6bf48a2cbe8e2 Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Tue, 5 Jul 2022 22:05:43 +0200 Subject: [PATCH 3/4] scsi/lsi53c895a: fix use-after-free in lsi_do_msgout (CVE-2022-0216) Set current_req->req to NULL to prevent reusing a free'd buffer in case of repeated SCSI cancel requests. Thanks to Thomas Huth for suggesting the patch. Fixes: CVE-2022-0216 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 Signed-off-by: Mauro Matteo Cascella Reviewed-by: Thomas Huth Message-Id: <20220705200543.2366809-1-mcascell@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/lsi53c895a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 4c431adb77..4c91854df9 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -1028,8 +1028,9 @@ static void lsi_do_msgout(LSIState *s) case 0x0d: /* The ABORT TAG message clears the current I/O process only. */ trace_lsi_do_msgout_abort(current_tag); - if (current_req) { + if (current_req && current_req->req) { scsi_req_cancel(current_req->req); + current_req->req = NULL; } lsi_disconnect(s); break; -- Gitee From b0a1db1428e8d92693a323b9d479764071d08247 Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Mon, 11 Jul 2022 14:33:16 +0200 Subject: [PATCH 4/4] scsi/lsi53c895a: really fix use-after-free in lsi_do_msgout (CVE-2022-0216) Set current_req to NULL, not current_req->req, to prevent reusing a free'd buffer in case of repeated SCSI cancel requests. Also apply the fix to CLEAR QUEUE and BUS DEVICE RESET messages as well, since they also cancel the request. Thanks to Alexander Bulekov for providing a reproducer. Fixes: CVE-2022-0216 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 Signed-off-by: Mauro Matteo Cascella Tested-by: Alexander Bulekov Message-Id: <20220711123316.421279-1-mcascell@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/lsi53c895a.c | 3 +- tests/qtest/fuzz-lsi53c895a-test.c | 75 ++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 4c91854df9..b9c9eb0dac 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s) trace_lsi_do_msgout_abort(current_tag); if (current_req && current_req->req) { scsi_req_cancel(current_req->req); - current_req->req = NULL; + current_req = NULL; } lsi_disconnect(s); break; @@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s) /* clear the current I/O process */ if (s->current) { scsi_req_cancel(s->current->req); + current_req = NULL; } /* As the current implemented devices scsi_disk and scsi_generic diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c index ba5d468970..0f968024c8 100644 --- a/tests/qtest/fuzz-lsi53c895a-test.c +++ b/tests/qtest/fuzz-lsi53c895a-test.c @@ -8,6 +8,79 @@ #include "qemu/osdep.h" #include "libqos/libqtest.h" +/* + * This used to trigger a UAF in lsi_do_msgout() + * https://gitlab.com/qemu-project/qemu/-/issues/972 + */ +static void test_lsi_do_msgout_cancel_req(void) +{ + QTestState *s; + + if (sizeof(void *) == 4) { + g_test_skip("memory size too big for 32-bit build"); + return; + } + + s = qtest_init("-M q35 -m 4G -display none -nodefaults " + "-device lsi53c895a,id=scsi " + "-device scsi-hd,drive=disk0 " + "-drive file=null-co://,id=disk0,if=none,format=raw"); + + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outl(s, 0xcf8, 0xc000); + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outw(s, 0xcfc, 0x7); + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outl(s, 0xcfc, 0xc000); + qtest_outl(s, 0xcf8, 0x80000804); + qtest_outw(s, 0xcfc, 0x05); + qtest_writeb(s, 0x69736c10, 0x08); + qtest_writeb(s, 0x69736c13, 0x58); + qtest_writeb(s, 0x69736c1a, 0x01); + qtest_writeb(s, 0x69736c1b, 0x06); + qtest_writeb(s, 0x69736c22, 0x01); + qtest_writeb(s, 0x69736c23, 0x07); + qtest_writeb(s, 0x69736c2b, 0x02); + qtest_writeb(s, 0x69736c48, 0x08); + qtest_writeb(s, 0x69736c4b, 0x58); + qtest_writeb(s, 0x69736c52, 0x04); + qtest_writeb(s, 0x69736c53, 0x06); + qtest_writeb(s, 0x69736c5b, 0x02); + qtest_outl(s, 0xc02d, 0x697300); + qtest_writeb(s, 0x5a554662, 0x01); + qtest_writeb(s, 0x5a554663, 0x07); + qtest_writeb(s, 0x5a55466a, 0x10); + qtest_writeb(s, 0x5a55466b, 0x22); + qtest_writeb(s, 0x5a55466c, 0x5a); + qtest_writeb(s, 0x5a55466d, 0x5a); + qtest_writeb(s, 0x5a55466e, 0x34); + qtest_writeb(s, 0x5a55466f, 0x5a); + qtest_writeb(s, 0x5a345a5a, 0x77); + qtest_writeb(s, 0x5a345a5b, 0x55); + qtest_writeb(s, 0x5a345a5c, 0x51); + qtest_writeb(s, 0x5a345a5d, 0x27); + qtest_writeb(s, 0x27515577, 0x41); + qtest_outl(s, 0xc02d, 0x5a5500); + qtest_writeb(s, 0x364001d0, 0x08); + qtest_writeb(s, 0x364001d3, 0x58); + qtest_writeb(s, 0x364001da, 0x01); + qtest_writeb(s, 0x364001db, 0x26); + qtest_writeb(s, 0x364001dc, 0x0d); + qtest_writeb(s, 0x364001dd, 0xae); + qtest_writeb(s, 0x364001de, 0x41); + qtest_writeb(s, 0x364001df, 0x5a); + qtest_writeb(s, 0x5a41ae0d, 0xf8); + qtest_writeb(s, 0x5a41ae0e, 0x36); + qtest_writeb(s, 0x5a41ae0f, 0xd7); + qtest_writeb(s, 0x5a41ae10, 0x36); + qtest_writeb(s, 0x36d736f8, 0x0c); + qtest_writeb(s, 0x36d736f9, 0x80); + qtest_writeb(s, 0x36d736fa, 0x0d); + qtest_outl(s, 0xc02d, 0x364000); + + qtest_quit(s); +} + /* * This used to trigger the assert in lsi_do_dma() * https://bugs.launchpad.net/qemu/+bug/697510 @@ -46,6 +119,8 @@ int main(int argc, char **argv) if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", test_lsi_do_dma_empty_queue); + qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req", + test_lsi_do_msgout_cancel_req); } return g_test_run(); -- Gitee