[Bash-completion-devel] [bash-completion-Bugs][311614] Quoting to prevent globbing (was: quoting bug in _known_hosts)

bash-completion-bugs at alioth.debian.org bash-completion-bugs at alioth.debian.org
Fri Sep 25 07:49:39 UTC 2009


Bugs item #311614, was changed at 2009-04-22 15:00 by Freddy Vulto
You can respond by visiting: 
https://alioth.debian.org/tracker/?func=detail&atid=413095&aid=311614&group_id=100114

>Status: Closed
Priority: 3
Submitted By: Eric Blake (eblake-guest)
Assigned to: Freddy Vulto (fvu-guest)
Summary: Quoting to prevent globbing (was: quoting bug in _known_hosts) 
Distribution: --Distribution-Agnostic--
Originally reported in: None
Milestone: 1.0
Status: None
Original bug number: 


Initial Comment:
There is a quoting bug in _known_hosts, which causes the shell to attempt glob expansion.  Although unlikely, a user can name a file to include shell metacharacters so that the glob performs arbitrary actions.

This portion of _known_hosts:

 COMPREPLY=($( awk 'BEGIN {FS=","}
                     /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \
                            gsub(" .*$", "", $i); \
                            if ($i ~ /'$cur'/) {print $i} \
                     }}' "${kh[@]}" 2>/dev/null ));

Needs "" around $cur.  Otherwise, something like 'ssh <tab>' causes cur to be defined as [a-z.], and since $cur does not occur in "", the shell treats it as a glob.


----------------------------------------------------------------------

>Comment By: Freddy Vulto (fvu-guest)
Date: 2009-09-25 09:49

Message:
I've rewalked bash-completion and the contrib/* files and quoted all unquoted occurences of $cur (git commit cfcf9fa).

Version 1.0-3 I tested was actually a Debian package, sorry about the confusion.  The latest version is indeed bash-completion-1.0.  Bash-completion-1.1 will probably be released within the next few weeks.

Regards,
Freddy Vulto
http://fvue.nl

----------------------------------------------------------------------

Comment By: Freddy Vulto (fvu-guest)
Date: 2009-09-04 23:13

Message:
I'm able to reproduce the problem on Windows/Cygwin (see below *1).
Nice I can also see the error on Windows/Cygwin using `strace' (see
below *2) or on Linux using `strace' (see below *3).

Enough havoc to not wait for a `set -o noglob' ;-)

I've patched _known_hosts_real().  About fixing the remaining of
bash_completion, any chance you can regenerate the patch against the
latest git master?


Regards, thanks,

Freddy Vulto
http://fvue.nl





*1)  Steps to reproduce on Windows/Cygwin
=========================================

Environment: Windows, cygwin-1.7, bash-completion-1.0-1

Steps to reproduce:
1.  Create files `config' and `known_hosts':

    $ cat config
    UserKnownHostsFile known_hosts
    $ cat known_hosts
    foo

2.  Do tab completion:

    scp -F config <TAB> 

Expected output: 

    foo

