Hi, I discovered a heap out of bounds read, visible with address sanitizer (also with valgrind).
To reproduce: * Build bash with address sanitizer: ./configure CFLAGS="-fsanitize=address -g" CXX="-fsanitize=addres -g" LDFLAGS="-fsanitize=address" --without-bash-malloc * Run bash: ./bash * Type & and [tab] This will cause an out of bounds read in the function check_redir. Full asan report is below. The problem is this line: prev_char = rl_line_buffer[ti - 1]; if ti is 0 then this is an invalid memory read. I've attached a patch to workaround the issue (not sure if you like the style, it's using the ? operator to check for ti>0 and assigns a zero byte to prev_char if it's 0.). ----------------- ==9564==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61100000887f at pc 0x510510 bp 0x7ffdff70c940 sp 0x7ffdff70c938 READ of size 1 at 0x61100000887f thread T0 #0 0x51050f in check_redir /mnt/ram/bash-4.4-rc1/bashline.c:1284 #1 0x5114e8 in attempt_shell_completion /mnt/ram/bash-4.4-rc1/bashline.c:1478 #2 0x5d2ea4 in gen_completion_matches /mnt/ram/bash-4.4-rc1/lib/readline/complete.c:1231 #3 0x5d7455 in rl_complete_internal /mnt/ram/bash-4.4-rc1/lib/readline/complete.c:2045 #4 0x5d0084 in rl_complete /mnt/ram/bash-4.4-rc1/lib/readline/complete.c:439 #5 0x5bdc82 in _rl_dispatch_subseq /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:859 #6 0x5bd855 in _rl_dispatch /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:802 #7 0x5bd051 in readline_internal_char /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:629 #8 0x5bd0e1 in readline_internal_charloop /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:656 #9 0x5bd10a in readline_internal /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:670 #10 0x5bc71f in readline /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:376 #11 0x42f07d in yy_readline_get /usr/homes/chet/src/bash/src/parse.y:1454 #12 0x42ef29 in yy_getc /usr/homes/chet/src/bash/src/parse.y:1388 #13 0x43125b in shell_getc /usr/homes/chet/src/bash/src/parse.y:2290 #14 0x433c64 in read_token /usr/homes/chet/src/bash/src/parse.y:3105 #15 0x432790 in yylex /usr/homes/chet/src/bash/src/parse.y:2666 #16 0x4276db in yyparse /mnt/ram/bash-4.4-rc1/y.tab.c:1832 #17 0x426741 in parse_command /mnt/ram/bash-4.4-rc1/eval.c:258 #18 0x426982 in read_command /mnt/ram/bash-4.4-rc1/eval.c:302 #19 0x425e01 in reader_loop /mnt/ram/bash-4.4-rc1/eval.c:149 #20 0x420f29 in main /mnt/ram/bash-4.4-rc1/shell.c:769 #21 0x7f640864978f in __libc_start_main (/lib64/libc.so.6+0x2078f) #22 0x41fc68 in _start (/mnt/ram/bash-4.4-rc1/bash+0x41fc68) 0x61100000887f is located 1 bytes to the left of 256-byte region [0x611000008880,0x611000008980) allocated by thread T0 here: #0 0x7f6408e789af in malloc (/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/libasan.so.1+0x549af) #1 0x533846 in xmalloc /mnt/ram/bash-4.4-rc1/xmalloc.c:112 #2 0x5beb35 in readline_initialize_everything /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:1194 #3 0x5be9e6 in rl_initialize /mnt/ram/bash-4.4-rc1/lib/readline/readline.c:1101 #4 0x50bcbb in initialize_readline /mnt/ram/bash-4.4-rc1/bashline.c:482 #5 0x42efa6 in yy_readline_get /usr/homes/chet/src/bash/src/parse.y:1440 #6 0x42ef29 in yy_getc /usr/homes/chet/src/bash/src/parse.y:1388 #7 0x43125b in shell_getc /usr/homes/chet/src/bash/src/parse.y:2290 #8 0x433c64 in read_token /usr/homes/chet/src/bash/src/parse.y:3105 #9 0x432790 in yylex /usr/homes/chet/src/bash/src/parse.y:2666 #10 0x4276db in yyparse /mnt/ram/bash-4.4-rc1/y.tab.c:1832 #11 0x426741 in parse_command /mnt/ram/bash-4.4-rc1/eval.c:258 #12 0x426982 in read_command /mnt/ram/bash-4.4-rc1/eval.c:302 #13 0x425e01 in reader_loop /mnt/ram/bash-4.4-rc1/eval.c:149 #14 0x420f29 in main /mnt/ram/bash-4.4-rc1/shell.c:769 #15 0x7f640864978f in __libc_start_main (/lib64/libc.so.6+0x2078f) SUMMARY: AddressSanitizer: heap-buffer-overflow /mnt/ram/bash-4.4-rc1/bashline.c:1284 check_redir Shadow bytes around the buggy address: 0x0c227fff90b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c227fff90c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c227fff90d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c227fff90e0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c227fff90f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c227fff9100: 00 00 fa fa fa fa fa fa fa fa fa fa fa fa fa[fa] 0x0c227fff9110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c227fff9120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c227fff9130: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c227fff9140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c227fff9150: 00 00 00 00 00 00 00 05 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 Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Contiguous container OOB:fc ASan internal: fe ==9564==ABORTING -- Hanno Böck https://hboeck.de/ mail/jabber: ha...@hboeck.de GPG: BBB51E42
--- bash-4.4-rc1/bashline.c 2015-12-30 14:53:23.000000000 +0100 +++ bash-4.4-rc1-1/bashline.c 2016-07-09 00:20:24.568169131 +0200 @@ -1281,7 +1281,7 @@ /* Handle the two character tokens `>&', `<&', and `>|'. We are not in a command position after one of these. */ this_char = rl_line_buffer[ti]; - prev_char = rl_line_buffer[ti - 1]; + prev_char = (ti > 0)?rl_line_buffer[ti - 1]:'\0'; if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || (this_char == '|' && prev_char == '>'))
pgp4FWblwHZxw.pgp
Description: OpenPGP digital signature