set-uid wrapper in C

set-uid wrapper in C

Post by Bill Heis » Fri, 19 May 1995 04:00:00



A while back I read somewhere that when you write a C program to
function as a set-uid wrapper around a command, you should use
execl() rather than system().  Apparently there is some security
risk inherent in the use of system().

Could someone elaborate on just what this is?  My reason isn't
to try and exploit any such hole, but to be able to explain
to my colleage why I'm using execl() rather than system() when
system() is actually easier to implement (because it allows
me to do more than one thing in the program without having
to fork(), etc..   i.e. with system() I could just have a
series of system() calls to do the things I want to do.

Thanks in advance.
Bill

--
These are my opinions, not those of my employer.

 
 
 

set-uid wrapper in C

Post by Jeff Dicks » Fri, 19 May 1995 04:00:00



>A while back I read somewhere that when you write a C program to
>function as a set-uid wrapper around a command, you should use
>execl() rather than system().  Apparently there is some security
>risk inherent in the use of system().

>Could someone elaborate on just what this is?  My reason isn't
>to try and exploit any such hole, but to be able to explain
>to my colleage why I'm using execl() rather than system() when
>system() is actually easier to implement (because it allows
>me to do more than one thing in the program without having
>to fork(), etc..   i.e. with system() I could just have a
>series of system() calls to do the things I want to do.

>Thanks in advance.
>Bill

>--
>These are my opinions, not those of my employer.


If you cared anything at all about being less taxing on the system you'd opt
for execl() instead of system() anyways. So what if it's harder to use? That's
part of the fun.

Jeff S.*son

 
 
 

set-uid wrapper in C

Post by Dave Plon » Fri, 26 May 1995 04:00:00




>     Bill> A while back I read somewhere that when you write a C
>     Bill> program to function as a set-uid wrapper around a command,
>     Bill> you should use execl() rather than system().  Apparently
>     Bill> there is some security risk inherent in the use of system().
> system() calls /bin/sh, which reads the IFS environment variable
> (Inter Field Separator). This variable affects how sh parses
> commands. So, for example, if your set-uid wrapper calls
> system("/bin/date"), you could set IFS to /, and the command would run
> a program called 'bin' with the argument 'date'. If you have a program
> in your path called 'bin', this program will be executed with set-uid
> permissions.
> Sounds goofy, but it's true.

That is it exactly.  Once I heard of this, I did some experiments and
found that this security hole has been "fixed" in other shells, by
being much less liberal with where IFS has an effect.  For instance,
in the Korn or POSIX shells I tested, IFS was only used in "for" loops,
the "set" command, and such, where changing the value of IFS is often
necessary.

On HP-UX, the system(3) function invokes /bin/posix/sh, so the problem
doesn't occur.  The other systems I know will still invoke the Bourne
shell.  Also, shell scripts that have "#!/bin/sh" (or whatever
path points specifically to the Bourne shell) at the top are dangerous in
this way.

It's easy to test a shell for this IFS behavior:
ksh> IFS='/' /bin/sh -c '/bin/date'
/bin/sh: bin: not found

Lastly, if you decide to play around with IFS, you can simply
unset it to restore its normal value.  (Remember to do this, especially
if your in an interactive shell.)

Dave

--
------------------------------------------------------///--------------------
  Dave Plonka  ARS:N9HZF          Amiga - 68040 -    ///  486DLC-33 running

- Lead Systems Programmer, McHugh Freeman ------- \\X/- Waukesha, Wisconsin -

 
 
 

set-uid wrapper in C

Post by Jake Donh » Fri, 26 May 1995 04:00:00



    Bill> A while back I read somewhere that when you write a C
    Bill> program to function as a set-uid wrapper around a command,
    Bill> you should use execl() rather than system().  Apparently
    Bill> there is some security risk inherent in the use of system().

system() calls /bin/sh, which reads the IFS environment variable
(Inter Field Separator). This variable affects how sh parses
commands. So, for example, if your set-uid wrapper calls
system("/bin/date"), you could set IFS to /, and the command would run
a program called 'bin' with the argument 'date'. If you have a program
in your path called 'bin', this program will be executed with set-uid
permissions.

Sounds goofy, but it's true.

Jake

 
 
 

set-uid wrapper in C

Post by Frank J. Edwar » Fri, 26 May 1995 04:00:00



Quote:>A while back I read somewhere that when you write a C program to
>function as a set-uid wrapper around a command, you should use
>execl() rather than system().  Apparently there is some security
>risk inherent in the use of system().

>Could someone elaborate on just what this is?  My reason isn't
>to try and exploit any such hole, but to be able to explain
>to my colleage why I'm using execl() rather than system() when
>system() is actually easier to implement (because it allows
>me to do more than one thing in the program without having
>to fork(), etc..   i.e. with system() I could just have a
>series of system() calls to do the things I want to do.

I saw a reply to this that didn't answer anything at all, so I'll do that
here.

The first and biggest problem with system() is that it executes a shell
for you.  It uses the SHELL environment variable to do that.  It's
therefore possible for the user to change their variable and point it
to a shell script that starts with "#!" and their script would be running
with setid authority (they would ignore any/all parameters passed to them,
of course).

The second problem is for programs that run multiple jobs at once.  The
system() call uses wait() to wait for the fork()ed process to complete.
If there is already another child running, the wait() will return and the
system() call will either (a) return the exit status of the wrong child,
or (b) loop until the correct child terminates, meaning that you cannot
retrieve the exit status of the prior child(ren).  (The choice of methods,
(a) or (b), is made by the author of the library call and is not
necessarily consistent across library implementations.)

Quote:>Thanks in advance.
>Bill

The general rule is to not use system() at all.  There are too many
variables which can cause the code to execute incorrectly at best, and
unsecurely at worst.

Even simple, non-intrusive, "obvious" code can fail in mysterious ways.
For instance, the following won't work if the SHELL variable contains
/bin/csh (or some other shell which doesn't understand Bourne syntax).

    system("if [ -r filename ]; then echo Yes; else echo No; fi");

However, there are numerous cases where it is extremely convenient for the
shell to do wildcards and I/O redirection for you.  In this case, a more
appropriate call would be:

    pid_t pid;
    int stat;

    switch (pid = fork()) {
        case -1 : /* error */
            break;
        case 0  : /* child */
            execl("/bin/sh", "sh", "-c", "PATH=/usr/bin:/sbin ...");
            perror("execl");
            exit(1);
        default : /* parent */
            if (waitpid(pid, &stat, 0) != pid)
                /* error */
    }

Obviously, there's more to flesh out in this example.  See the W. Richard
Stevens book, _Advanced Programming in the Unix Environment_ for more
details.

--
Frank "Crash" Edwards      Edwards & Edwards Consulting
Voice:      813/786-3675   Unix/AIX-Sun-HP: Training, Programming, and SysAdmin

Outside FL: 500/HI-CRASH   (this is NOT toll-free, but is auto-forwarded to me)
    "The beast of Tenagra.  Rozauni; his army.  Chaka; when the walls fell."

 
 
 

set-uid wrapper in C

Post by Kazimir Kylhe » Sat, 27 May 1995 04:00:00




>It's easy to test a shell for this IFS behavior:
>ksh> IFS='/' /bin/sh -c '/bin/date'
>/bin/sh: bin: not found

GNU Bash will silently ignore assignments to IFS.

bash$ IFS='abc'
bash$ echo $IFS

bash$

--
"... nobody really knows what the Bourne shell's grammar is. Even examination
 of the source code is little help. "
-Tom Duff, "Rc -- A Shell for Plan 9 and UNIX Systems"

 
 
 

1. KSH: Help sought getting wrapper code to work in set-uid mode

A local wrapper application has started to fail.  I am trying to figure out
how to get it to work again.

The wrapper is designed to provide a cross platform layer.  The code
takes a look at uname's output, then constructs a pathname to the real
application, based on the output of uname.

It then does an
exec $newpath $arguments
type invocation to the appropriate application.

What we are seeing is that this works fine when invoked from normal scripts.
But if the script that invokes the wrapper is setuid, the effective
userid is being lost.

The peculiar thing is that this wrapper has not been modified for more
than 4 months.  It has been working daily.  The ksh that it uses hasn't
been changed for a year.

But in the past week or two, we started getting errors indicating that
the set-uid case was losing the different effective user-id.
If we change the script to skip the wrapper, and invoke the architecture
specific binary directly, things work just fine.  It would just mean
that we would have to expand the number of scripts we have - one for
each platform.

Is anyone familar with what kinds of conditions might cause ksh to throw
away set-uid bits - or at least what kinds of things I need to do in a ksh
script to ensure that the effective and real user-id gets passed along
to the binary being exec'd ?
--
<URL: http://wiki.tcl.tk/ > In God we trust.
Even if explicitly stated to the contrary, nothing in this posting
should be construed as representing my employer's opinions.

2. Partition Numbering Discrepancy

3. suidcgi - a set UID wrapper for CGI scripts.

4. SCO IDECD Installation

5. set uid with a c wrapper confusion

6. shell script problem

7. PPPD on Redhat requires set-uid root

8. Sawfish mouse click to raise windows

9. SET-UID command to become root?

10. SET-UID not working?

11. set-uid programs on a vold-mounted CD-ROM?

12. set-uid/file permissions of xlock and sys-suspend

13. Set-UID runtime libraries?