# When bash is compiled with multibyte support, the following happens: - set -o vi - Type: <a><ESC><r><ñ><.> - Bash writes \261 to `mb[0]' and '\0' to `mb[1]' (ñ is U+00F1, or in UTF-8, \303\261) - `mb' is of type signed char, and not really suitable to store a wide character.
dualbus@debian:~$ set -o vi dualbus@debian:~$ � bash: $'\261': command not found # When bash is compiled w/o multibyte support, the following happens: 1948 int 1949 rl_vi_change_char (int count, int key) 1950 { 1951 int c; 1952 char mb[MB_LEN_MAX]; /* MB_LEN_MAX == 1 */ 1953 1954 if (_rl_vi_redoing) 1955 { 1956 c = _rl_vi_last_replacement; 1957 mb[0] = c; 1958 mb[1] = '\0'; /* out of bounds write */ 1959 } Reproduce with: - set -o vi - Type: <a><ESC><r><b><.> - Bash writes '\0' to `mb[1]', which is out of bounds. dualbus@debian:~/src/gnu/bash-build$ ./bash bash-4.4$ set -o vi bash-4.4$ ================================================================= ==7881==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe8416f471 at pc 0x55e4ba75d81a bp 0x7ffe8416f420 sp 0x7ffe8416f418 WRITE of size 1 at 0x7ffe8416f471 thread T0 #0 0x55e4ba75d819 in rl_vi_change_char ../../../bash/lib/readline/vi_mode.c:1959 #1 0x55e4ba74fe3d in _rl_dispatch_subseq ../../../bash/lib/readline/readline.c:851 #2 0x55e4ba74fa18 in _rl_dispatch ../../../bash/lib/readline/readline.c:797 #3 0x55e4ba752a41 in rl_vi_redo ../../../bash/lib/readline/vi_mode.c:285 #4 0x55e4ba74fe3d in _rl_dispatch_subseq ../../../bash/lib/readline/readline.c:851 #5 0x55e4ba74fa18 in _rl_dispatch ../../../bash/lib/readline/readline.c:797 #6 0x55e4ba74f257 in readline_internal_char ../../../bash/lib/readline/readline.c:629 #7 0x55e4ba74f2e9 in readline_internal_charloop ../../../bash/lib/readline/readline.c:656 #8 0x55e4ba74f30d in readline_internal ../../../bash/lib/readline/readline.c:670 #9 0x55e4ba74e9c3 in readline ../../../bash/lib/readline/readline.c:374 #10 0x55e4ba5ffd01 in yy_readline_get ../bash/parse.y:1464 #11 0x55e4ba5ffed9 in yy_readline_get ../bash/parse.y:1495 #12 0x55e4ba5ffb64 in yy_getc ../bash/parse.y:1397 #13 0x55e4ba601ea4 in shell_getc ../bash/parse.y:2297 #14 0x55e4ba6048d0 in read_token ../bash/parse.y:3146 #15 0x55e4ba6032ad in yylex ../bash/parse.y:2683 #16 0x55e4ba5f7f31 in yyparse /home/dualbus/src/gnu/bash-build/y.tab.c:1821 #17 0x55e4ba5f7102 in parse_command ../bash/eval.c:294 #18 0x55e4ba5f7357 in read_command ../bash/eval.c:338 #19 0x55e4ba5f6593 in reader_loop ../bash/eval.c:140 #20 0x55e4ba5f1d3d in main ../bash/shell.c:794 #21 0x7ff2e9a7d2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0) #22 0x55e4ba5f0939 in _start (/home/dualbus/src/gnu/bash-build/bash+0x7b939) Address 0x7ffe8416f471 is located in stack of thread T0 at offset 33 in frame #0 0x55e4ba75d72f in rl_vi_change_char ../../../bash/lib/readline/vi_mode.c:1950 This frame has 1 object(s): [32, 33) 'mb' <== Memory access at offset 33 overflows this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow ../../../bash/lib/readline/vi_mode.c:1959 in rl_vi_change_char Shadow bytes around the buggy address: 0x100050825e30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825e40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825e60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825e70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x100050825e80: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1[01]f4 0x100050825e90: f4 f4 f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 0x100050825ea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825eb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825ec0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100050825ed0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 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 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==7881==ABORTING Issue found with cppcheck: [../bash/lib/readline/vi_mode.c:1958]: (error) Array 'mb[1]' accessed at index 1, which is out of bounds. -- Eduardo Bustamante https://dualbus.me/