💾 Archived View for thrig.me › blog › 2023 › 02 › 27 › bad-var-good-var.gmi captured on 2024-07-09 at 00:58:31. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-02-05)

-=-=-=-=-=-=-

use of $var in POSIX shell code considered harmful

This is a public service announcement. Use of unquoted variables in POSIX shells will cause a perhaps unexpected split and glob. When in doubt, quote your variables, or use a different programming language.

    $ mkdir empty && cd empty
    $ touch foo bar
    $ var="f* b*"
    $ echo $var
    foo bar
    $ echo "$var"
    f* b*

That is, `cmd $var` in a POSIX shell is actually something like (command (glob (split var))) in a sane language. The extra quotes `cmd "$var"` give you the simpler and probably what you expected (command var). A sensible default in POSIX sh code is to always put in the double quotes.

ZSH is not a POSIX shell and does not exhibit this glorious footgun, by default. A fine manual to read might be zshexpn(1), or you can mash tab at various points to see a completion list, assuming the completion system is enabled.

    $ zsh
    % var="f* b*"
    % print -l $var
    f* b*
    % print -l ${(z)var}
    f*
    b*
    % print -l ${~${(z)var}}
    foo
    bar

Where (z) is some sort of split and ~ some sort of glob, the readability of which might be contrasted with the following, which does take longer to type out.

    perl -E 'say for map { glob } split " ", "f* b*"'

Also you're not supposed to use echo(1) in portable code, try printf(1) instead.

But what is the big deal?

Shell code, alas, is often used where it should not be, and this can result in security vulnerabilities, e.g. when a DHCP client hook script hands off something from an untrusted server to random shell code, or where an attacker can place files into a directory that the auto-glob of an unquoted $var picks up on and then, well, who knows what a clever attacker will make the code do.

    $ touch ./-rf
    $ echo *
    -rf bar foo

You might see where this could go if the command is instead rm(1), or if the command could be convinced to open a port for an attacker to connect to, or who knows what. Worse: what if the shell code is a CGI? David Korn's cgi-lib.ksh is reputed to have a security vulnerability in the cookie handling code due to unquoted variables.

So. By default, quote your "$var" in POSIX shell code. Or use some other language (and pay attention to what security vulnerabilities are possible there).

How did we get here?

David Korn regrets inheriting the auto-split from sh, though wrote for compatibility with existing scripts to ease adoption of his namesake Korn Shell:

Korn: The things that I most regret are not the code itself but mistakes that are in the shell language that I inherited from the Bourne shell code. A lot of effort was made to maintain compatibility while trying to improve ksh at the same time. Compatibility was an extremely important consideration for the adoption of ksh by may organizations. At one point I backed out an improvement because it broke one script in a published UNIX book. If I had my choice, the backquote would disappear as a special character and $() would need to be used instead. Double quoted strings would interpret all of the ANSI-C backslash conventions as well as expand $ expansions. The echo command would not perform any interpretation on its argument. Word splitting would be disabled by default. Note that because I did not make these changes, ksh can safely replace /bin/sh on most systems today unlike zsh which would cause many script to fail in mysterious ways.

https://news.slashdot.org/story/01/02/06/2030205/david-korn-tells-all

tags #unix #sh #security