[comp.unix.ultrix] how to setuid for shell scripts on ultrix?

robinson (Jim Robinson) (11/16/90)

In article <25009@adm.brl.mil> K390590%AEARN@pucc.princeton.edu ( Steinparz Franz) writes:
>Could someone give me advice how to make a shell script which inherits
>its access rights from its owner as this is done by set uid for regular
>programs. Just setting the set uid bit via CHMOD 06xxx does not work
>on vax under ultrix.

I have always been under the impression that setuid shell scripts
intentionally do not work for BSD derived unixes in deference to security
considerations.  However, our experience with ultrix 4.0 (and I believe
2.0) is that *if and only if* "#!/bin/some-shell" is the first line of the
script, then setuid will work for that script. However, does this behaviour
not violate the whole point of not allowing setuid shell scripts - i.e.,
that they are a security risk?  And, if it was indeed the intention to
allow setuid shell scripts, why not go all the way and not require the
leading "#!/bin/shell" as is the case with System V?
-- 
Jim Robinson
{uunet,ubc-cs}!van-bc!mdivax1!robinson

prl@iis.UUCP (Peter Lamb) (11/16/90)

In article <1990Nov15.181448.23231@mdivax1.uucp>:

>In article <25009@adm.brl.mil> K390590%AEARN@pucc.princeton.edu ( Steinparz Franz) writes:
>I have always been under the impression that setuid shell scripts
>intentionally do not work for BSD derived unixes in deference to security
>considerations.

The ability to run setuid shell scripts is inherently tied up
with the #!/path/name header for a script. I seem to remember that
this originated with BSD, but I'm no longer certain.

>However, our experience with ultrix 4.0 (and I believe
>2.0) is that *if and only if* "#!/bin/some-shell" is the first line of the
>script, then setuid will work for that script.

This is true. This is true for all BSD derivatives I know.

>However, does this behaviour
>not violate the whole point of not allowing setuid shell scripts - i.e.,
>that they are a security risk?  And, if it was indeed the intention to
>allow setuid shell scripts, why not go all the way and not require the
>leading "#!/bin/shell" as is the case with System V?

I'm a bit confused by this. I don't think that you need a #! header
in SysV for non-setuid shell scripts. I think that it probably still
honours the old practice of:

1) The shell tries to exec the script with exec[vl](2). If it has
   a #! header, the kernel executes the program named in the header
   and passes it the name of the script as an argument.

2) If the exec() fails, what happens depends on the shell:
	if you are trying to run the program from Bourne shell,
	then the shell forks and the child reads the script as commands.

	if you are using csh, then csh examines the first byte
	of the file, and if it's a #, then csh forks and
	reads the file as commands, otherwise
	it forks, and execs /bin/sh with the pathname of the script
	as its argument.

The reasons behind the strategy in 2) are rather archane; the Bourne shell
predated csh, and in *that* (V7) version of the Bourne shell, # was not
a comment character; so that csh could run both sh and csh scripts,
csh scripts had to start with a #, since this was an unlikely
first character for a (V7) sh script (In V7 there was no #!/path/name
hack). Confused? I am!

You should also note that #! is not restricted to shells. If you
can predict what the following #! executable will do, you
are well on the way to understanding all this:

#!/bin/cat
hello squire

(You need to put it in a file and make it executable. What happens
when you run it? [retorical question :-)])

Those in need of a bit more of a challenge might try:

#!/bin/sed /^#/d
hello sailor


HOWEVER, before you dash off and start making setuid shell scripts:

	SETUID SHELL SCRIPTS ARE INHERENTLY A SECURITY HOLE!

		You *CAN'T* make them hackerproof.

The only exceptions I know to this are Larry Wall's perl interpreter
and Maarten Litmaat's setuid program (but make sure you get his
*second* release, not the first, to comp.sources.unix).

Since bulletproof /bin/sh and /bin/csh programs are notoriously
difficult to write, even in the absence of the kernel problem,
my recommendation is perl.
Peter Lamb
uucp:  uunet!mcsun!ethz!prl	eunet: prl@iis.ethz.ch	Tel:   +411 256 5241
Integrated Systems Laboratory
ETH-Zentrum, 8092 Zurich

magnus%thep.lu.se@Urd.lth.se (Magnus Olsson) (11/16/90)

In article <6644@ethz.UUCP> prl@iis.UUCP (Peter Lamb) writes:
>	SETUID SHELL SCRIPTS ARE INHERENTLY A SECURITY HOLE!
>
>		You *CAN'T* make them hackerproof.

Why? 

Magnus Olsson                   | \e+      /_
Dept. of Theoretical Physics    |  \  Z   / q
University of Lund, Sweden      |   >----<           
Internet: magnus@thep.lu.se     |  /      \===== g
Bitnet: THEPMO@SELDC52          | /e-      \q

cjc@ulysses.att.com (Chris Calabrese) (11/18/90)

