Setuid shell scripts (was System V Release 4 ...)

Kenneth Almquist ka at june.cs.washington.edu
Thu Oct 20 04:07:52 AEST 1988


John Chambers asks:

> To be more specific, I'd sure like to know what it is about the
> shell programming languages (Bourne, C, K, T, etc...) that make
> them more risky than a C program.

Here is a possibly incomplete list of problems:

1.  The behavior of shell scripts can depend upon the environment variables
    passed in to them.  The fix to explicitly set every shell variable
    that your shell procedure uses.  Explicitly set shell variables to
    the empty string rather than assuming they will be initialized to
    the empty string by default.  More important, explicitly set all shell
    variables that the shell refers to implicitly.  This includes things
    like PATH and IFS.

2.  The #! passes the name of the shell script as argv[1], but the shell
    does not understand about this convention and will interpret argv[1]
    as an option rather than as a file name if the first character of
    argv[1] is a minus sign.  The fix is to write a little stub program
    in C for each setuid shell procedure.  The stub program is setuid, and
    simply does an exec of the shell with argv[1] set to the full path
    name of the actual shell procedure.  Since the path name of the shell
    procedure is hard coded into the stub, it is guaranteed not to start
    with a minus sign.  The file containing the shell procedure should not
    be either setuid or executable, to ensure that all user invoke the
    stub rather than running the shell procedure directly.

Aside from problems 1 and 2, there are also some more general issues:

3.  People tend to use the shell for quick hacks which work right in most
    cases.  But being a little bit insecure is like being a little bit
    pregnant.  The fix is to put as much thought into writing a setuid
    shell procedure as you would into writing a setuid C program.  In fact,
    writing a setuid shell procedure is *more* difficult that writing a
    setuid C program because the semantics of C are simpler.

4.  When you write a shell procedure your code depends upon a large body
    of software:  the shell and also all the programs that your shell
    procedure invokes.  These programs change.  Usually the changes are
    backward compatible enough for most purposes, but they may not achieve
    the level of backward compatibility required to preserve the security
    of a setuid shell script.  For example, csh doesn't have IFS.  If IFS
    were added to csh, most csh shell scripts would continue to work, but
    setuid csh scripts would have to be modified to set IFS to a standard
    value.  The fix is to write setuid programs in C.

OK, that last sentence deserves half a ":-)", but most of the time it's
not worth the trouble to write a setuid program as a shell procedure when
you have C available.  An exception is when you need to invoke an operation
(such as ps(1)) which requires you to run a separate program.  This is
enough of a pain to do without the shell (note that popen invokes the shell)
that I might use a setuid shell procedure.

In any case, this discussion started with the claim that System V Release 4
would ignore the setuid bits when interpreting "#!".  This affects various
interpreted languages like ICON, but as I explained in point 2 above, setuid
shell procedures implemented using a C language stub (which is the only way
I know of to implement setuid shell procedures if you want securely) don't
use the #! facility at all.
				Kenneth Almquist



More information about the Comp.unix.wizards mailing list