bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

`complete -p -- <cmd>` doesn't yield reusable input when "-F" is assigne


From: Great Big Dot
Subject: `complete -p -- <cmd>` doesn't yield reusable input when "-F" is assigned an invalid identifier
Date: Thu, 24 Jan 2019 12:24:46 -0500

Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=x86-64 -mtune=generic -O2 -pipe
-fstack-protector-strong -fno-plt
-DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local
/bin:/usr/bin' -DSTANDARD_UTILS_PATH='/usr/bin'
-DSYS_BASHRC='/etc/bash.bashrc' -DSYS_BASH_LOGOUT='/etc/bash.bash_logout'
-DNON_INTERACTIVE_LOGIN_SHELLS -Wno-parentheses -Wno-format-security
uname output: Linux ArchBox0 4.20.0-arch1-1-ARCH #1 SMP PREEMPT Mon Dec 24
03:00:40 UTC 2018 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu

Bash Version: 5.0
Patch Level: 0
Release Status: release


Description:
    According to the manual's section on the `complete` builtin:

    > "If the -p option is supplied, or if no options are supplied,
      existing completion specifications are printed in a way that allows
      them to be reused as input."

    Unfortunately, there is at least one edge cases that, despite being
    invalid, are considered valid by `complete`, and the proper measures to
    deal with it are not taken. Namely:

    $ complete -F 'bad func' -- cmd        # No error is triggered here...
    $ complete -p -- cmd                   #
    => complete -F bad func cmd            # Not quoted!!

    The expected behavior ought to be either that the first line yields an
    error (e.g., "bash: `'bad func'': not a valid identifier"), or else the
    second line's output is properly quoted. In particular, if you treat
    the output of `complete -p -- cmd` as valid, sanitized data safe for
    input, you can get any result. E.g., running `eval -- "$(complete -p --
    cmd)"` in this case would set the completion for both `cmd` and "func"
    to the function "bad", which bears little resemblance to what should be
    done.

    Semicolons and quotes such aren't escaped either, so you can in fact
    run arbitrary code if you evaluate it. (Yes, I know that `eval` is
    considered unsafe in general for exactly this reason, but the output of
    `complete -p` is supposed to be safe for reuse; this ought to be a rare
    case when `eval` shouldn't cause problems, no matter what the input.)

    The command name itself is also never quoted. E.g.:

    $ complete -F func -- 'bad cmd'    # Maybe technically a valid command?
    $ complete -p -- 'bad cmd'         #
    => complete -F func bad cmd        # Not quoted!

    (For whatever reason, if you set a completion with "-C", *its* argument
    is escaped properly.)

    This does only occur in the case of invalid identifiers, but no error
    is thrown, so it seems like a problem nonetheless. Putting the above
    results another way, `complete -p` silently transforms an invalid
    command to an entirely different, potentially valid command.

Repeat-By:
    $ complete -F 'invalid indentifier' -- cmd
    $ complete -p -- cmd
    => complete -F invalid identifier cmd

Fix:
    As long as you don't do dumb stuff like setting a completion to a
    "function" with an invalid identifier, this problem is irrelevant. If
    you don't need to parse the output of complete (e.g., if you can make
    an array variable to hold the info or something), it is also
    irrelevant.

    But if you are using `complete -p` and there is for some reason the
    potential for invalid identifiers, I think parsing can actually still
    be done accurately, provided you know the name of the command you're
    completing. (If you don't have the command name, you can't in general
    extract it from the completion, thanks to this bug. E.g., `complete -F
    'foo bar' -- baz` and `complete -F foo -- 'bar baz'` both yield
    "complete -F foo bar baz".)

    Namely: remove the command name and a space from the end of
    `complete -p`'s output, then find the first unquoted " -F "; everything
    after it is the actual function name. (If any of the other complete
    options have problems (which would make it impossible to find the first
    "real" " -F "), I haven't found them.)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]