Bash is incorrectly and inconsistently expanding tilde in $PATH
configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: x86_64-pc-linux-gnu-gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I./include -I. -I./include -I./lib -DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' -DSTANDARD_UTILS_PATH='/bin:/usr/bin:/sbin:/usr/sbin' -DSYS_BASHRC='/etc/bash/bashrc' -DSYS_BASH_LOGOUT='/etc/bash/bash_logout' -DNON_INTERACTIVE_LOGIN_SHELLS -DSSH_SOURCE_BASHRC -DUSE_MKTEMP -DUSE_MKSTEMP -O2 -march=native -mtune=native -pipe uname output: Linux zyx-desktop 4.10.12-gentoo #1 SMP Tue Apr 25 19:08:41 MSK 2017 x86_64 AMD FX(tm)-6200 Six-Core Processor AuthenticAMD GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 48 Release Status: release Description: If $PATH in bash contains ~ (e.g. `PATH='~/bin'`) it is incorrectly treated as if $HOME is present. This may even present a small security risk under certain circumstances: e.g. consider an unexperienced admin which has `PATH="~/bin:$PATH"` in his bashrc. He received an archive with potentially malicious software and wants to analyze it. To do this he created a new directory, made it current and unpacked archive to the place. After that he found that archive contains executables `~/bin/init.sh` and `~/bin/python3`. So to determine what this software targets he opens `~/bin/init.sh` like this: `nvim \~/bin/init.sh`. And whoops, he just has some keylogger running as his user: he has https://github.com/Shougo/denite.nvim installed for his nvim so nvim needs python3 and just executed `./~/bin/python3`, because the only application which expands `~/` in `$PATH` is bash and Neovim python provider is using `system([])` form which calls in libuv directly. Of course, analyzing potential malware not in a VM is unwise and it requires a combination of factors to make the attack successfull. Specifically these factors are: - Admin needs to have `~/bin` in `$PATH` and not `$HOME/bin`, preferably at near the start of the `$PATH`. - Attacker needs to be able to somehow put an executable to `./~/bin/…`. - Attacker needs to make admin run something not with bash while current directory is still set to where executables were put to. Though last part is not too hard: `#!/bin/sh` scripts are using `dash` in debian and it does not expand tilde. Neovim has run-without-a-shell feature for functions like `system()`, `jobstart()`, etc and it is actively used in a plugins where compatibility with Vim does not matter. --- Second point behind disabling this behaviour is inconsistency. Consider another use-case: user has compiled custom Python and wants to use it in Neovim. He has `~/bin` in `$PATH`, put link to his Python installation there, verified that `python --version` shows correct output and started Neovim. Suddenly it appears that Neovim is still using system Python. He checked that `:!python --version` in Neovim is still his custom version (`:!` uses shell) and now goes to Neovim bug tracker and wastes a lot of time waiting for the reply and makes other people waste time deducing the solution. If his configuration was correct not only in bash there would be no such waste on either side, but bash hides the incorrectness. --- Some note: I have found > nn. Bash no longer expands tildes in $PATH elements while in Posix mode. in the 4.4 changelog, but it does not look like it is solving the issue. What I am talking about is that tilde must *never* be expanded in `$PATH`. Repeat-By: Create script.sh with the following contents: ```shell dir="$(mktemp -d)" cd "$dir" mkdir -p home/bin mkdir -p \~/bin HOME="$dir/home" printf '#!/bin/sh\necho script' > home/bin/script printf '#!/bin/sh\necho script2'> home/bin/script2 printf '#!/bin/sh\necho vulnerable' > \~/bin/script chmod a+x home/bin/script chmod a+x home/bin/script2 chmod a+x \~/bin/script PATH='~/bin' if test $# -gt 0 ; then "$@" else script fi cd / /bin/rm -r "$dir" ``` Run it like `bash script.sh`, it will print `script`. Additional information: To defend a point raised in the title that this behaviour is “inconsistent” I have collected results of various different kind of invocations of
Segmentation fault for read -e in _rl_copy_to_kill_ring
Steps to reproduce: Run: read -e Type: 0 ESC 0 \C-? \C-w dualbus@afl2-hjbw:~$ cat -A amin/id:80,sig:11,src:005611+014207,op:splice,rep:16.min 0^[0^?^W dualbus@afl2-hjbw:~$ xxd amin/id:80,sig:11,src:005611+014207,op:splice,rep:16.min : 301b 307f 17 0.0.. Starting program: /home/dualbus/src/gnu/bash/bash bash-4.4$ read -e 0 Program received signal SIGSEGV, Segmentation fault. strlen () at ../sysdeps/x86_64/strlen.S:106 106 ../sysdeps/x86_64/strlen.S: No such file or directory. (gdb) bt #0 strlen () at ../sysdeps/x86_64/strlen.S:106 #1 0x55647425 in _rl_copy_to_kill_ring (text=0x559417a0 "0", append=0) at kill.c:134 #2 0x55647568 in rl_kill_text (from=1, to=0) at kill.c:179 #3 0x556478f1 in rl_unix_word_rubout (count=-1, key=23) at kill.c:328 #4 0x5562d76e in _rl_dispatch_subseq (key=23, map=0x55895140 , got_subseq=0) at readline.c:851 #5 0x5562d4e5 in _rl_dispatch (key=0, map=0x55895140 ) at readline.c:797 #6 0x5562d16d in readline_internal_char () at readline.c:629 #7 0x5562d1c5 in readline_internal_charloop () at readline.c:656 #8 0x5562d1e9 in readline_internal () at readline.c:670 #9 0x5562cc06 in readline (prompt=0x5566dc94 "") at readline.c:374 #10 0x55606f17 in edit_line (p=0x5566dc94 "", itext=0x0) at ./read.def:1069 #11 0x55605e3d in read_builtin (list=0x0) at ./read.def:550 #12 0x555a2034 in execute_builtin (builtin=0x5560510e , words=0x558d0b40, flags=0, subshell=0) at execute_cmd.c:4605 #13 0x555a2f10 in execute_builtin_or_function (words=0x558d0b40, builtin=0x5560510e , var=0x0, redirects=0x0, fds_to_close=0x558d09b0, flags=0) at execute_cmd.c:5103 #14 0x555a193a in execute_simple_command (simple_command=0x558d0970, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x558d09b0) at execute_cmd.c:4391 #15 0x5559b2f0 in execute_command_internal (command=0x558d0c00, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x558d09b0) at execute_cmd.c:811 #16 0x5559a84c in execute_command (command=0x558d0c00) at execute_cmd.c:393 #17 0x555849ca in reader_loop () at eval.c:172 #18 0x55582617 in main (argc=1, argv=0x7fffe498, env=0x7fffe4a8) at shell.c:794
Re: Bash is incorrectly and inconsistently expanding tilde in $PATH
On Wed, May 3, 2017 at 5:40 PM, Nikolay Aleksandrovich Pavlov (ZyX) wrote: [...] > If $PATH in bash contains ~ (e.g. `PATH='~/bin'`) it is incorrectly > treated > as if $HOME is present. Hm. You can start bash in POSIX mode (https://www.gnu.org/software/bash/manual/bash.html#Bash-POSIX-Mode) if you want to disable this feature. i.e. dualbus@debian:~$ bash --posix -c 'printf "%s\n" "#!/bin/bash" "echo hi" > ~/cmd; chmod +x ~/cmd; PATH=\~; declare -p PATH; cmd' declare -x PATH="~" bash: cmd: command not found dualbus@debian:~$ bash -c 'printf "%s\n" "#!/bin/bash" "echo hi" > ~/cmd; chmod +x ~/cmd; PATH=\~; declare -p PATH; cmd' declare -x PATH="~" hi Bash's behavior here is intentional by the way, review the function find_in_path_element in http://git.savannah.gnu.org/cgit/bash.git/tree/findcmd.c?h=devel#n527, it will perform tilde expansion if the path component starts with a tilde. Perhaps it should be documented under https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Variables that bash treats tildes inside PATH specially. Also, I think it's a bit of a stretch to call this a security problem. The scenario you describe (a user having a directory literally named `~' with a bin subdirectory, a malicious program creating evil binaries in $HOME/bin, the user having a misconfigured PATH, ...) is highly unlikely.
Re: Bash is incorrectly and inconsistently expanding tilde in $PATH
Here's a previous discussion on that subject: - http://lists.gnu.org/archive/html/bug-bash/2014-07/msg00022.html - https://lists.gnu.org/archive/html/bug-bash/2014-08/msg2.html
Re: Bash is incorrectly and inconsistently expanding tilde in $PATH
On Thu, May 04, 2017 at 09:54:07AM -0500, Eduardo Bustamante wrote: > Also, I think it's a bit of a stretch to call this a security problem. > The scenario you describe (a user having a directory literally named > `~' with a bin subdirectory, a malicious program creating evil > binaries in $HOME/bin, the user having a misconfigured PATH, ...) is > highly unlikely. Without taking a side on whether this is a security bug in bash, I will support the idea that users who put ~/bin (or similar) in PATH should be educated to make sure the ~ is expanded, rather than literal. This will protect them even if bash gets patched, because most of them will still be using an older/unpatched version. I will also point out that bash expands ~ in PATH assignments such as PATH=~/bin:$PATH or even PATH=$PATH:~/bin:/other/bin. So, it really does take a bit of work to get a literal ~ into PATH in bash, and users should be discouraged from doing that extra, self-harming work.
Re: Bash is incorrectly and inconsistently expanding tilde in $PATH
On Thu, May 4, 2017 at 10:01 AM, Greg Wooledge wrote: [...] > Without taking a side on whether this is a security bug in bash, I will > support the idea that users who put ~/bin (or similar) in PATH should > be educated to make sure the ~ is expanded, rather than literal. This > will protect them even if bash gets patched, because most of them will > still be using an older/unpatched version. So should bash print a warning whenever it performs tilde expansion in one of the PATH components? (similar to the warning it prints when discarding NUL bytes). Something like: dualbus@debian:~/src/gnu/bash$ ./bash -c 'PATH="~"; cmd' ./bash: warning: command lookup: performing tilde expansion due to literal `~' found in PATH hi dualbus@debian:~/src/gnu/bash$ git diff -- findcmd.c diff --git a/findcmd.c b/findcmd.c index c3f00a40..12d3ac2d 100644 --- a/findcmd.c +++ b/findcmd.c @@ -524,7 +524,12 @@ find_in_path_element (name, path, flags, name_len, dotinfop) int status; char *full_path, *xpath; - xpath = (posixly_correct == 0 && *path == '~') ? bash_tilde_expand (path, 0) : path; + if (posixly_correct == 0 && *path == '~') { +internal_warning ("%s", "command lookup: performing tilde expansion due to literal `~' found in PATH"); +xpath = bash_tilde_expand (path, 0); + } else { +xpath = path; + } /* Remember the location of "." in the path, in all its forms (as long as they begin with a `.', e.g. `./.') */
Re: Bash is incorrectly and inconsistently expanding tilde in $PATH
04.05.2017, 17:54, "Eduardo Bustamante" : > On Wed, May 3, 2017 at 5:40 PM, Nikolay Aleksandrovich Pavlov (ZyX) > wrote: > [...] >> If $PATH in bash contains ~ (e.g. `PATH='~/bin'`) it is incorrectly >> treated >> as if $HOME is present. > > Hm. You can start bash in POSIX mode > (https://www.gnu.org/software/bash/manual/bash.html#Bash-POSIX-Mode) > if you want to disable this feature. i.e. > > dualbus@debian:~$ bash --posix -c 'printf "%s\n" "#!/bin/bash" > "echo hi" > ~/cmd; chmod +x ~/cmd; PATH=\~; declare -p PATH; cmd' > declare -x PATH="~" > bash: cmd: command not found > > dualbus@debian:~$ bash -c 'printf "%s\n" "#!/bin/bash" "echo hi" > > ~/cmd; chmod +x ~/cmd; PATH=\~; declare -p PATH; cmd' > declare -x PATH="~" > hi POSIX mode is inconvenient to use: different rc files, a bunch of differences regarding scripts, other things. No process substitution, this is a stopper. > > Bash's behavior here is intentional by the way, review the function > find_in_path_element in > http://git.savannah.gnu.org/cgit/bash.git/tree/findcmd.c?h=devel#n527, > it will perform tilde expansion if the path component starts with a > tilde. Perhaps it should be documented under > https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Variables > that bash treats tildes inside PATH specially. > > Also, I think it's a bit of a stretch to call this a security problem. > The scenario you describe (a user having a directory literally named > `~' with a bin subdirectory, a malicious program creating evil > binaries in $HOME/bin, the user having a misconfigured PATH, ...) is > highly unlikely. There still is a consistency problem. $PATH is not a bash-specific variable for it to have bash-specific features, and I really saw such bugs in either vim-dev or neovim bug tracker (not sure, can’t construct a good search to look for non-letter characters like tilde). More likely in Neovim because in Vim it would need to have &shell set not to bash. Also actually found an [issue][1] in powerline, it does not have that much bugs to search. This is going to be a problem in all cases when bash is used with something which searches in $PATH, but is not bash, so if intentional it is a misfeature. [1]: https://github.com/powerline/powerline/issues/850
Re: Racing condition leads to unstable exit code
On 5/3/17 8:43 PM, Luiz Angelo Daros de Luca wrote: > Yes, the devel one does work. Sorry for the confusion. > It is the first time I see master as stable. It was like that when I inherited it, and I didn't have enough git expertise to fold in all of the previous commits where they should go, so I left it as is and started a new branch. > Would the fix be backported to stable? Let me see if I can put together a patch for you to test. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Bash is incorrectly and inconsistently expanding tilde in $PATH
On 2017-05-04 at 10:11 -0500, Eduardo Bustamante wrote: > On Thu, May 4, 2017 at 10:01 AM, Greg Wooledge wrote: > [...] > > Without taking a side on whether this is a security bug in bash, I will > > support the idea that users who put ~/bin (or similar) in PATH should > > be educated to make sure the ~ is expanded, rather than literal. This > > will protect them even if bash gets patched, because most of them will > > still be using an older/unpatched version. > > So should bash print a warning whenever it performs tilde expansion in > one of the PATH components? (similar to the warning it prints when > discarding NUL bytes). No. IMHO the fix would be to expand ~ at assignment time, even when quoted, ie. PATH='~/bin' would be equivalent to PATH=~/bin Thus, assignments of ~/whatever done in bash would continue working, and descendants using a execvp() function would not find a bare tilde but the expanded path, which is the 'expected' thing. (And for people that really want a literal ~ in PATH, that is already «broken» in bash, so if they expect that to be kept, they should not be doing so within bash)
double free or corruption read builtin
dualbus@debian:~/bash-fuzzing/read$ cat -A 6b M-^_0^A\$ ^N dualbus@debian:~/bash-fuzzing/read$ od -c 6b 000 237 0 001 \ \n 016 006 (gdb) file ~/src/gnu/bash/bash Reading symbols from ~/src/gnu/bash/bash...done. (gdb) r -c 'exec < 6b; read -N3 -d "" IFS; read a b' Starting program: /home/dualbus/src/gnu/bash/bash -c 'exec < 6b; read -N3 -d "" IFS; read a b' *** Error in `/home/dualbus/src/gnu/bash/bash': double free or corruption (out): 0x558b6ac0 *** === Backtrace: = /lib/x86_64-linux-gnu/libc.so.6(+0x70bcb)[0x7767dbcb] /lib/x86_64-linux-gnu/libc.so.6(+0x76f96)[0x77683f96] /lib/x86_64-linux-gnu/libc.so.6(+0x7778e)[0x7768478e] /home/dualbus/src/gnu/bash/bash(read_builtin+0x1a58)[0x55606b82] /home/dualbus/src/gnu/bash/bash(+0x4e034)[0x555a2034] /home/dualbus/src/gnu/bash/bash(+0x4ef10)[0x555a2f10] /home/dualbus/src/gnu/bash/bash(+0x4d93a)[0x555a193a] /home/dualbus/src/gnu/bash/bash(execute_command_internal+0x80a)[0x5559b2f0] /home/dualbus/src/gnu/bash/bash(+0x4a49d)[0x5559e49d] /home/dualbus/src/gnu/bash/bash(execute_command_internal+0xbc0)[0x5559b6a6] /home/dualbus/src/gnu/bash/bash(parse_and_execute+0x548)[0x555fe2d9] /home/dualbus/src/gnu/bash/bash(+0x2f32f)[0x5558332f] /home/dualbus/src/gnu/bash/bash(main+0x83a)[0x555824aa] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7762d2b1] /home/dualbus/src/gnu/bash/bash(_start+0x2a)[0x55581b6a] === Memory map: 4000-5568e000 r-xp fe:01 17570340 /home/dualbus/src/gnu/bash/bash 5588e000-55891000 r--p 0013a000 fe:01 17570340 /home/dualbus/src/gnu/bash/bash 55891000-5589b000 rw-p 0013d000 fe:01 17570340 /home/dualbus/src/gnu/bash/bash 5589b000-558c6000 rw-p 00:00 0 [heap] 7000-70021000 rw-p 00:00 0 70021000-7400 ---p 00:00 0 773f6000-7740c000 r-xp fe:01 1310769 /lib/x86_64-linux-gnu/libgcc_s.so.1 7740c000-7760b000 ---p 00016000 fe:01 1310769 /lib/x86_64-linux-gnu/libgcc_s.so.1 7760b000-7760c000 r--p 00015000 fe:01 1310769 /lib/x86_64-linux-gnu/libgcc_s.so.1 7760c000-7760d000 rw-p 00016000 fe:01 1310769 /lib/x86_64-linux-gnu/libgcc_s.so.1 7760d000-777a2000 r-xp fe:01 1311151 /lib/x86_64-linux-gnu/libc-2.24.so 777a2000-779a1000 ---p 00195000 fe:01 1311151 /lib/x86_64-linux-gnu/libc-2.24.so 779a1000-779a5000 r--p 00194000 fe:01 1311151 /lib/x86_64-linux-gnu/libc-2.24.so 779a5000-779a7000 rw-p 00198000 fe:01 1311151 /lib/x86_64-linux-gnu/libc-2.24.so 779a7000-779ab000 rw-p 00:00 0 779ab000-779ae000 r-xp fe:01 1311170 /lib/x86_64-linux-gnu/libdl-2.24.so 779ae000-77bad000 ---p 3000 fe:01 1311170 /lib/x86_64-linux-gnu/libdl-2.24.so 77bad000-77bae000 r--p 2000 fe:01 1311170 /lib/x86_64-linux-gnu/libdl-2.24.so 77bae000-77baf000 rw-p 3000 fe:01 1311170 /lib/x86_64-linux-gnu/libdl-2.24.so 77baf000-77bd4000 r-xp fe:01 1310814 /lib/x86_64-linux-gnu/libtinfo.so.5.9 77bd4000-77dd4000 ---p 00025000 fe:01 1310814 /lib/x86_64-linux-gnu/libtinfo.so.5.9 77dd4000-77dd8000 r--p 00025000 fe:01 1310814 /lib/x86_64-linux-gnu/libtinfo.so.5.9 77dd8000-77dd9000 rw-p 00029000 fe:01 1310814 /lib/x86_64-linux-gnu/libtinfo.so.5.9 77dd9000-77dfc000 r-xp fe:01 1310733 /lib/x86_64-linux-gnu/ld-2.24.so 77e6-77e61000 rw-p 00:00 0 77e61000-77eb2000 r--p fe:01 26351510 /usr/lib/locale/aa_DJ.utf8/LC_CTYPE 77eb2000-77fe2000 r--p fe:01 26351509 /usr/lib/locale/aa_DJ.utf8/LC_COLLATE 77fe2000-77fe4000 rw-p 00:00 0 77fe4000-77fe5000 r--p fe:01 26351533 /usr/lib/locale/aa_ET/LC_NUMERIC 77fe5000-77fe6000 r--p fe:01 26480725 /usr/lib/locale/en_US.utf8/LC_TIME 77fe6000-77fe7000 r--p fe:01 26355066 /usr/lib/locale/chr_US/LC_MONETARY 77fe7000-77fe8000 r--p fe:01 26355282 /usr/lib/locale/en_AG/LC_MESSAGES/SYS_LC_MESSAGES 77fe8000-77fe9000 r--p fe:01 26355068 /usr/lib/locale/chr_US/LC_PAPER 77fe9000-77fea000 r--p fe:01 26355067 /usr/lib/locale/chr_US/LC_NAME 77fea000-77feb000 r--p fe:01 26480723 /usr/lib/locale/en_US.utf8/LC_ADDRESS 77feb000-77fec000 r--p fe:01 26355069 /usr/lib/locale/chr_US/LC_TELEPHONE 77fec000-77fed000 r--p fe:01 26355064 /usr/lib/locale/chr_US/LC_MEASUREMENT 77fed000-77ff4000 r--s fe:01 25449459 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache 77ff4000-77ff5000 r--p fe:01 26480724 /usr/lib/locale/en_US.utf8/LC_IDENTIFICATION 77ff5000-77ff8000 rw-p 00:00 0 77ff8000-77ffa000 r--p 00:00 0