Bugtraq mailing list archives

Re: BoS: Re: XFree86 3.1.2 Security Problems


From: casper () holland Sun COM (Casper Dik)
Date: Thu, 1 Feb 1996 09:23:39 +0100


Folks,  I went through exactly the same thing when I developed the LPRng
print spooler package.  The solution that I used for the problem was as
follows:

1.  In the startup code,  use seteuid()/setreud() to set
   EUID to something banal such as daemon, and RUID to root.
   (you might want to save the original RUID for permissions checking).

The correct approach, though OS milage may vary.

On systems with saved user ids, it's usually best *not* to set the
ruid to another uid than the originally invoking userid and start you program
of with:


uid_t euid;

        main ...
        {
                euid = geteuid();
                seteuid(getuid());

when you require the set-uid powers you can then do:

                seteuid(euid);
                /* section requiring special powers;
                   bind to reserved port, open /etc/shadow
                 */
                seteuid(getuid());

(On some systems use setreuid(-1, euid); ... setreuid(-1, getuid());)
Again. this requires a saved uid mechanism (available in SVR4, SunOS 4 and
countless others)

You don't need to specifically reset the uids for an exec either
as the effective user id and real user id are always the invoking (or
non-dangerous) uid.  Coding like this also serve another useful purpose;
the casual user of the code can immediately see where the program
requires its special powers and why it needs to be set-uid in the
first place.

When you're no longer in need of having the powers at all you may
think of giving them up completely.  First of all, this is not
always possible.  (SVR4 doesn't allow you to do away the saved uid unless
you're root)

But *after* you've given away all powers (setreuid(getuid(),getuid())
or setuid(getuid())), you're vulnerable to a debugger attaching to the
process.  So if you totally give up all powers you need to
close all the special fds you had and destroy any special data (/etc/shadow).

It's often better to just keep the saved uid and not having to worry about
this.  Removing read access from the executable usually also prevents
the attack through debuggers.

After an exec, the saved uid will be gone anyway.

2.  Do all operations EXCEPT socket() and bind() calls as EUID daemon.
   It turns out that on some ^&*(*&*( systems when you want to bind
   to a reserved port,  you must open the socket EUID ROOT and to the
   bind EUID root.

SVR4 systes often have that problem.

3.  Before you do an exec,  do a seteuid/setuid
   to the original user and/or daemon UID (your application milage may
   vary on this).

With the saved set-uid model, you are running with euid==uid most of the time
and this step isn't necessary.

Obviously, special care ust be taken with signal handlers (don't know the
state of the uid) and in multithreaded apps (don't have multithreaded
set-uid apps).  Even implied multithreading (e.g., RPC servers with threads)
is dangerous if uid juggling is necessary.


Casper



Current thread: