Fuzzing libVLC - De-multiplexer
So, I have been working on writing a fuzz target for the demux API for the past two weeks and I have reached a point where it has a good code coverage and has already found some few shallow bugs.
Here are some of the stacktraces libfuzzer spit out and all of them were fixed rather promptly.
A Segfault on a null pointer, fixed by adding a null check
==25241==ERROR: AddressSanitizer: SEGV on unknown address 0xffffffffffffff68 (pc 0x7f56c19e8ab0 bp 0xffffffffffffff58 sp 0x7ffcdfe59e58 T0)
==25241==The signal is caused by a READ memory access.
#0 0x7f56c19e8aaf (/usr/lib/libpthread.so.0+0x9aaf)
#1 0x7f56c275c5e1 in Lookup misc/variables.c:158
#2 0x7f56c275c5e1 in AddCallback misc/variables.c:839
#3 0x7f56c275c5e1 in var_AddCallback misc/variables.c:884
#4 0x7f56b336a55e in blurayOpen access/bluray.c:674
#5 0x7f56c26df59d in module_load modules/modules.c:183
#6 0x7f56c26dfb43 in vlc_module_load modules/modules.c:275
#7 0x7f56c2704dec in demux_NewAdvanced input/demux.c:259
#8 0x7f56c2705236 in demux_New input/demux.c:151
#9 0x40575b in LLVMFuzzerTestOneInput /home/shalzz/builds/vlc/test/fuzz/libvlc_demux_fuzzer.cpp:73
#10 0x416714 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:458
#11 0x416983 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) FuzzerLoop.cpp:397
#12 0x41714d in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:596
#13 0x417397 in fuzzer::Fuzzer::Loop() FuzzerLoop.cpp:624
#14 0x410438 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:744
#15 0x405c40 in main FuzzerMain.cpp:20
#16 0x7f56c0089439 in __libc_start_main (/usr/lib/libc.so.6+0x20439)
#17 0x404ee9 in _start (/home/shalzz/builds/vlc/test/fuzz/.libs/lt-libvlc_demux_fuzzer+0x404ee9)
Abort due to character conversion without a conversion descriptor, fixed.
==32703== ERROR: libFuzzer: deadly signal
#0 0x7f46cd57fb68 in __sanitizer_print_stack_trace /build/gcc-multilib/src/gcc/libsanitizer/asan/asan_stack.cc:36
#1 0x468961 in fuzzer::Fuzzer::CrashCallback() FuzzerLoop.cpp:195
#2 0x46892d in fuzzer::Fuzzer::StaticCrashSignalCallback() FuzzerLoop.cpp:179
#3 0x7f46cc83993f (/usr/lib/libpthread.so.0+0x1193f)
#4 0x7f46cbf8d66f in raise (/usr/lib/libc.so.6+0x3366f)
#5 0x7f46cbf8ecff in __GI_abort (/usr/lib/libc.so.6+0x34cff)
#6 0x7f46cce9996f in vlc_iconv extras/libc.c:391
#7 0x7f46ccf3e083 in vlc_stream_ReadLine input/stream.c:321
#8 0x7f4690b96342 in peek_Readline demux/subtitle_helper.h:38
#9 0x7f4690b96b02 in Open demux/vobsub.c:128
#10 0x7f46cce9b2dc in generic_start modules/modules.c:356
#11 0x7f46cce9a508 in module_load modules/modules.c:183
#12 0x7f46cce9abd6 in vlc_module_load modules/modules.c:279
#13 0x7f46cce9b42d in module_need modules/modules.c:371
#14 0x7f46cceef2bd in demux_NewAdvanced input/demux.c:259
#15 0x7f46cceeeadd in demux_New input/demux.c:151
#16 0x458a46 in LLVMFuzzerTestOneInput (/home/shalzz/builds/vlc-clean/test/fuzz/libvlc_demux_fuzzer+0x458a46)
#17 0x469754 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:458
#18 0x4699c3 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) FuzzerLoop.cpp:397
#19 0x45f421 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) FuzzerDriver.cpp:268
#20 0x463034 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:683
#21 0x458c80 in main FuzzerMain.cpp:20
#22 0x7f46cbf7a439 in __libc_start_main (/usr/lib/libc.so.6+0x20439)
#23 0x458239 in _start (/home/shalzz/builds/vlc-clean/test/fuzz/libvlc_demux_fuzzer+0x458239)
A heap-use-after-free, fixed by this and this.
==26135==ERROR: AddressSanitizer: heap-use-after-free on address 0x613000005a00 at pc 0x7f4549af4c64 bp 0x7ffcb951f110 sp 0x7ffcb951e8b8
READ of size 4 at 0x613000005a00 thread T0
#0 0x7f4549af4c63 in __interceptor_memcmp /build/gcc-multilib/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:626
#1 0x7f453871981c in Open demux/image.c:640
#2 0x7f4548ffdb26 in generic_start modules/modules.c:356
#3 0x7f4548ffca56 in module_load modules/modules.c:183
#4 0x7f4548ffd2e5 in vlc_module_load modules/modules.c:279
#5 0x7f4548ffdc77 in module_need modules/modules.c:371
#6 0x7f4549076c84 in demux_NewAdvanced input/demux.c:259
#7 0x7f4549075fc2 in demux_New input/demux.c:151
#8 0x405ce5 in LLVMFuzzerTestOneInput /home/shalzz/builds/vlc/test/fuzz/libvlc_demux_fuzzer.cpp:68
#9 0x4169d4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:458
#10 0x416c43 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) FuzzerLoop.cpp:397
#11 0x41740d in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:596
#12 0x417657 in fuzzer::Fuzzer::Loop() FuzzerLoop.cpp:624
#13 0x4106f8 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:744
#14 0x405f00 in main FuzzerMain.cpp:20
#15 0x7f45464b0439 in __libc_start_main (/usr/lib/libc.so.6+0x20439)
#16 0x404e49 in _start (/home/shalzz/builds/vlc/test/fuzz/.libs/lt-libvlc_demux_fuzzer+0x404e49)
0x613000005a00 is located 128 bytes inside of 380-byte region [0x613000005980,0x613000005afc)
freed by thread T0 here:
#0 0x7f4549b234c8 in __interceptor_free /build/gcc-multilib/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:45
#1 0x7f4549193fc7 in block_generic_Release misc/block.c:99
#2 0x7f4549193a3c in block_Release ../include/vlc_block.h:184
#3 0x7f4549194de2 in block_TryRealloc misc/block.c:212
#4 0x7f45490e89bb in vlc_stream_Peek input/stream.c:506
#5 0x7f4538717037 in IsPnm demux/image.c:354
#6 0x7f45387195bd in Open demux/image.c:634
#7 0x7f4548ffdb26 in generic_start modules/modules.c:356
#8 0x7f4548ffca56 in module_load modules/modules.c:183
#9 0x7f4548ffd2e5 in vlc_module_load modules/modules.c:279
#10 0x7f4548ffdc77 in module_need modules/modules.c:371
#11 0x7f4549076c84 in demux_NewAdvanced input/demux.c:259
#12 0x7f4549075fc2 in demux_New input/demux.c:151
#13 0x405ce5 in LLVMFuzzerTestOneInput /home/shalzz/builds/vlc/test/fuzz/libvlc_demux_fuzzer.cpp:68
#14 0x4169d4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:458
#15 0x416c43 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) FuzzerLoop.cpp:397
#16 0x41740d in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:596
#17 0x417657 in fuzzer::Fuzzer::Loop() FuzzerLoop.cpp:624
#18 0x4106f8 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:744
#19 0x405f00 in main FuzzerMain.cpp:20
#20 0x7f45464b0439 in __libc_start_main (/usr/lib/libc.so.6+0x20439)
previously allocated by thread T0 here:
#0 0x7f4549b23860 in __interceptor_malloc /build/gcc-multilib/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:62
#1 0x7f4549194434 in block_Alloc misc/block.c:128
#2 0x7f4549194c77 in block_TryRealloc misc/block.c:205
#3 0x7f45490e89bb in vlc_stream_Peek input/stream.c:506
#4 0x7f4539fc5e24 in DetectPVRHeadersAndHeaderSize demux/mpeg/ts.c:256
#5 0x7f4539fc6272 in Open demux/mpeg/ts.c:357
#6 0x7f4548ffdb26 in generic_start modules/modules.c:356
#7 0x7f4548ffca56 in module_load modules/modules.c:183
#8 0x7f4548ffd2e5 in vlc_module_load modules/modules.c:279
#9 0x7f4548ffdc77 in module_need modules/modules.c:371
#10 0x7f4549076c84 in demux_NewAdvanced input/demux.c:259
#11 0x7f4549075fc2 in demux_New input/demux.c:151
#12 0x405ce5 in LLVMFuzzerTestOneInput /home/shalzz/builds/vlc/test/fuzz/libvlc_demux_fuzzer.cpp:68
#13 0x4169d4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:458
#14 0x416c43 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) FuzzerLoop.cpp:397
#15 0x41740d in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:596
#16 0x417657 in fuzzer::Fuzzer::Loop() FuzzerLoop.cpp:624
#17 0x4106f8 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:744
#18 0x405f00 in main FuzzerMain.cpp:20
#19 0x7f45464b0439 in __libc_start_main (/usr/lib/libc.so.6+0x20439)
SUMMARY: AddressSanitizer: heap-use-after-free /build/gcc-multilib/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:626 in __interceptor_memcmp
Shadow bytes around the buggy address:
0x0c267fff8af0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c267fff8b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c267fff8b10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c267fff8b20: 00 00 00 00 00 fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8b30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c267fff8b40:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff8b50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c267fff8b60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8b70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8b90: 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
==26135==ABORTING
Unfortunately I cannot publish my source code yet or start integrating with oss-fuzz and cluster fuzz by Google as VideoLAN/Labs is still undecided and would rather do this privately, mostly because they don’t want to be bound by Google’s bug disclosure policy.
I think they are just confused that they have to do a software release within the specified deadline when it’s just a bug disclosure, but whatever. (There’s no longer any confusion.)
Update: You can find all my bug fixes and patches here