Instead I see:

    cygwin warning:
    MS-DOS style path detected: BEGIN {FS=","}
                                  /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \
                                         gsub(" .*$", "", $i); \
                                         if ($i ~ /
    Preferred POSIX equivalent is: BEGIN {FS=","}
                                  /^/s*[^|/#]/ {for (i=1; i<=2; ++i) { /
                                         gsub(" .*$", "", $i); /
                                         if ($i ~ /
    CYGWIN environment variable option "nodosfilewarning" turns off this warning.
    Consult the user's guide for more details about POSIX paths:
      http://cygwin.com/cygwin-ug-net/using.html#using-pathnames



*2)  Steps to reproduce on Windows/Cygwin using strace
======================================================
    
Environment:  Windows, Cygwin-1.7, bash-completion-1.0-1

1.  Create files `config' and `known_hosts':

    $ cat config
    UserKnownHostsFile known_hosts
    $ cat known_hosts
    foo

2.  Let `strace' track `bash' in a separate window (-w) and log to `strace.log':

    $ strace -o strace.log -w bash

3.  In the new bash window, type:

    $ scp -F config <TAB>

4.  Type ^C and ^D to exit the bash window

5.  Check `strace.log', here you can see bash accessing something it shouldn't:

    ...
    5121 69950229 [main] bash 1340 normalize_posix_path: src BEGIN {FS=","}
       /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \
	      gsub(" .*$", "", $i); \
	      if ($i ~ /
    ...



*3)  Steps to reproduce on Linux using `strace'
===============================================

Environment:  Linux, bash-completion-1.0

1.  Start bash with bash-completion loaded, create files
    `config' and `known_hosts', and find out PID ($$):

    $ cat config
    UserKnownHostsFile known_hosts
    $ cat known_hosts
    foo
    $ echo $$
    291515

2.  In a second bash shell, `strace' the above PID:

    $ strace -e trace=open -f -p 291515 -o strace.log

3.  Within the first bash shell, type:

    $ scp -F config <TAB>

4.  In the second bash shell, type ^C to quick `strace'.

5.  Check `strace.log', here you can see bash accessing
    something it shouldn't:

    ...
    29659 open("BEGIN {FS=\",\"}
        /^\\s*[^|\\#]/ {for (i=1; i<=2; ++i) { \\
            gsub(\" .*$\", \"\", $i); \\
            if ($i ~ /", O_RDONLY|O_NONBLOCK|O_LARGEFILE
            |O_DIRECTORY) = -1 ENOENT (No such file or directory)
    ...
 
    


----------------------------------------------------------------------

Comment By: Eric Blake (eblake-guest)
Date: 2009-09-03 02:58

Message:
The warning is new to cygwin 1.7 (it was not present on cygwin 1.5); and can be avoided by an appropriate setting of the CYGWIN environment variable (although bash-completion should probably  not mess with that).  The warning is a one-shot event - it is only printed the first time any program calls a stat(), open(), or exec() on a string that contains a backslash for a given instantiation of the cygwin dll; thereafter, all strings with backslashes avoid the warning.

Therefore, my recipe for reproducing is to use cygwin's bash-completion-1.0-1 (where'd you get the version 1.0-3?), start a new shell, type 'ssh [TAB]', and notice the following warning:

$ ssh [TAB]cygwin warning:
  MS-DOS style path detected: BEGIN {FS=","}
                                /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \
                                       gsub(" .*$", "", $i); \
                                       if ($i ~ /
  Preferred POSIX equivalent is: BEGIN {FS=","}
                                /^/s*[^|/#]/ {for (i=1; i<=2; ++i) { /
                                       gsub(" .*$", "", $i); /
                                       if ($i ~ /
  CYGWIN environment variable option "nodosfilewarning" turns off this warning.
  Consult the user's guide for more details about POSIX paths:
    http://cygwin.com/cygwin-ug-net/using.html#using-pathnames

Notice the filename that was stat()d as part of glob() - the fact that $cur was unquoted, but contained a *, meant that the entire shell word (including the full sed script with \ line continuations) is passed to glob().  On the other hand, if you double-quote $cur, then the shell ignores the * in $cur and does not call glob(), thus avoiding the stat() of a super-long string containing backslash.


----------------------------------------------------------------------

Comment By: Freddy Vulto (fvu-guest)
Date: 2009-09-02 23:21

Message:
Hello Eric,

Can you give more precise steps to reproduce the problem?

I've tried cygwin-1.5 and cygwin-1.7 with
bash-completion-cygwin, bash-completion-1.0-3 and
bash-completion git and I can't reproduce the problem.

Typing "ssh [TAB]" gives me no warning.  From what I
understand from the problem reported at cygwin.com, it looks
like Cygwin is warning about the backslashes in the sed
script, not $cur?

Regards,

Freddy Vulto

----------------------------------------------------------------------

Comment By: Eric Blake (eblake-guest)
Date: 2009-08-28 02:49

Message:
Here's a real-life example where suppressing the globbing actually matters:

http://cygwin.com/ml/cygwin/2009-04/msg00442.html

On cygwin, attempts to perform ANY glob, where the string being checked for potential expansion contains a literal backslash, issues a warning about using backslash rather than forward slash as a path separator.  Double-quoting $cur silences this warning.


----------------------------------------------------------------------

Comment By: Freddy Vulto (fvu-guest)
Date: 2009-08-27 22:57

Message:
Because this has survived for so many years in bash-completion, I don't think it's really an issue.  Especially considering the great lengths you need to go to make things go wrong:

    $ cur="[a-z.]"
    $ echo 'if ($i ~ /'$cur'/) {print $i}'  # (1)
    if ($i ~ /[a-z.]/) {print $i}           # (2)
    $ mkdir -p 'if ($i ~ /'a'/) {print $i}' # (3)
    $ echo 'if ($i ~ /'$cur'/) {print $i}'  # 
    if ($i ~ /a/) {print $i}                # (4)
    $ rm -rf 'if ($i ~ /'                   # Clean up

Explanation of the above: A sample awk-snippet (1) appears to echo all right (2), but creating awk-like dirs (3) however, causes the glob to resolve, resulting in a mangled awk-snippet (4): the awk-snippet resolves to `if ($i ~ /a/) {print $i}' where it should've been: `if ($i ~ /[a-z.]/) {print $i}'.

Also, quoting solves only half the globbing problem:

    $ cd /var
    $ cur="*"
    $ a=( $( echo "$cur" ) )    # (1)
    $ echo "${a[@]}"            # (2)
    backups cache crash games lib local lock log mail opt run spool tmp
    $

Explanation of the above: Additional globbing is performed when assigning items to `a' (1), causing `a' to contain globbing results instead of '*' (2).

Considering all this, for now I'd rather use quotes just where whitespace might occur, and not quote whole bash-completion for noglobbing sake: Let's just fix globbing where real bugs occur.

For future development however, I think it should be fixed.  Not by quoting but by using `set -o noglob'. Since most of bash-completion is not using globbing and just suffering its consequences, why don't we turn things upside-down and (within a completion) disable globbing by default?

Maybe we can do so after we branched development (drop bash-2 support, merge bash-completion-lib): if a user starts to complete, globbing is turned off, and at the end of a completion, globbing is restored to its previous setting.  Example:

    $ oldSetOptions=$(set +o)
    $ set -o noglob
    $ cur=*
    $ echo $cur
    *
    $ arr=( $( echo $cur ) )
    $ echo "${arr[@]}"
    *
    $ eval "$oldSetOptions" 2> /dev/null
    $

What do you all think?

Freddy Vulto
http://fvue.nl

----------------------------------------------------------------------

Comment By: Eric Blake (eblake-guest)
Date: 2009-05-18 17:52

Message:
I regenerated the patch against the latest git master; with many more instances of underquoted $cur fixed in bash_completion proper.  However, I suspect that a full audit of the contrib files will find yet more underquoted instances.

----------------------------------------------------------------------

Comment By: Eric Blake (eblake-guest)
Date: 2009-04-23 00:08

Message:
attaching a patch for all instances of underquoted $cur that I could find


----------------------------------------------------------------------

You can respond by visiting: 
https://alioth.debian.org/tracker/?func=detail&atid=413095&aid=311614&group_id=100114



More information about the Bash-completion-devel mailing list