All of lore.kernel.org
 help / color / mirror / Atom feed
* "command -p" does not correctly limit search to a safe PATH
@ 2013-07-10 18:18 Craig Loomis
  2013-07-14 19:54 ` Harald van Dijk
  0 siblings, 1 reply; 6+ messages in thread
From: Craig Loomis @ 2013-07-10 18:18 UTC (permalink / raw)
  To: dash

  I needed to bootstrap a safe shell environment, assuming only a
minimal "POSIX system" and expecting some peculiar ones (embedded
systems with unusual paths, etc).

  One modern POSIX prescription to establish a safe PATH is fleshed
out in OpenGroup's IEEE 1003.1 at
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
(and so 'man 1p command' on some Linux versions).
  This boils down to (after setting IFS and cleaning out aliases and functions):

$ PATH="$(command -p getconf PATH):$PATH"

  Which works as a bootstrap because:
    - "command" is a shell builtin (per the standard)
    - "command -p" limits its search to system-defined locations.
    - "getconf PATH" uses confstr(3) to get the required
system-defined _CS_PATH.

  The Standard's definition of paths is a bit fuzzy; a paragraph from
the Rationale helps:

"The -p option is present because it is useful to be able to ensure a
safe path search that finds all the standard utilities. This search
might not be identical to the one that occurs through one of the exec
functions (as defined in the System Interfaces volume of POSIX.1-2008)
when PATH is unset. At the very least, this feature is required to
allow the script to access the correct version of getconf so that the
value of the default path can be accurately retrieved."


  Dash (0.5.7 and git master) does not implement 'command -p'
according to the standard, and opens an intriguing security hole to
anyone trying this scheme.

  When using 'command -v' to simply print the path to an executable,
'-p' has no effect:

# Assume that an executable /tmp/evilbin/getconf exists
$ PATH=/tmp/evilbin:$PATH

$ command -v getconf
/tmp/evilbin/getconf
$ command -p -v getconf
/tmp/evilbin/getconf

  Not good, but most people would call getconf directly. At first
glance that _appears_ to work better -- /tmp/evilbin/getconf is not
called:

$ command getconf PATH
/tmp/evilbin:/bin:/usr/bin
$ command -p getconf PATH
/usr/bin:/bin:/usr/sbin:/sbin

  but there are two surprises:
    a) the behavior of 'command -p cmd' and '$(command -p -v cmd)'
really should be the same, no?
    b) the path that 'command -p cmd' uses is a compiled-in constant
from dash's src/var.c:defpathvar, which starts with
"/usr/local/sbin:/usr/local/bin". To me, that is both completely
unexpected and pretty scary -- /usr/local/bin is (very) often less
well secured or checked than, say, /bin:

# somehow, sometime, 'sudo make install' or a g+w /usr/local/ might get you:
$ cp evil_getconf /usr/local/bin/getconf

  after which:

$ command -p getconf PATH
/tmp/evilbin:/bin:/usr/bin

  Ouch.

  src/exec.c and src/eval.c are a bit tricky (see the different
behavior between 'command cmd' and 'command -v cmd') and too
fundamental for me to stand behind a quick patch. Sorry.

  FWIW, bash 4.1+ (and maybe earlier) has a posix compliant 'command
-p'. Fixed sometime after 3.2, from trying that version on OS X 10.8
and RHEL 5.9.

 - craig

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-09-27 22:07 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-10 18:18 "command -p" does not correctly limit search to a safe PATH Craig Loomis
2013-07-14 19:54 ` Harald van Dijk
2013-07-19 21:49   ` Harald van Dijk
2014-09-26  9:19     ` Herbert Xu
2014-09-27 21:57       ` Jilles Tjoelker
2014-09-26  8:44   ` Herbert Xu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.