Niels Hald Pedersen wrote:

> > However: DO NOT DO THIS TO PROGRAMS WHICH WERE NOT DESIGNED TO BE
> > SETUID ROOT.
> > 
> > Setuid programs need to be written with security in mind. If you make
> > an ordinary program setuid root, you will probably allow every user on
> > the system to obtain full root privileges; i.e. they will be able to
> > execute any command whatsoever as root.
> 
> Could you comment on what the main points are in designing thus ? (the
> top five things NOT to do in a setuid root program, or whatever)

I don't know about the top five exactly, but important points are (in
no particular order):

1. Ensure that the program is bug-free. Especially, ensure that buffers 
can't be overrun. Doing something like:

        char buff[1024];
        strcpy(buff, getenv("TERM"));

is a definite no-no. A buffer overrun allows a user to execute
arbitrary code as the uid under which the program runs (including the
equivalent of exec("/bin/sh")).

2. Don't allow the program's behaviour to be controlled by the user,
except as specifically intended. Watch out for anything that can be
affected by environment variables. E.g. the tempnam() function will
use the TMPDIR variable if it is set. Particularly, don't call
system() without dropping privileges; there are a load of environment
variables that can be used to affect the result. Don't use execlp() or
execvp() without dropping privileges, as the user can set PATH to
whatever they like.

3. Check the permissions on any files that you open, unless you
explicitly intend to use your additional privileges.

A classic exploitable bug that occurred from not doing this was in
in.fingerd. It opened ~/.plan as root, and sent the contents to the
finger client. A user could make ~/.plan a symlink to some file which
they weren't supposed to have read privilege on (e.g. /etc/shadow),
and finger themself, thereby reading the contents of that file.

4. Be careful when creating new files in directories to which ordinary
users have write access (e.g. /tmp or home directories). Otherwise a
user can create a link (symlink or hard link) to some existing file,
and then have the suid program overrwrite that file.

5. Beware of race conditions when avoiding 3 or 4 above. Don't do:

        struct stat buf;
        stat(filename, &buf);
        // check contents of buf
        fd = open(filename, flags);

The file referred to by `filename' could have been created or replaced
between the stat() and the open(). Instead, open() the file first (NB:
don't use O_TRUNC), and then use fstat() on the descriptor. That way,
the information definitely refers to the file which you're going to be
reading/writing.

-- 
Glynn Clements <[EMAIL PROTECTED]>

Reply via email to