Description
Heap Buffer overflows in objc_build_refs
I have discovered two heap buffer
overflows while parsing mach-o executables.
Please refer bellow for further information.
Environment
shad3@ubuntu:~/Desktop/$ uname -ms
Linux x86_64
shad3@ubuntu:~/Desktop/$ r2 -v
radare2 5.5.2 27243 @ linux-x86-64 git.5.5.0
commit: 79effabdf5db431e40ea2aafc7f322ca32edb876 build: 2021-12-07__12:18:24
shad3@ubuntu:~/Desktop/$ date
Tue Dec 7 14:07:20 PST 2021ASAN
Stack Trace from an ASAN build while triggering the firs bug
=================================================================
==91945==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6250004cb6a8 at pc 0x7f29c4016d1a bp 0x7ffe0c8bf8b0 sp 0x7ffe0c8bf058
WRITE of size 9896288 at 0x6250004cb6a8 thread T0
#0 0x7f29c4016d19 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19)
#1 0x7f29c08c3157 in r_io_vread_at /home/shad3/Desktop/radare2/libr/io/io.c:203
#2 0x7f29c08c33ec in internal_r_io_read_at /home/shad3/Desktop/radare2/libr/io/io.c:226
#3 0x7f29c08c36b6 in r_io_read_at /home/shad3/Desktop/radare2/libr/io/io.c:264
#4 0x7f29b99bf27b in objc_build_refs /home/shad3/Desktop/radare2/libr/core/anal_objc.c:150
#5 0x7f29b99c0143 in objc_find_refs /home/shad3/Desktop/radare2/libr/core/anal_objc.c:231
#6 0x7f29b99c14b5 in cmd_anal_objc /home/shad3/Desktop/radare2/libr/core/anal_objc.c:329
#7 0x7f29b95fa8f0 in cmd_anal_all /home/shad3/Desktop/radare2/libr/core/cmd_anal.c:10595
#8 0x7f29b9603d85 in cmd_anal /home/shad3/Desktop/radare2/libr/core/cmd_anal.c:11639
#9 0x7f29b9828c92 in r_cmd_call /home/shad3/Desktop/radare2/libr/core/cmd_api.c:537
#10 0x7f29b96fbea3 in r_core_cmd_subst_i /home/shad3/Desktop/radare2/libr/core/cmd.c:4392
#11 0x7f29b96ef27b in r_core_cmd_subst /home/shad3/Desktop/radare2/libr/core/cmd.c:3279
#12 0x7f29b9705da6 in run_cmd_depth /home/shad3/Desktop/radare2/libr/core/cmd.c:5279
#13 0x7f29b9706add in r_core_cmd /home/shad3/Desktop/radare2/libr/core/cmd.c:5362
#14 0x7f29b9707883 in r_core_cmd0 /home/shad3/Desktop/radare2/libr/core/cmd.c:5519
#15 0x7f29c3151748 in r_main_radare2 /home/shad3/Desktop/radare2/libr/main/radare2.c:1390
#16 0x560128934b4e in main /home/shad3/Desktop/radare2/binr/radare2/radare2.c:96
#17 0x7f29c1fc8bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
#18 0x560128934579 in _start (/home/shad3/Desktop/radare2/binr/radare2/radare2+0x1579)
0x6250004cb6a8 is located 0 bytes to the right of 9640-byte region [0x6250004c9100,0x6250004cb6a8)
allocated by thread T0 here:
#0 0x7f29c4096d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28)
#1 0x7f29b99bf0a6 in objc_build_refs /home/shad3/Desktop/radare2/libr/core/anal_objc.c:145
#2 0x7f29b99c0143 in objc_find_refs /home/shad3/Desktop/radare2/libr/core/anal_objc.c:231
#3 0x7f29b99c14b5 in cmd_anal_objc /home/shad3/Desktop/radare2/libr/core/anal_objc.c:329
#4 0x7f29b95fa8f0 in cmd_anal_all /home/shad3/Desktop/radare2/libr/core/cmd_anal.c:10595
#5 0x7f29b9603d85 in cmd_anal /home/shad3/Desktop/radare2/libr/core/cmd_anal.c:11639
#6 0x7f29b9828c92 in r_cmd_call /home/shad3/Desktop/radare2/libr/core/cmd_api.c:537
#7 0x7f29b96fbea3 in r_core_cmd_subst_i /home/shad3/Desktop/radare2/libr/core/cmd.c:4392
#8 0x7f29b96ef27b in r_core_cmd_subst /home/shad3/Desktop/radare2/libr/core/cmd.c:3279
#9 0x7f29b9705da6 in run_cmd_depth /home/shad3/Desktop/radare2/libr/core/cmd.c:5279
#10 0x7f29b9706add in r_core_cmd /home/shad3/Desktop/radare2/libr/core/cmd.c:5362
#11 0x7f29b9707883 in r_core_cmd0 /home/shad3/Desktop/radare2/libr/core/cmd.c:5519
#12 0x7f29c3151748 in r_main_radare2 /home/shad3/Desktop/radare2/libr/main/radare2.c:1390
#13 0x560128934b4e in main /home/shad3/Desktop/radare2/binr/radare2/radare2.c:96
#14 0x7f29c1fc8bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19)
Shadow bytes around the buggy address:
0x0c4a80091680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c4a80091690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c4a800916a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c4a800916b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c4a800916c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c4a800916d0: 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa fa
0x0c4a800916e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c4a800916f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c4a80091700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c4a80091710: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c4a80091720: 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
==91945==ABORTING
Explanation of the vulnerabilities
The vulnerability lies in the objc_build_refs function that
is responsible of building the references of a mach-o file as its name
suggests.
The function can be found out at:
/radare2/libr/core/anal_objc.c
Please consider the following code
bellow which has been simplified for readability:
static bool objc_build_refs(RCoreObjc *objc) {
...
size_t ss_selrefs = objc->_selrefs->vsize;
size_t maxsize = R_MAX (ss_const, ss_selrefs); // 1a
maxsize = R_MIN (maxsize, objc->file_size); // 1b
ut8 *buf = calloc (1, maxsize); // 2
if (!buf) {
return false;
}
...
if (!r_io_read_at (objc->core->io, va_selrefs, buf, ss_selrefs)) { // 3
eprintf ("aao: Cannot read the whole selrefs section\n");
return false;
}
...
free (buf);
return true;
}At points 1a and 1b theres an attempt to sanitize the ss_selrefs
variable as it has to be done. Based on the return value of the two macros
which is stored in the maxsize variable* an internal buffer of the function
is allocated, here called buf. At point 3 there's a read operation perfomed
to the buffer based on the unsanitized ss_selfrefs variable instead of the
maxsize one. In case where the ss_selrefs is greater than the maxsize
variable this read operation results in a heap buffer overflow.
The same vulnerability exists on the other read operation performed in the same function.
Which also results in a heap buffer overflow.
size_t ss_const = objc->_const->vsize;
....
if (!r_io_read_at (objc->core->io, objc->_const->vaddr, buf, ss_const)) {
eprintf ("aao: Cannot read the whole const section %zu\n", ss_const);
return false;
}
PS: maxsize seems like an obscure name for that variable, it might
be better to consider changing that, unless there's a specific reason.
Proposed fixes
The r_io_read_at functions to be to be called with the variable
maxsize instead of the ss_selrefs and ss_const as an argument.
Notes
-
Please check the attached binary that crashes
the radare2 binary and reproduces the first vulnerability
by running the following command e.g. in an ASAN build
r2 -qq -AA crash -
I would highly appreciate if these bugs qualify for
CVEs to request them for me.