Heap overflow due to inadequate length check in SMC91c111 device
Explanation of the bug:
The len variable which is got from the guest, is not checked if it is very small. So if len is less than 5 the check
if (len > MAX_PACKET_SIZE)
(https://github.com/qemu/qemu/blob/ece408818d27f745ef1b05fb3cc99a1e7a5bf580/hw/net/smc91c111.c#L292) passes, and after the line
len -= 6;
(https://github.com/qemu/qemu/blob/ece408818d27f745ef1b05fb3cc99a1e7a5bf580/hw/net/smc91c111.c#L303) len becomes a very huge value.
This leads to buffer overflow in qemu_net_queue_send function as
packet = g_malloc(sizeof(NetPacket) + size);(https://github.com/qemu/qemu/blob/ece408818d27f745ef1b05fb3cc99a1e7a5bf580/net/queue.c#L105) wraps to a smaller number but
memcpy(packet->data, buf, size); (https://github.com/qemu/qemu/blob/ece408818d27f745ef1b05fb3cc99a1e7a5bf580/net/queue.c#L110) is using the very huge value.
Steps to reproduce: Prepare the guest:
git clone https://git.buildroot.net/buildroot
cd buildroot
make qemu_arm_versatile_defconfig
I enabled 9P_FS and VIRTIO to make it easy to push the driver to the guest. (refer the attached .config file )
make linux-rebuild all
On the host, compiled qemu with Asan enabled. started qemu as:
~/dump/qemu/build/qemu-system-arm -M versatilepb -m 128M -nographic \
-kernel zImage \
-dtb versatile-pb.dtb \
-drive file=rootfs.ext2,if=scsi,format=raw \
-append "root=/dev/sda console=ttyAMA0,115200" \
-fsdev local,path=$HOME/smc_driver_project,security_model=passthrough,id=host_share \
-device virtio-9p-pci,fsdev=host_share,mount_tag=host_share \
-netdev user,id=sshnet,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=sshnet \
-netdev socket,id=targetnet,listen=:12345 \
-net nic,model=smc91c111,netdev=targetnet \
-object filter-dump,id=dump0,netdev=targetnet,file=repro_trace.pcap
This line was added like this so that the qemu_net_queue_append is taken. This is just a poc!
-net nic,model=smc91c111,netdev=targetnet \
-object filter-dump,id=dump0,netdev=targetnet,file=repro_trace.pcap
Inside guest: Login as root:
mkdir -p /mnt/host
mount -t 9p -o trans=virtio,version=9p2000.L host_share /mnt/host
cd /mnt/host
insmod qemu_smc_repro.ko
Welcome to Buildroot
buildroot login: root
# mkdir -p /mnt/host
# mount -t 9p -o trans=virtio,version=9p2000.L host_share /mnt/host
# cd /mnt/host
# insmod qemu_smc_repro.ko
qemu_smc_repro: loading out-of-tree module taints kernel.
=================================================================
==528315==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5290000316c0 at pc 0x7fed4a072957 bp 0x7fecb2bf8590 sp 0x7fecb2bf7d50
READ of size 65536 at 0x5290000316c0 thread T2
#0 0x7fed4a072956 in read_iovec ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:963
#1 0x7fed4a0c5307 in writev ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1157
#2 0x55fd235c24d3 in dump_receive_iov ../net/dump.c:90
#3 0x55fd235c2e00 in filter_dump_receive_iov ../net/dump.c:158
#4 0x55fd235ca3a8 in qemu_netfilter_receive ../net/filter.c:41
#5 0x55fd235d326b in filter_receive_iov ../net/net.c:668
#6 0x55fd235d3464 in filter_receive ../net/net.c:692
#7 0x55fd235d38a1 in qemu_send_packet_async_with_flags ../net/net.c:753
#8 0x55fd235d3978 in qemu_send_packet_async ../net/net.c:768
#9 0x55fd235d39b0 in qemu_send_packet ../net/net.c:774
#10 0x55fd22fd120b in smc91c111_do_tx ../hw/net/smc91c111.c:332
#11 0x55fd22fd13dc in smc91c111_queue_tx ../hw/net/smc91c111.c:355
#12 0x55fd22fd255e in smc91c111_writeb ../hw/net/smc91c111.c:533
#13 0x55fd22fd378a in smc91c111_writefn ../hw/net/smc91c111.c:784
#14 0x55fd23472f7d in memory_region_write_accessor ../system/memory.c:491
#15 0x55fd23473617 in access_with_adjusted_size ../system/memory.c:567
#16 0x55fd2347baa2 in memory_region_dispatch_write ../system/memory.c:1547
#17 0x55fd234a5b96 in flatview_write_continue_step ../system/physmem.c:3241
#18 0x55fd234a5d8d in flatview_write_continue ../system/physmem.c:3271
#19 0x55fd234a6093 in flatview_write ../system/physmem.c:3302
#20 0x55fd234a4333 in subpage_write ../system/physmem.c:2909
#21 0x55fd234731b1 in memory_region_write_with_attrs_accessor ../system/memory.c:512
#22 0x55fd23473617 in access_with_adjusted_size ../system/memory.c:567
#23 0x55fd2347bb89 in memory_region_dispatch_write ../system/memory.c:1554
#24 0x55fd236f7999 in int_st_mmio_leN ../accel/tcg/cputlb.c:2465
#25 0x55fd236f7c76 in do_st_mmio_leN ../accel/tcg/cputlb.c:2498
#26 0x55fd236f8b60 in do_st_1 ../accel/tcg/cputlb.c:2626
#27 0x55fd236f938f in do_st1_mmu ../accel/tcg/cputlb.c:2701
#28 0x55fd236fafc6 in helper_stb_mmu ../accel/tcg/ldst_common.c.inc:86
#29 0x7fecbd4c0229 (/memfd:tcg-jit (deleted)+0x24d5229)
0x5290000316c0 is located 0 bytes after 17600-byte region [0x52900002d200,0x5290000316c0)
allocated by thread T0 here:
#0 0x7fed4a0f4c57 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7fed48c19701 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x65701) (BuildId: 0238e5480cfba00d18623750cdd44b19a753f7ad)
#2 0x55fd23cafb16 in object_new ../qom/object.c:789
#3 0x55fd23ca2349 in qdev_new ../hw/core/qdev.c:149
#4 0x55fd22fd431d in smc91c111_init ../hw/net/smc91c111.c:945
#5 0x55fd239b72a6 in versatile_init ../hw/arm/versatilepb.c:269
#6 0x55fd239b7de2 in vpb_init ../hw/arm/versatilepb.c:408
#7 0x55fd22c91bb6 in machine_run_board_init ../hw/core/machine.c:1732
#8 0x55fd234504e1 in qemu_init_board ../system/vl.c:2715
#9 0x55fd23450cc9 in qmp_x_exit_preconfig ../system/vl.c:2809
#10 0x55fd23455c40 in qemu_init ../system/vl.c:3849
#11 0x55fd23fd6eb9 in main ../system/main.c:71
#12 0x7fed45d95ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: fce446c9d4ad48e2b0c90cce1a11722897805281)
Thread T2 created by T0 here:
#0 0x7fed4a0ecae1 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:245
#1 0x55fd2417ea2b in qemu_thread_create ../util/qemu-thread-posix.c:433
#2 0x55fd237144fe in mttcg_start_vcpu_thread ../accel/tcg/tcg-accel-ops-mttcg.c:135
#3 0x55fd2345c1ae in qemu_init_vcpu ../system/cpus.c:726
#4 0x55fd23872b5a in arm_cpu_realizefn ../target/arm/cpu.c:2210
#5 0x55fd23ca3f00 in device_set_realized ../hw/core/qdev.c:523
#6 0x55fd23cb7ca8 in property_set_bool ../qom/object.c:2376
#7 0x55fd23cb2fd9 in object_property_set ../qom/object.c:1450
#8 0x55fd23cbd2a2 in object_property_set_qobject ../qom/qom-qobject.c:28
#9 0x55fd23cb355b in object_property_set_bool ../qom/object.c:1520
#10 0x55fd23ca2d3d in qdev_realize ../hw/core/qdev.c:276
#11 0x55fd239b6cc1 in versatile_init ../hw/arm/versatilepb.c:222
#12 0x55fd239b7de2 in vpb_init ../hw/arm/versatilepb.c:408
#13 0x55fd22c91bb6 in machine_run_board_init ../hw/core/machine.c:1732
#14 0x55fd234504e1 in qemu_init_board ../system/vl.c:2715
#15 0x55fd23450cc9 in qmp_x_exit_preconfig ../system/vl.c:2809
#16 0x55fd23455c40 in qemu_init ../system/vl.c:3849
#17 0x55fd23fd6eb9 in main ../system/main.c:71
#18 0x7fed45d95ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: fce446c9d4ad48e2b0c90cce1a11722897805281)
SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:963 in read_iovec
Shadow bytes around the buggy address:
0x529000031400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x529000031480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x529000031500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x529000031580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x529000031600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x529000031680: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
0x529000031700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x529000031780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x529000031800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x529000031880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x529000031900: 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[exploit.zip](/uploads/3e7d4c46d522fd7ad94d7e775cdcd877/exploit.zip)
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzon
-Vinod