In article <6644@ethz.UUCP> prl@iis.UUCP (Peter Lamb) writes:
>HOWEVER, before you dash off and start making setuid shell scripts:
>
>	SETUID SHELL SCRIPTS ARE INHERENTLY A SECURITY HOLE!
>
>		You *CAN'T* make them hackerproof.
>
>The only exceptions I know to this are Larry Wall's perl interpreter
>and Maarten Litmaat's setuid program (but make sure you get his
>*second* release, not the first, to comp.sources.unix).
>
>Since bulletproof /bin/sh and /bin/csh programs are notoriously
>difficult to write, even in the absence of the kernel problem,
>my recommendation is perl.
>Peter Lamb
>uucp:  uunet!mcsun!ethz!prl	eunet: prl@iis.ethz.ch	Tel:   +411 256 5241
>Integrated Systems Laboratory
>ETH-Zentrum, 8092 Zurich

I thought I'd throw my $.02 into this discussion.
Yes, it is possible to make them hackerproof.
This requires 2 things. First, it requires the the script itself is
secure (perl, etc help here).  Second, it requires the elimination of
the kernel problem.  This has been fixed in versions done at bell labs
(and subsequently used in the System V Release 4 kernel).

The key is that the kernel must pass a file descriptor to the script,
not merely the name of the script.  This is done by using /dev/fd and
passing the appropriate file name for the file descriptor.  Under this
scheme, since the file is never closed and a descriptor is effectively
passed, any foolings with symlinks, naming, etc as has been suggested
as the inherent security hole won't work.

Of course, it's still difficult to do the right thing with IFS, etc.
But at least this makes it _possible_ to write a 100% bullet proof
setuid script.

Name:			Christopher J. Calabrese
Brain loaned to:	AT&T Bell Laboratories, Murray Hill, NJ
att!ulysses!cjc		cjc@ulysses.att.com
Obligatory Quote:	``pher - gr. vb. to schlep.  phospher - to schlep light.philosopher - to schlep thoughts.''

guy@auspex.auspex.com (Guy Harris) (11/18/90)

>I have always been under the impression that setuid shell scripts
>intentionally do not work for BSD derived unixes in deference to security
>considerations.

What actually happened is that due to a particular
unclosable-without-"/dev/fd" security hole, Berkeley sent out a 4.xBSD
patch to disable set-UID shell scripts, which some vendors have picked
up.

Prior to that patch, BSD quite happily let you write setuid shell
scripts, and happily let anybody who knew the trick get an interactive
shell running with the user ID of such a script.

>However, our experience with ultrix 4.0 (and I believe 2.0) is that *if
>and only if* "#!/bin/some-shell" is the first line of the script, then
>setuid will work for that script.

That's because if the script doesn't begin with a "#!" line, the shell
script isn't "directly executable" - i.e., an "execv()" or "execl()"
call specifying that script will fail, while if it begins with a "#!"
line, on many systems the "execv()" or "execl()" call will succeed.  The
way that works on a large number of those systems is that the code that
implements "execv()" ("execl()" generally being a wrapper around it)
notices the "#!" line, parses it, and runs the program specified by the
pathname.  That's generally the same code that handles the set-UID bit,
so it just runs the program in question set-UID.

For non-"#!" scripts, the code that calls "execv()" or "execl()" has to
notice the failure and decide to run a shell with that script.  The code
in question is generally running as ordinary user-mode code and
therefore cannot simply decide to run the shell in question set-UID.

>However, does this behaviour not violate the whole point of not
>allowing setuid shell scripts - i.e., that they are a security risk?

It does, but at the time the particular security hole that provoked
Berkeley into making the patch in question wasn't known, so it was
considered OK to have the system allow shell scripts to be set-UID.

>And, if it was indeed the intention to allow setuid shell scripts, why
>not go all the way and not require the leading "#!/bin/shell" as is the
>case with System V?

No System V system with which I'm familiar allows scripts *not*
beginning with "#!" to be set-UID.  Certainly none of the vanilla
from-AT&T versions of S5 I've seen the code of (S5"R1", S5R2, S5R3) do. 
None of the S5's from AT&T prior to S5R4 even support "#!" in the
fashion I described above; S5R4 does, and also, I think, fixes the
particular security hole in question.  (There may well be other holes
nobody's found, or at least told enough people about, yet.)

Both System V *and* BSD (and the earlier UNIX systems on their branches
of the family tree) have shells that will do the aforementioned
operation for scripts that don't begin with "#!", and all but some
systems *very* far back on the family tree have routines ("execlp()",
"execvp()") that do stuff similar to what the shells do.

In other words:

Few if any UNIX systems require a "#!" line for executable shell scripts
- or, at least, scripts executable as commands by the shells and
executable by programs using "execlp()" or "execvp()".

Few if any UNIX systems *don't* require a "#!" line for set-UID scripts,
although some shells have alternative mechanisms for handling them that
may allow them to work without "#!" (e.g., some versions of the Korn
shell) and some other programs exist to handle them as well.