OOB access in `plist_from_memory`
oliverchang opened this issue ยท 3 comments
oliverchang commented
This was found using this fuzz target:
#include <plist/plist.h>
#include <stdio.h>
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size)
{
plist_t root_node = NULL;
plist_format_t format;
plist_from_memory(reinterpret_cast<const char*>(data), size, &root_node, reinterpret_cast<plist_format_t*>(&format));
plist_free(root_node);
return 0;
}
If we pass an input containing a single whitespace character, we get the following crash.
$ echo > input
$ ./fuzzer input
=================================================================
==1593913==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000031 at pc 0x55edd8892a82 bp 0x7ffd5a7d7010 sp 0x7ffd5a7d7008
READ of size 1 at 0x602000000031 thread T0
#0 0x55edd8892a81 in plist_from_memory /usr/local/google/home/ochang/libplist/src/plist.c:225:13
#1 0x55edd88925a3 in LLVMFuzzerTestOneInput (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x1305a3) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#2 0x55edd87b8463 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x56463) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#3 0x55edd87a14ef in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x3f4ef) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#4 0x55edd87a7376 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x45376) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#5 0x55edd87d2302 in main (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x70302) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#6 0x7fb7385666c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#7 0x7fb738566784 in __libc_start_main csu/../csu/libc-start.c:360:3
#8 0x55edd879b990 in _start (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x39990) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
0x602000000031 is located 0 bytes to the right of 1-byte region [0x602000000030,0x602000000031)
allocated by thread T0 here:
#0 0x55edd888ff4d in operator new[](unsigned long) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x12df4d) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#1 0x55edd87b8372 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x56372) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#2 0x55edd87a14ef in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x3f4ef) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#3 0x55edd87a7376 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x45376) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#4 0x55edd87d2302 in main (/usr/local/google/home/ochang/libplist/fuzz/a.out+0x70302) (BuildId: c693d0b93035822c68e876f752fea4035ceaa1ed)
#5 0x7fb7385666c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/local/google/home/ochang/libplist/src/plist.c:225:13 in plist_from_memory
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 01 fa fa fa[01]fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: 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
==1593913==ABORTING
The root cause looks like there's some bounds checking that needs to happen after whitespace characters are skipped here:
Line 224 in c46afc8
nikias commented
Thanks for reporting. I was about to say, interesting that clusterfuzz didn't catch that one yet, but plist_from_memory isn't part of the harness.
oliverchang commented
Thanks for the response!
And heh, this is an auto-generated target we got as part of https://security.googleblog.com/2023/08/ai-powered-fuzzing-breaking-bug-hunting.html. We're hoping to roll this out more broadly next year for all OSS-Fuzz projects.