Race condition in megasas device
Host environment
-
Operating system: Debian 12
-
OS/kernel version: Kernel: Linux 6.1.0-11-amd64
-
Architecture: x86_64
-
QEMU version: QEMU emulator version 9.0.50 (v9.0.0-1733-g3f044554b9)
-
QEMU command line:
./build/qemu-system-x86_64 -display none -machine accel=qtest, -m 512M -machine q35 -nodefaults -device megasas -device scsi-cd,drive=null0 -blockdev driver=null-co,read-zeroes=on,node-name=null0 -qtest stdio
Emulated/Virtualized environment
Does not matter
Description of problem
Race condition DoS in megasas device was found during fuzzing. I'm not sure about worst case impact, but for now I can make a suggestion: worst case might be leading to DoS, but probably it's a rabbit hole. So if we dig deeper we might find something like CWE-200 or CWE-202 (Exposure of Sensitive Information to an Unauthorized Actor and so on). Also, I think that we should analyse thread usage in this case and make all operations thread-safe, but it's not my business of course. As a consequence, I do not suggest any patch (at least for now).
Steps to reproduce
This command:
cat << EOF | ./build/qemu-system-x86_64 \
-display none -machine accel=qtest, -m 512M -machine q35 -nodefaults \
-device megasas -device scsi-cd,drive=null0 -blockdev \
driver=null-co,read-zeroes=on,node-name=null0 -qtest stdio
outl 0xcf8 0x80000818
outl 0xcfc 0xc000
outl 0xcf8 0x80000804
outw 0xcfc 0x05
write 0x20 0x1 0x03
write 0x26 0x1 0x08
write 0x27 0x1 0x01
write 0x30 0x1 0x02
write 0x40 0x1 0x08
write 0x57 0x1 0x01
write 0x5a 0x1 0x08
outl 0xc03d 0x20000000
outl 0xc03d 0x00
EOF
Results in:
[R +0.081916] outl 0xcf8 0x80000818
[S +0.081986] OK
OK
[R +0.082033] outl 0xcfc 0xc000
[S +0.082083] OK
OK
[R +0.082102] outl 0xcf8 0x80000804
[S +0.082117] OK
OK
[R +0.082133] outw 0xcfc 0x05
[S +0.082926] OK
OK
[R +0.082961] write 0x20 0x1 0x03
[S +0.083688] OK
OK
[R +0.083731] write 0x26 0x1 0x08
[S +0.083754] OK
OK
[R +0.083780] write 0x27 0x1 0x01
[S +0.083799] OK
OK
[R +0.083817] write 0x30 0x1 0x02
[S +0.083850] OK
OK
[R +0.083872] write 0x40 0x1 0x08
[S +0.083903] OK
OK
[R +0.083925] write 0x57 0x1 0x01
[S +0.083947] OK
OK
[R +0.083962] write 0x5a 0x1 0x08
[S +0.083985] OK
OK
[R +0.084000] outl 0xc03d 0x20000000
[S +0.085531] OK
OK
[R +0.085570] outl 0xc03d 0x00
[S +0.085673] OK
OK
qemu/include/exec/memory.h:1152:12: runtime error: member access within null pointer of type 'AddressSpace' (aka 'struct AddressSpace')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior qemu/include/exec/memory.h:1152:12 in
AddressSanitizer:DEADLYSIGNAL
=================================================================
==168244==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000020 (pc 0x56259b9829ac bp 0x000000000001 sp 0x7ffe62140220 T0)
==168244==The signal is caused by a READ memory access.
==168244==Hint: address points to the zero page.
#0 0x56259b9829ac in address_space_to_flatview qemu/include/exec/memory.h:1152:12
#1 0x56259b9829ac in address_space_write qemu/build/../system/physmem.c:2929:14
#2 0x56259b98665e in address_space_unmap qemu/build/../system/physmem.c:3272:9
#3 0x56259af31dce in dma_memory_unmap qemu/include/sysemu/dma.h:236:5
#4 0x56259af31dce in dma_blk_unmap qemu/build/../system/dma-helpers.c:93:9
#5 0x56259af2f220 in dma_complete qemu/build/../system/dma-helpers.c:105:5
#6 0x56259af2f220 in dma_blk_cb qemu/build/../system/dma-helpers.c:129:9
#7 0x56259bce7041 in blk_aio_complete qemu/build/../block/block-backend.c:1555:9
#8 0x56259c224495 in aio_bh_call qemu/build/../util/async.c:171:5
#9 0x56259c224ca6 in aio_bh_poll qemu/build/../util/async.c:218:13
#10 0x56259c1b9b89 in aio_dispatch qemu/build/../util/aio-posix.c:423:5
#11 0x56259c228f40 in aio_ctx_dispatch qemu/build/../util/async.c:360:5
#12 0x7f2b8c0a07a8 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x547a8) (BuildId: 9f90bd7bbfcf84a1f1c5a6102f70e6264837b9d4)
#13 0x56259c22a1ed in glib_pollfds_poll qemu/build/../util/main-loop.c:287:9
#14 0x56259c22a1ed in os_host_main_loop_wait qemu/build/../util/main-loop.c:310:5
#15 0x56259c22a1ed in main_loop_wait qemu/build/../util/main-loop.c:589:11
#16 0x56259af5159e in qemu_main_loop qemu/build/../system/runstate.c:796:9
#17 0x56259baefdb4 in qemu_default_main qemu/build/../system/main.c:37:14
#18 0x7f2b8aff7249 (/lib/x86_64-linux-gnu/libc.so.6+0x27249) (BuildId: 82ce4e6e4ef08fa58a3535f7437bd3e592db5ac0)
#19 0x7f2b8aff7304 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x27304) (BuildId: 82ce4e6e4ef08fa58a3535f7437bd3e592db5ac0)
#20 0x562599f60b70 in _start (qemu/build/qemu-system-x86_64+0x20feb70) (BuildId: 48f1333e9a9d60383d8c9e0db5f690e7c26e1bb2)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV qemu/include/exec/memory.h:1152:12 in address_space_to_flatview
==168244==ABORTING
But, if we manually put all of those qtest commands and wait for each command to complete, QEMU doesn't fail. It's because of possible race condition - while QEMU still mapping memory, we already starting to unmap it. It results in this crash.