Dear Bash Maintainers, I encountered an issue in Bash and would like to report it. buggyfile.txt is attached to the email.
Steps to reproduce $ CC=clang-19 CFLAGS="-fsanitize=address -g -O0" ./configure --without-bash-malloc $ make $ cat crash1.txt | ./bash --norc --noediting -i Expected Behaviour Any error messages without asan ERROR. Actual Behaviour ==349030==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50200001a40e at pc 0x555555711a6a bp 0x7fffffffcfb0 sp 0x7fffffffcfa8 ==READ of size 1 at 0x50200001a40e thread T0 #0 0x555555711a69 in read_token_word /usr/local/src/chet/src/bash/src/parse.y:5210:12 #1 0x555555711a69 in read_token /usr/local/src/chet/src/bash/src/parse.y:3594:12 #2 0x5555556ea27f in yylex /usr/local/src/chet/src/bash/src/parse.y:2890:19 #3 0x5555556ea27f in yyparse /home/as/projects/bash/bash-SAN/bash/y.tab.c:1854:16 #4 0x55555571e3d1 in parse_comsub /usr/local/src/chet/src/bash/src/parse.y:4138:7 #5 0x55555571b5aa in parse_matched_pair /usr/local/src/chet/src/bash/src/parse.y:3943:16 #6 0x55555570664b in read_token_word /usr/local/src/chet/src/bash/src/parse.y:4935:11 #7 0x55555570664b in read_token /usr/local/src/chet/src/bash/src/parse.y:3594:12 #8 0x5555556ea27f in yylex /usr/local/src/chet/src/bash/src/parse.y:2890:19 #9 0x5555556ea27f in yyparse /home/as/projects/bash/bash-SAN/bash/y.tab.c:1854:16 #10 0x5555556e95c8 in parse_command /home/as/projects/bash/bash-SAN/bash/eval.c:348:7 #11 0x5555556e875d in read_command /home/as/projects/bash/bash-SAN/bash/eval.c:392:12 #12 0x5555556e7971 in reader_loop /home/as/projects/bash/bash-SAN/bash/eval.c:139:11 #13 0x5555556e12dc in main /home/as/projects/bash/bash-SAN/bash/shell.c:945:3 #14 0x7ffff7cac249 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #15 0x7ffff7cac304 in __libc_start_main csu/../csu/libc-start.c:360:3 #16 0x5555555fc9e0 in _start (/home/as/projects/bash/bash-SAN/bash/bash+0xa89e0) (BuildId: 3272a6f95dabaf748ee26df2befb4fa82755bd61) 0x50200001a40e is located 2 bytes before 10-byte region [0x50200001a410,0x50200001a41a) allocated by thread T0 here: #0 0x55555569bc7f in malloc (/home/as/projects/bash/bash-SAN/bash/bash+0x147c7f) (BuildId: 3272a6f95dabaf748ee26df2befb4fa82755bd61) #1 0x5555558f6b84 in xrealloc /home/as/projects/bash/bash-SAN/bash/xmalloc.c:135:47 #2 0x5555557081ad in read_token_word /usr/local/src/chet/src/bash/src/parse.y #3 0x5555557081ad in read_token /usr/local/src/chet/src/bash/src/parse.y:3594:12 #4 0x5555556ea27f in yylex /usr/local/src/chet/src/bash/src/parse.y:2890:19 #5 0x5555556ea27f in yyparse /home/as/projects/bash/bash-SAN/bash/y.tab.c:1854:16 #6 0x5555556e95c8 in parse_command /home/as/projects/bash/bash-SAN/bash/eval.c:348:7 #7 0x5555556e875d in read_command /home/as/projects/bash/bash-SAN/bash/eval.c:392:12 SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/local/src/chet/src/bash/src/parse.y:5210:12 in read_token_word Shadow bytes around the buggy address: 0x50200001a180: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd 0x50200001a200: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa 0x50200001a280: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x50200001a300: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x50200001a380: fa fa fd fd fa fa 00 04 fa fa fd fa fa fa fd fa =>0x50200001a400: fa[fa]00 02 fa fa fd fd fa fa fd fd fa fa fd fa 0x50200001a480: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fd 0x50200001a500: fa fa fd fd fa fa 00 00 fa fa fd fa fa fa fd fa 0x50200001a580: fa fa fd fa fa fa fd fd fa fa fd fd fa fa fd fd 0x50200001a600: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa 0x50200001a680: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd 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 ==349030==ABORTING Additional Notes The reason of the fault is current_delimiter(ds) incorrect macros: #define current_delimiter(ds) \ (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) Suggested Solution Add extra check in ternary operator: #define current_delimiter(ds) \ (ds.delimiter_depth && !(ds.delimiter_depth - 1 < 0) ? ds.delimiters[ds.delimiter_depth - 1] : 0) Bash Version as@astra:~/projects/bash/up/bash$ ./bashversion 5.3.0(1)-rc1 Also, the behaviour is repeating on release bash 5.2 version. System Info Linux astra 6.1.90-1-generic #astra2+ci15 SMP PREEMPT_DYNAMIC Tue Jul 23 09:49:19 MSK 2024 x86_64 GNU/Linux Debian clang version 19.1.1 (++20241001124028+d401987fe349-1~exp1~20241001124040.50) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/lib/llvm-19/bin Attached file you can download from https://dropmefiles.com/6aIL2. Or just see attaches to the message.
ÿ a[]=Âtaaa# This program is free software: you can redis ibute it and/or modify # under the terms of the GNU General Public License as published e readonly ref by # the Frere Foundation, either version 3 of the License, or # (at yoÂr option) any later version. # # This program is distributed in the hope that it will be usefu qix# This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # From mksh set -o posix ; shopt -u xpg_echo (echo 1 ${IFS+'}'z}) 2>&- || echo failed in 1 (echo 2 "${IFS+'}'z}") 2>&- || echo failed in 2 (echo 3 "foo ${IFS+'bar} baz") 2>&- || echo failed in 3 (echo -n '4 '; printf '%s\n' "foo ${IFS+"b c"} baz") 2>&- || echo failed in 4 (echo -n '5 '; printf '%s\n' "foo ${IFS+b c} baz") 2>&- || echo failed in 5 (echo 6 ${IFS+"}"z}) 2>&- || echo failed in 6 (echo 7 "${IFS+"}"z}") 2>&- || echo failed in 7 (echo 8 "${IFS+\"}\"z}") 2>&- || echo failed in 8 (echo 9 "${IFS+\"\}\"z}") 2>&- || echo failed in 9 (echo 10 foo ${IFS+'bar} baz'}) 2>&- || echo failed in 10 (echo 11 "$(echo "${IFS+'ÿÿ ")") 2>&- || echo failed in 11 (echo 12 "$(echo ${IFS+'}'z})") 2>&- || echo failed in 12 (echo 13 ${IFS+\}z}) 2>&- || echo failed in 13 (echo 14 "${IFS+\}z}") 2>&- || echo failed in 14 u=x; (echo -n '15 '; printf '<%s> ' "foo ${IFS+a"b$u{ {"{{\}b} c ${IFS+d{}} bar" ${IFS-e{}} baz; echo .) 2>&- || echo failed in 15 l=t; (echo 16 ${IFS+h`echo -n i ${IFS+$l}h`ere}) 2>&- || echo failed in 16 l=t; (echo 17 ${IFS+h$(echo -n i ${IFS+$l}h)ere}) 2>&- || echo failed in 17 l=t; (echo 18 "${IFS+h`echo -n i ${IFS+$l}h`ere}") 2>&- || echo failed in 18 l=t; (echo 19 "${IFS+h$(echo -n i ${IFS+$l}h)ere}")!2>&- || echo failed in 19 l=t; (echo 20 ${IFS+h`echo -n i "${IFS+$l}"h`ere}) 2>&- || echo failed in 20 l=t; (echo 21 ${IFS+h$(echo -n i "${IFS+$l}"h)ere}) 2>&- || echo failed in 21 l=t; (echo 22 "${IFS+h`echo -n i "${IFS+$l}"h`ere}") 2>&- || echo failed in 22 l=t; (echo 23 "${IFS+h$(echo -n i "${IFS+$l}"h)ere}") 2>&- || echo failed in 23 key=value; (echo -n '24 '; printf '%s\n' "${IFS+'$key'}") 2>&- || echo failed in 24 key=value; (echo -n '25 '; printf '%s\n' "${IFS+"'$key'"}") 2>&- || echo failed in 25 # ksh93: âÂÂ'$key'â key=value; (echo -n '26 '; printf '%s\n' ${IFS+'$key'}) 2>&- || echo failed in 26 key=value; (echo -n '27 '; printf '%s\n' ${IFS+"'$key'"}) 2>&- || echo failed in 27 (echo -n '28 '; printf '%s\n' "${IFS+"'"x ~ x'}'x"'}"x}" #') 2>&- || echo failed in 28 u=x; (echo -n '29 '; printf '<%s> ' foo ${IFS+a"b$u{ {"{ {\}b} c ${IFS+d{}} bar ${IFS-e{}} baz; echo .) 2>&- || echo failed in 29 (echo -n '30 '; printf '<%s> ' ${IFS+foo 'b\ ar' baz}; echo .) 2>&- || (echo failed in 30; echo failed in 31) (echo -n '32 '; printf '<%s> ' ${IFS+foo "b\ ar" baz}; echo .) 2>&- || echo failed in 32 (echo -n '33 '; printf '<%s> ' "${IFS+foo 'b\ ar' baz}"; echo .) 2>&- || echo failed in 33 (echo -n '34 '; printf '<%s> ' "${IFS+foo "b\ ar" baz}"; echo .) 2>&- || echo failed in 34 (echo -n '35 '; printf '<%s> ' ${v=a\ b} x ${v=c\ d}; echo .) 2>&- || echo failed in 35 (echo -n '36 '; printf '<%s> ' "${v=a\ b}" x "${v=c\ d}"; echo .) 2>&- || ech