When compiling gdb with '-lasan -fsanitizer=address' and running tests with:
- export ASAN_OPTIONS="detect_leaks=0:alloc_dealloc_mismatch=0", and
- a target board using local-board.exp, which sets sysroot to ""
we run into a heap-buffer-overflow in child_path for f.i. gdb.arch/amd64-byte:
...
==3997==ERROR: AddressSanitizer: heap-buffer-overflow on address \
0x60200002abcf at pc 0x5602acdf6872 bp 0x7ffe5237a090 sp 0x7ffe5237a080
READ of size 1 at 0x60200002abcf thread T0
#0 0x5602acdf6871 in child_path(char const*, char const*) \
gdb/common/pathstuff.c:161
#1 0x5602adb06587 in find_separate_debug_file gdb/symfile.c:1483
#2 0x5602adb06f2f in find_separate_debug_file_by_debuglink[abi:cxx11](...) \
gdb/symfile.c:1563
#3 0x5602ad13b743 in elf_symfile_read gdb/elfread.c:1293
#4 0x5602adb01cfa in read_symbols gdb/symfile.c:798
#5 0x5602adb03769 in syms_from_objfile_1 gdb/symfile.c:1000
#6 0x5602adb039d0 in syms_from_objfile gdb/symfile.c:1017
#7 0x5602adb04551 in symbol_file_add_with_addrs gdb/symfile.c:1124
#8 0x5602adb04ebf in symbol_file_add_from_bfd(...) gdb/symfile.c:1204
#9 0x5602ada5a78d in solib_read_symbols(...) gdb/solib.c:695
#10 0x5602ada5bdae in solib_add(char const*, int, int) gdb/solib.c:1004
#11 0x5602ada49bcd in enable_break gdb/solib-svr4.c:2394
#12 0x5602ada4dae9 in svr4_solib_create_inferior_hook gdb/solib-svr4.c:3028
#13 0x5602ada5d4f1 in solib_create_inferior_hook(int) gdb/solib.c:1215
#14 0x5602ad347f66 in post_create_inferior(target_ops*, int) \
gdb/infcmd.c:467
#15 0x5602ad348b3c in run_command_1 gdb/infcmd.c:663
#16 0x5602ad348e55 in run_command gdb/infcmd.c:686
#17 0x5602acd7d32b in do_const_cfunc gdb/cli/cli-decode.c:106
#18 0x5602acd84bfe in cmd_func(cmd_list_element*, char const*, int) \
gdb/cli/cli-decode.c:1892
#19 0x5602adc62a90 in execute_command(char const*, int) gdb/top.c:630
#20 0x5602ad5053e6 in catch_command_errors gdb/main.c:372
#21 0x5602ad507eb1 in captured_main_1 gdb/main.c:1138
#22 0x5602ad5081ec in captured_main gdb/main.c:1163
#23 0x5602ad508281 in gdb_main(captured_main_args*) gdb/main.c:1188
#24 0x5602ac9ddc3a in main gdb/gdb.c:32
#25 0x7f582b56eb96 in __libc_start_main \
(/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#26 0x5602ac9dda09 in _start \
(/home/smarchi/build/binutils-gdb/gdb/gdb+0x19a2a09)
0x60200002abcf is located 1 bytes to the left of 1-byte region \
[0x60200002abd0,0x60200002abd1)
allocated by thread T0 here:
#0 0x7f582e0e4b50 in __interceptor_malloc \
(/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
#1 0x5602acdd3656 in xmalloc gdb/common/common-utils.c:44
#2 0x5602aefe17d1 in xstrdup libiberty/xstrdup.c:34
#3 0x5602acdf61f6 in gdb_realpath(char const*) gdb/common/pathstuff.c:80
#4 0x5602adb06278 in find_separate_debug_file gdb/symfile.c:1444
#5 0x5602adb06f2f in find_separate_debug_file_by_debuglink[abi:cxx11](...) \
gdb/symfile.c:1563
#6 0x5602ad13b743 in elf_symfile_read gdb/elfread.c:1293
#7 0x5602adb01cfa in read_symbols gdb/symfile.c:798
#8 0x5602adb03769 in syms_from_objfile_1 gdb/symfile.c:1000
#9 0x5602adb039d0 in syms_from_objfile gdb/symfile.c:1017
#10 0x5602adb04551 in symbol_file_add_with_addrs gdb/symfile.c:1124
#11 0x5602adb04ebf in symbol_file_add_from_bfd(...) gdb/solib.c:695
#13 0x5602ada5bdae in solib_add(char const*, int, int) gdb/solib.c:1004
#14 0x5602ada49bcd in enable_break gdb/solib-svr4.c:2394
#15 0x5602ada4dae9 in svr4_solib_create_inferior_hook gdb/solib-svr4.c:3028
#16 0x5602ada5d4f1 in solib_create_inferior_hook(int) gdb/solib.c:1215
#17 0x5602ad347f66 in post_create_inferior(target_ops*, int) \
gdb/infcmd.c:467
#18 0x5602ad348b3c in run_command_1 gdb/infcmd.c:663
#19 0x5602ad348e55 in run_command gdb/infcmd.c:686
#20 0x5602acd7d32b in do_const_cfunc gdb/cli/cli-decode.c:106
#21 0x5602acd84bfe in cmd_func(cmd_list_element*, char const*, int) \
gdb/cli/cli-decode.c:1892
#22 0x5602adc62a90 in execute_command(char const*, int) gdb/top.c:630
#23 0x5602ad5053e6 in catch_command_errors gdb/main.c:372
#24 0x5602ad507eb1 in captured_main_1 gdb/main.c:1138
#25 0x5602ad5081ec in captured_main gdb/main.c:1163
#26 0x5602ad508281 in gdb_main(captured_main_args*) gdb/main.c:1188
#27 0x5602ac9ddc3a in main gdb/gdb.c:32
#28 0x7f582b56eb96 in __libc_start_main \
(/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
SUMMARY: AddressSanitizer: heap-buffer-overflow gdb/common/pathstuff.c:161 \
in child_path(char const*, char const*)
Shadow bytes around the buggy address:
0x0c047fffd520: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fa
0x0c047fffd530: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fffd540: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fffd550: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
0x0c047fffd560: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 00 00
=>0x0c047fffd570: fa fa 07 fa fa fa 00 fa fa[fa]01 fa fa fa fa fa
0x0c047fffd580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffd590: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffd5a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffd5b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fffd5c0: 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
==3997==ABORTING
...
The direct cause is that child_path gets called with parent == "", so this
test:
...
if (IS_DIR_SEPARATOR (parent[parent_len - 1]))
...
accesses parent[-1].
[ There is an open discussion (1) about whether an empty sysroot should indeed
be represented internally as "". But this patch focuses on fixing the
heap-buffer-overflow without any redesign. ]
Fix this by guarding the test with 'parent_len > 0'.
Note that the fix makes child_path behave the same for:
- parent == "/" && child == "/foo" (returns "foo")
- parent == "" and child == "/foo" (returns "foo").
Build and reg-tested on x86_64-linux.
(1) https://sourceware.org/ml/gdb-patches/2019-05/msg00193.html
gdb/ChangeLog:
2019-06-17 Tom de Vries <tdevries@suse.de>
PR gdb/24617
* common/pathstuff.c (child_path): Make sure parent_len > 0 before
accessing parent[parent_len - 1].
+2019-06-17 Tom de Vries <tdevries@suse.de>
+
+ PR gdb/24617
+ * common/pathstuff.c (child_path): Make sure parent_len > 0 before
+ accessing parent[parent_len - 1].
+
2019-06-17 Paul Pluzhnikov <ppluzhnikov@google.com>
PR gdb/24364
/* The parent path must be a directory and the child must contain at
least one component underneath the parent. */
const char *child_component;
- if (IS_DIR_SEPARATOR (parent[parent_len - 1]))
+ if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1]))
{
/* The parent path ends in a directory separator, so it is a
directory. The first child component starts after the common