Heap buffer overflow in nand_blk_write_512()
Host environment
- Operating system: Ubuntu 20.04
- OS/kernel version: Linux 5.15.0-56-generic
- Architecture: x86
- QEMU flavor: qemu-system-arm
- QEMU version: 7.2.50
- QEMU command line: see below
Description of problem
I captured the negative-size-param (memcpy) in nand_blk_load_512() like below.
diff --git a/hw/block/nand.c b/hw/block/nand.c
index 8bc80e351..f68b23d05 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -790,6 +790,10 @@ static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
}
} else {
+ int size = NAND_PAGE_SIZE + OOB_SIZE - offset;
+ if (size < 0) {
+ return;
+ }
memcpy(s->io, s->storage + PAGE_START(s->addr) +
offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
s->ioaddr = s->io;
Then, I triggered an integer overflow in nand_blk_write_512() resulting in a heap buffer overflow. Specifically, s->iolen is a signed integer[1], but based on the function signature of mem_and(), s->iolen will be casted to an unsigned integer[2]. Asan then captures a heap buffer overflow[3].
static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
// ...
if (!s->blk) {
mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
s->offset, s->io, s->iolen); // <--------------- [1]
} else if (s->mem_oob) {
// ...
static void mem_and(uint8_t *dest, const uint8_t *src, size_t n) // <--- [2]
{
int i;
for (i = 0; i < n; i++) {
dest[i] &= src[i]; // <----------------------------------------- [3]
}
}
Steps to reproduce
Please patch your hw/block/nand.c first.
export QEMU=/path/to/qemu-system-arm
cat << EOF | $QEMU \
-machine tosa -monitor none -serial none \
-display none -qtest stdio
write 0x10000111 0x1 0xca
write 0x10000104 0x1 0x47
write 0x1000ca04 0x1 0xd7
write 0x1000ca01 0x1 0xe0
write 0x1000ca04 0x1 0x71
write 0x1000ca00 0x1 0x50
write 0x1000ca04 0x1 0xd7
read 0x1000ca02 0x1
write 0x1000ca01 0x1 0x10
EOF
Additional information
==15750==WARNING: ASan doesn't fully support makecontext/swapcontext functions and may produce false positives in some cases!
INFO: found LLVMFuzzerCustomMutator (0x560e65814d70). Disabling -len_control by default.
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 4218744906
INFO: Loaded 1 modules (601336 inline 8-bit counters): 601336 [0x560e68702000, 0x560e68794cf8),
INFO: Loaded 1 PC tables (601336 PCs): 601336 [0x560e67dd42a0,0x560e68701220),
/root/videzzo/videzzo_qemu/out-san/qemu-videzzo-arm-target-videzzo-fuzz-tc6393xb: Running 1 inputs 1 time(s) each.
INFO: Reading pre_seed_input if any ...
INFO: Executing pre_seed_input if any ...
Matching objects by name , *tc6393xb*
This process will fuzz the following MemoryRegions:
* tc6393xb.vram[0] (size 100000)
* tc6393xb[0] (size 10000)
This process will fuzz through the following interfaces:
* clock_step, EVENT_TYPE_CLOCK_STEP, 0xffffffff +0xffffffff, 255,255
* tc6393xb.vram, EVENT_TYPE_MMIO_READ, 0x10100000 +0x100000, 1,4
* tc6393xb.vram, EVENT_TYPE_MMIO_WRITE, 0x10100000 +0x100000, 1,4
* tc6393xb, EVENT_TYPE_MMIO_READ, 0x10000000 +0x10000, 1,1
* tc6393xb, EVENT_TYPE_MMIO_WRITE, 0x10000000 +0x10000, 1,1
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 3 ft: 4 corp: 1/1b exec/s: 0 rss: 281Mb
Running: /root/videzzo/videzzo_qemu/out-san/poc-qemu-videzzo-arm-target-videzzo-fuzz-tc6393xb-crash-35f3f537422c4e74ce65177b3d6369045e60b47f.minimized
=================================================================
==15750==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61f000000de0 at pc 0x560e61557210 bp 0x7ffcfc4a59f0 sp 0x7ffcfc4a59e8
READ of size 1 at 0x61f000000de0 thread T0
#0 0x560e6155720f in mem_and /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/block/nand.c:101:20
#1 0x560e6155ac9c in nand_blk_write_512 /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/block/nand.c:663:9
#2 0x560e61544200 in nand_command /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/block/nand.c:293:13
#3 0x560e6153cc83 in nand_setio /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/block/nand.c:520:13
#4 0x560e61a0a69e in tc6393xb_nand_writeb /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/display/tc6393xb.c:380:13
#5 0x560e619f9bf7 in tc6393xb_writeb /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/display/tc6393xb.c:524:9
#6 0x560e647c7d03 in memory_region_write_accessor /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/memory.c:492:5
#7 0x560e647c7641 in access_with_adjusted_size /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/memory.c:554:18
#8 0x560e647c5f66 in memory_region_dispatch_write /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/memory.c:1514:16
#9 0x560e6485409e in flatview_write_continue /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/physmem.c:2825:23
#10 0x560e648421eb in flatview_write /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/physmem.c:2867:12
#11 0x560e64841ca8 in address_space_write /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/physmem.c:2963:18
#12 0x560e61170162 in qemu_writeb /root/videzzo/videzzo_qemu/qemu/build-san-6/../tests/qtest/videzzo/videzzo_qemu.c:1080:5
#13 0x560e6116eef7 in dispatch_mmio_write /root/videzzo/videzzo_qemu/qemu/build-san-6/../tests/qtest/videzzo/videzzo_qemu.c:1227:28
#14 0x560e6581072f in videzzo_dispatch_event /root/videzzo/videzzo.c:1122:5
#15 0x560e65807aab in __videzzo_execute_one_input /root/videzzo/videzzo.c:272:9
#16 0x560e65807980 in videzzo_execute_one_input /root/videzzo/videzzo.c:313:9
#17 0x560e611780fc in videzzo_qemu /root/videzzo/videzzo_qemu/qemu/build-san-6/../tests/qtest/videzzo/videzzo_qemu.c:1504:12
#18 0x560e65815012 in LLVMFuzzerTestOneInput /root/videzzo/videzzo.c:1891:18
#19 0x560e61059816 in fuzzer::Fuzzer::ExecuteCallback(unsigned char*, unsigned long) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:594:17
#20 0x560e6103c444 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:323:21
#21 0x560e610473ee in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char*, unsigned long)) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:885:19
#22 0x560e610339d6 in main /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:30
#23 0x7f79587d0082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
#24 0x560e61033a2d in _start (/root/videzzo/videzzo_qemu/out-san/qemu-videzzo-arm-target-videzzo-fuzz-tc6393xb+0x300fa2d)
0x61f000000de0 is located 0 bytes to the right of 3424-byte region [0x61f000000080,0x61f000000de0)
allocated by thread T0 here:
#0 0x560e611276cf in malloc /root/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x7f7959a87e98 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x57e98)
#2 0x560e64b98871 in object_new /root/videzzo/videzzo_qemu/qemu/build-san-6/../qom/object.c:749:12
#3 0x560e64b5d1a1 in qdev_new /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/core/qdev.c:153:19
#4 0x560e61547ea5 in nand_init /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/block/nand.c:639:11
#5 0x560e619f8772 in tc6393xb_init /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/display/tc6393xb.c:558:16
#6 0x560e6390bad2 in tosa_init /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/arm/tosa.c:250:12
#7 0x560e61730887 in machine_run_board_init /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/core/machine.c:1400:5
#8 0x560e633bdd5b in qemu_init_board /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/vl.c:2485:5
#9 0x560e633bda6c in qmp_x_exit_preconfig /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/vl.c:2581:5
#10 0x560e633c4fef in qemu_init /root/videzzo/videzzo_qemu/qemu/build-san-6/../softmmu/vl.c:3584:9
#11 0x560e611763f3 in LLVMFuzzerInitialize /root/videzzo/videzzo_qemu/qemu/build-san-6/../tests/qtest/videzzo/videzzo_qemu.c:1761:5
#12 0x560e61043fab in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char*, unsigned long)) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:664:29
#13 0x560e610339d6 in main /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:30
#14 0x7f79587d0082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
SUMMARY: AddressSanitizer: heap-buffer-overflow /root/videzzo/videzzo_qemu/qemu/build-san-6/../hw/block/nand.c:101:20 in mem_and
Shadow bytes around the buggy address:
0x0c3e7fff8160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3e7fff8170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3e7fff8180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3e7fff8190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3e7fff81a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c3e7fff81b0: 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa
0x0c3e7fff81c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3e7fff81d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3e7fff81e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3e7fff81f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3e7fff8200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
Shadow gap: cc
==15750==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000
0x1,0xb,0x12,0x1,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xca,0x4f,0x4d,0x5f,0x0,0x0,0x0,0x0,0x1,0xb,0x4,0x1,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x47,0xf0,0xc8,0x58,0x0,0x0,0x0,0x0,0x1,0xb,0x4,0xa1,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xd7,0x38,0xfc,0x29,0x0,0x0,0x0,0x0,0x1,0xb,0x1,0x9a,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xe0,0xb0,0x63,0x62,0x0,0x0,0x0,0x0,0x1,0xb,0x4,0x8a,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x71,0xaa,0x20,0x60,0x0,0x0,0x0,0x0,0x1,0xb,0x0,0x5,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x50,0x9f,0x0,0x40,0x0,0x0,0x0,0x0,0x1,0xb,0x4,0xa1,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xd7,0x38,0xfc,0x29,0x0,0x0,0x0,0x0,0x0,0xa,0x2,0x24,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0xb,0x1,0xc5,0x0,0x10,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x10,0x8b,0x36,0x70,0x0,0x0,0x0,0x0,
\x01\x0b\x12\x01\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\xcaOM_\x00\x00\x00\x00\x01\x0b\x04\x01\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00G\xf0\xc8X\x00\x00\x00\x00\x01\x0b\x04\xa1\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\xd78\xfc)\x00\x00\x00\x00\x01\x0b\x01\x9a\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\xe0\xb0cb\x00\x00\x00\x00\x01\x0b\x04\x8a\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00q\xaa `\x00\x00\x00\x00\x01\x0b\x00\x05\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00P\x9f\x00@\x00\x00\x00\x00\x01\x0b\x04\xa1\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\xd78\xfc)\x00\x00\x00\x00\x00\x0a\x02$\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\x01\x0b\x01\xc5\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\x10\x8b6p\x00\x00\x00\x00