binutils-gdb/gdb/common
Tom de Vries 310b3441a0 [gdb] Fix heap-buffer-overflow in child_path
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 22:25:06 +02:00
..
agent.c
agent.h
array-view.h
ax.def
break-common.h
btrace-common.c
btrace-common.h
buffer.c
buffer.h
byte-vector.h
cleanups.c
cleanups.h
common-debug.c
common-debug.h
common-defs.h Move gnulib to top level 2019-06-14 12:40:02 -06:00
common-exceptions.c Make exception handling more efficient 2019-04-25 12:59:35 -06:00
common-exceptions.h Make exception handling more efficient 2019-04-25 12:59:35 -06:00
common-gdbthread.h
common-inferior.h
common-regcache.c
common-regcache.h
common-types.h
common-utils.c Move gdb's xmalloc and friends to new file 2019-06-11 07:41:00 -06:00
common-utils.h
common.host
common.m4
create-version.sh
def-vector.h
default-init-alloc.h
enum-flags.h
environ.c
environ.h
errors.c
errors.h
fileio.c
fileio.h
filestuff.c Introduce and use make_unique_xstrdup 2019-06-04 22:48:32 +01:00
filestuff.h
filtered-iterator.h
format.c
format.h
forward-scope-exit.h
function-view.h
gdb_assert.h
gdb_locale.h
gdb_optional.h
gdb_proc_service.h
gdb_ref_ptr.h
gdb_setjmp.h
gdb_signals.h
gdb_splay_tree.h
gdb_string_view.h
gdb_string_view.tcc
gdb_sys_time.h
gdb_tilde_expand.c Introduce and use make_unique_xstrdup 2019-06-04 22:48:32 +01:00
gdb_tilde_expand.h
gdb_unique_ptr.h Introduce and use make_unique_xstrdup 2019-06-04 22:48:32 +01:00
gdb_unlinker.h
gdb_vecs.c
gdb_vecs.h
gdb_wait.h
hash_enum.h
host-defs.h
job-control.c
job-control.h
mingw-strerror.c
netstuff.c On MS-Windows, define _WIN32_WINNT in a single common place. 2019-05-03 10:55:33 +03:00
netstuff.h
new-op.c Make exception handling more efficient 2019-04-25 12:59:35 -06:00
next-iterator.h
observable.h
offset-type.h
pathstuff.c [gdb] Fix heap-buffer-overflow in child_path 2019-06-17 22:25:06 +02:00
pathstuff.h
poison.h
posix-strerror.c
preprocessor.h
print-utils.c
print-utils.h
ptid.c
ptid.h
refcounted-object.h
rsp-low.c
rsp-low.h
run-time-clock.c
run-time-clock.h
safe-iterator.h
scope-exit.h
scoped_fd.h
scoped_mmap.c Fix scoped_mmap includes 2019-05-06 21:00:52 -06:00
scoped_mmap.h Fix scoped_mmap includes 2019-05-06 21:00:52 -06:00
scoped_restore.h
selftest.c Rename gdb exception types 2019-04-08 09:05:40 -06:00
selftest.h
signals-state-save-restore.c
signals-state-save-restore.h
signals.c
symbol.h
tdesc.c AArch64: Add half float view to V registers 2019-05-14 10:10:56 +01:00
tdesc.h AArch64: Add half float view to V registers 2019-05-14 10:10:56 +01:00
traits.h
underlying.h
valid-expr.h
vec.c
vec.h
version.h
x86-xstate.h
xml-utils.c
xml-utils.h