From: the.true.nathan.mi...@gmail.com To: bug-bash@gnu.org Subject: Getopts crashes when passing several zeroes.
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -g -O2 uname output: Linux nixos 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 5.3-devel Patch Level: 0 Release Status: devel-a23c863e Clang: ``` clang version 19.1.7 Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /nix/store/x6rsdc4s0f1j9bn1cx2h1l5fj8765ykw-clang-19.1.7/bin ``` NixOS: ``` nixos-version > 25.05.806304.dfcd5b901dba (Warbler) ``` Description: Running the following code causes AddressSanitizer to crash with a heap buffer overflow. It seems that nextchar points one past the NUL terminator on the 2nd getopts call. Probably because the 3rd argument of the first call was one character longer. It seems that sh_charindex does not get reset to zero between getopts invocations. Found with AFL++ in Docker but I could not get crashwalk to work in docker. This is crash id #1898 which includes NUL bytes and tab characters, but I minimized it to the following command: ./bash -c "getopts 0 0 -00;getopts 0 0 0" The laptop I'm running this on is a MSI GS63 Stealth 8RE (6-cores, 12 hyperthreads) with 32GB RAM and Windows 10 (Bash is being run in a WSL2 VM). System bash on NixOS does not crash given the same command. [Detailed description of the problem, suggestion, or complaint.] Repeat-By: 1. Compile Bash from source with commit a23c863e as follows: > nix --enable-experimental-features 'nix-command flakes' develop nixpkgs#bash. > export CC=clang CXX=clang CFLAGS='-O0 -g3 -fno-omit-frame-pointer > -fsanitize=address,undefined' LDFLAGS='-fsanitize=address,undefined';time > (./configure --without-bash-malloc && make -j6) 2. Run the development Bash with -c "getopts 0 0 -00;getopts 0 0 0" (that's the number zero, not a NUL byte or the letter O) 3. Address Sanitizer complains of a heap buffer overflow. Fix: I don't know how to fix this. I have tried resetting sh_charindex in a few places, but the testsuite hangs in an infinite loop of printing "opt: ?" when running the run-getopts test. That test runs fine with unmodified Bash from source. [Description of how to fix the problem. If you don't know a fix for the problem, don't include this section.] Output: ../1898-heap-buffer-overflow-getopts.sh: line 2: getopts: `0': not a valid identifier ================================================================= ==29221==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5020000050f2 at pc 0x555555be2761 bp 0x7fffffff7770 sp 0x7fffffff7768 READ of size 1 at 0x5020000050f2 thread T0 #0 0x555555be2760 (/home/nixos/src/bash/nonAFL/bash+0x68e760) (BuildId: dab15212a73e587148877896feaabf620911fe79) #1 0x555555bc5fc7 (/home/nixos/src/bash/nonAFL/bash+0x671fc7) (BuildId: dab15212a73e587148877896feaabf620911fe79) #2 0x555555bc5a91 (/home/nixos/src/bash/nonAFL/bash+0x671a91) (BuildId: dab15212a73e587148877896feaabf620911fe79) #3 0x55555598ea39 (/home/nixos/src/bash/nonAFL/bash+0x43aa39) (BuildId: dab15212a73e587148877896feaabf620911fe79) #4 0x55555598d65b (/home/nixos/src/bash/nonAFL/bash+0x43965b) (BuildId: dab15212a73e587148877896feaabf620911fe79) #5 0x555555969513 (/home/nixos/src/bash/nonAFL/bash+0x415513) (BuildId: dab15212a73e587148877896feaabf620911fe79) #6 0x55555595dcc1 (/home/nixos/src/bash/nonAFL/bash+0x409cc1) (BuildId: dab15212a73e587148877896feaabf620911fe79) #7 0x55555595a7f1 (/home/nixos/src/bash/nonAFL/bash+0x4067f1) (BuildId: dab15212a73e587148877896feaabf620911fe79) #8 0x5555558f2a90 (/home/nixos/src/bash/nonAFL/bash+0x39ea90) (BuildId: dab15212a73e587148877896feaabf620911fe79) #9 0x5555558e9fb2 (/home/nixos/src/bash/nonAFL/bash+0x395fb2) (BuildId: dab15212a73e587148877896feaabf620911fe79) #10 0x7ffff7a2a47d (/nix/store/zdpby3l6azi78sl83cpad2qjpfj25aqx-glibc-2.40-66/lib/libc.so.6+0x2a47d) (BuildId: 184c6644327611cadef0a544327ebb842fceaa2c) #11 0x7ffff7a2a538 (/nix/store/zdpby3l6azi78sl83cpad2qjpfj25aqx-glibc-2.40-66/lib/libc.so.6+0x2a538) (BuildId: 184c6644327611cadef0a544327ebb842fceaa2c) #12 0x5555557a8a84 (/home/nixos/src/bash/nonAFL/bash+0x254a84) (BuildId: dab15212a73e587148877896feaabf620911fe79) 0x5020000050f2 is located 0 bytes after 2-byte region [0x5020000050f0,0x5020000050f2) allocated by thread T0 here: #0 0x55555589b787 (/home/nixos/src/bash/nonAFL/bash+0x347787) (BuildId: dab15212a73e587148877896feaabf620911fe79) #1 0x555555b52801 (/home/nixos/src/bash/nonAFL/bash+0x5fe801) (BuildId: dab15212a73e587148877896feaabf620911fe79) #2 0x555555a433dd (/home/nixos/src/bash/nonAFL/bash+0x4ef3dd) (BuildId: dab15212a73e587148877896feaabf620911fe79) #3 0x555555a89082 (/home/nixos/src/bash/nonAFL/bash+0x535082) (BuildId: dab15212a73e587148877896feaabf620911fe79) #4 0x555555a4ecd6 (/home/nixos/src/bash/nonAFL/bash+0x4facd6) (BuildId: dab15212a73e587148877896feaabf620911fe79) #5 0x555555a4eae1 (/home/nixos/src/bash/nonAFL/bash+0x4faae1) (BuildId: dab15212a73e587148877896feaabf620911fe79) #6 0x55555596726e (/home/nixos/src/bash/nonAFL/bash+0x41326e) (BuildId: dab15212a73e587148877896feaabf620911fe79) #7 0x55555595dcc1 (/home/nixos/src/bash/nonAFL/bash+0x409cc1) (BuildId: dab15212a73e587148877896feaabf620911fe79) #8 0x55555595a7f1 (/home/nixos/src/bash/nonAFL/bash+0x4067f1) (BuildId: dab15212a73e587148877896feaabf620911fe79) #9 0x5555558f2a90 (/home/nixos/src/bash/nonAFL/bash+0x39ea90) (BuildId: dab15212a73e587148877896feaabf620911fe79) #10 0x5555558e9fb2 (/home/nixos/src/bash/nonAFL/bash+0x395fb2) (BuildId: dab15212a73e587148877896feaabf620911fe79) #11 0x7ffff7a2a47d (/nix/store/zdpby3l6azi78sl83cpad2qjpfj25aqx-glibc-2.40-66/lib/libc.so.6+0x2a47d) (BuildId: 184c6644327611cadef0a544327ebb842fceaa2c) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/nixos/src/bash/nonAFL/bash+0x68e760) (BuildId: dab15212a73e587148877896feaabf620911fe79) Shadow bytes around the buggy address: 0x502000004e00: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa 0x502000004e80: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x502000004f00: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x502000004f80: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x502000005000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa =>0x502000005080: fa fa 00 fa fa fa 02 fa fa fa 00 01 fa fa[02]fa 0x502000005100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000005180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000005200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000005280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000005300: 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 ==29221==ABORTING Program received signal SIGKILL, Killed. 0x00005555558b9810 in __sanitizer::internal__exit(int) () (rr) bt #0 0x00005555558b9810 in __sanitizer::internal__exit(int) () #1 0x00005555558c6853 in __sanitizer::Die() () #2 0x00005555558a56c3 in __asan::ScopedInErrorReport::~ScopedInErrorReport() () #3 0x00005555558a4cba in __asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) [clone .part.0] () #4 0x00005555558a6006 in __asan_report_load1 () #5 0x0000555555be2761 in sh_getopt (argc=2, argv=0x504000011620, optstring=0x5020000050b0 "0") at getopt.c:137 #6 0x0000555555bc5fc8 in dogetopts (argc=2, argv=0x504000011620) at ./getopts.def:194 #7 0x0000555555bc5a92 in getopts_builtin (list=0x5020000048d0) at ./getopts.def:326 #8 0x000055555598ea3a in execute_builtin (builtin=0x555555bc5918 <getopts_builtin>, words=0x502000004930, flags=0, subshell=0) at execute_cmd.c:5097 #9 0x000055555598d65c in execute_builtin_or_function (words=0x502000004930, builtin=0x555555bc5918 <getopts_builtin>, var=0x0, redirects=0x0, fds_to_close=0x502000004dd0, flags=0) at execute_cmd.c:5643 #10 0x0000555555969514 in execute_simple_command (simple_command=0x503000010ea0, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x502000004dd0) at execute_cmd.c:4856 #11 0x000055555595dcc2 in execute_command_internal (command=0x503000010e70, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x502000004dd0) at execute_cmd.c:938 #12 0x000055555595a7f2 in execute_command (command=0x503000010e70) at execute_cmd.c:456 #13 0x00005555558f2a91 in reader_loop () at eval.c:183 #14 0x00005555558e9fb3 in main (argc=2, argv=0x7fffffff8e78, env=0x7fffffff8e90) at shell.c:834