Out of Bound Read in g_markup_parse_context_parse()
@JsHuang
Submitted by Jin Link to original bug (#795060)
Description
Created attachment 370643 libfuzer fuzz target function and crash input
Function g_markup_parse_context_parse() can cause an out of bound read and may cause access violation error. While parsing a invalid string , g_markup_parse_context_parse() will call set_error() (gmarkup.c: line1254) fuction to print some error message, in set_error(), it calls utf8_str() to get the current parsing character. utf8_str() calls char_str() and g_utf8_get_char(), the error comes in g_utf8_get_char().
g_utf8_get_char (const gchar *p) { int i, mask = 0, len; gunichar result; unsigned char c = (unsigned char) *p;
// compute len and mask UTF8_COMPUTE (c, mask, len);
/* for an invalid input string, eg: 4 byte input 0x3c002fc9(bin), when handling the last character "c9" ,len will be 2, other invalid character, may be bigger then 2. */
if (len == -1) return (gunichar)-1; UTF8_GET (result, p, i, mask, len);
/* len is 2, and will read out of bound */
return result; }
This bug is found by ASAN. The error message is as below :
==18252==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000050294 at pc 0x7f335b6638b2 bp 0x7ffffc114660 sp 0x7ffffc114658
READ of size 1 at 0x602000050294 thread T0
#0 0x7f335b6638b1 in g_utf8_get_char /home/afl/fuzzing/glib-master/glib/gutf8.c:323:3
#1 (closed) 0x7f335b55119e in utf8_str /home/afl/fuzzing/glib-master/glib/gmarkup.c:564:13
#2 (closed) 0x7f335b55119e in g_markup_parse_context_parse /home/afl/fuzzing/glib-master/glib/gmarkup.c:1256
#3 (closed) 0x545729 in LLVMFuzzerTestOneInput /home/afl/fuzzing/glib-master/fuzzing/g_markup_parse_context_parse.cc:18:2
#4 (closed) 0x52da66 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/afl/Fuzzer/./FuzzerLoop.cpp:517:13
#5 (closed) 0x52d29b in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/afl/Fuzzer/./FuzzerLoop.cpp:442:3
#6 (closed) 0x52e9d6 in fuzzer::Fuzzer::MutateAndTestOne() /home/afl/Fuzzer/./FuzzerLoop.cpp:650:19
#7 (closed) 0x52f355 in fuzzer::Fuzzer::Loop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
>, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
> > > const&) /home/afl/Fuzzer/./FuzzerLoop.cpp:773:5
#8 (closed) 0x525180 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/afl/Fuzzer/./FuzzerDriver.cpp:754:6
#9 (closed) 0x520930 in main /home/afl/Fuzzer/./FuzzerMain.cpp:20:10
#10 (closed) 0x7f3359fea82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
#11 (closed) 0x41d248 in _start (/home/afl/fuzzing/glib-master/fuzzing/g_markup_parse_context_parse+0x41d248)
0x602000050294 is located 0 bytes to the right of 4-byte region [0x602000050290,0x602000050294)
allocated by thread T0 here:
#0 0x4e8fb8 in __interceptor_malloc (/home/afl/fuzzing/glib-master/fuzzing/g_markup_parse_context_parse+0x4e8fb8)
#1 (closed) 0x7f335af69e77 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x8de77)
#2 (closed) 0x52d29b in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/afl/Fuzzer/./FuzzerLoop.cpp:442:3
#3 (closed) 0x52e9d6 in fuzzer::Fuzzer::MutateAndTestOne() /home/afl/Fuzzer/./FuzzerLoop.cpp:650:19
#4 (closed) 0x52f355 in fuzzer::Fuzzer::Loop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
>, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
> > > const&) /home/afl/Fuzzer/./FuzzerLoop.cpp:773:5
#5 (closed) 0x525180 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/afl/Fuzzer/./FuzzerDriver.cpp:754:6
#6 (closed) 0x520930 in main /home/afl/Fuzzer/./FuzzerMain.cpp:20:10
#7 (closed) 0x7f3359fea82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/afl/fuzzing/glib-master/glib/gutf8.c:323:3 in g_utf8_get_char Shadow bytes around the buggy address: 0x0c0480002000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002010: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002020: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002030: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002040: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa =>0x0c0480002050: fa fa[04]fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c04800020a0: 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
Function g_markup_parse_context_parse() can cause an out of bound read and may cause access violation error. While parsing a invalid string , g_markup_parse_context_parse() will call set_error() (gmarkup.c: line1254) fuction to print some error message, in set_error(), it calls utf8_str() to get the current parsing character. utf8_str() calls char_str() and g_utf8_get_char(), the error comes in g_utf8_get_char().
g_utf8_get_char (const gchar *p) { int i, mask = 0, len; gunichar result; unsigned char c = (unsigned char) *p;
// compute len and mask UTF8_COMPUTE (c, mask, len);
/* for an invalid input string, eg: 4 byte input 0x3c002fc9(bin), when handling the last character "c9" ,len will be 2, other invalid character, may be bigger then 2. */
if (len == -1) return (gunichar)-1; UTF8_GET (result, p, i, mask, len);
/* len is 2, and will read out of bound */
return result; }
This bug is found by ASAN. The error message is as below :
==18252==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000050294 at pc 0x7f335b6638b2 bp 0x7ffffc114660 sp 0x7ffffc114658
READ of size 1 at 0x602000050294 thread T0
#0 0x7f335b6638b1 in g_utf8_get_char /home/afl/fuzzing/glib-master/glib/gutf8.c:323:3
#1 (closed) 0x7f335b55119e in utf8_str /home/afl/fuzzing/glib-master/glib/gmarkup.c:564:13
#2 (closed) 0x7f335b55119e in g_markup_parse_context_parse /home/afl/fuzzing/glib-master/glib/gmarkup.c:1256
#3 (closed) 0x545729 in LLVMFuzzerTestOneInput /home/afl/fuzzing/glib-master/fuzzing/g_markup_parse_context_parse.cc:18:2
#4 (closed) 0x52da66 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/afl/Fuzzer/./FuzzerLoop.cpp:517:13
#5 (closed) 0x52d29b in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/afl/Fuzzer/./FuzzerLoop.cpp:442:3
#6 (closed) 0x52e9d6 in fuzzer::Fuzzer::MutateAndTestOne() /home/afl/Fuzzer/./FuzzerLoop.cpp:650:19
#7 (closed) 0x52f355 in fuzzer::Fuzzer::Loop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
>, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
> > > const&) /home/afl/Fuzzer/./FuzzerLoop.cpp:773:5
#8 (closed) 0x525180 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/afl/Fuzzer/./FuzzerDriver.cpp:754:6
#9 (closed) 0x520930 in main /home/afl/Fuzzer/./FuzzerMain.cpp:20:10
#10 (closed) 0x7f3359fea82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
#11 (closed) 0x41d248 in _start (/home/afl/fuzzing/glib-master/fuzzing/g_markup_parse_context_parse+0x41d248)
0x602000050294 is located 0 bytes to the right of 4-byte region [0x602000050290,0x602000050294)
allocated by thread T0 here:
#0 0x4e8fb8 in __interceptor_malloc (/home/afl/fuzzing/glib-master/fuzzing/g_markup_parse_context_parse+0x4e8fb8)
#1 (closed) 0x7f335af69e77 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x8de77)
#2 (closed) 0x52d29b in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/afl/Fuzzer/./FuzzerLoop.cpp:442:3
#3 (closed) 0x52e9d6 in fuzzer::Fuzzer::MutateAndTestOne() /home/afl/Fuzzer/./FuzzerLoop.cpp:650:19
#4 (closed) 0x52f355 in fuzzer::Fuzzer::Loop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
>, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char>
> > > const&) /home/afl/Fuzzer/./FuzzerLoop.cpp:773:5
#5 (closed) 0x525180 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/afl/Fuzzer/./FuzzerDriver.cpp:754:6
#6 (closed) 0x520930 in main /home/afl/Fuzzer/./FuzzerMain.cpp:20:10
#7 (closed) 0x7f3359fea82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/afl/fuzzing/glib-master/glib/gutf8.c:323:3 in g_utf8_get_char Shadow bytes around the buggy address: 0x0c0480002000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002010: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002020: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002030: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c0480002040: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa =>0x0c0480002050: fa fa[04]fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c0480002090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c04800020a0: 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
credit:ADLab of Venustech
Attachment 370643, "libfuzer fuzz target function and crash input":
g_markup_parse_context_parse-crash
Version: 2.56.x