[net.bugs.usg] Problems with setuid

tim@siedap.UUCP (09/22/86)

The setuid() system call under SVr2v2 (on a 3B2) doesn't seem to do
one thing which the manual claims it does :

> If the effective user id of the calling process is not super-user,
> but the saved set-user (group) ID from exec(2) is equal to uid (gid),
> the effective user (group) ID is set to uid (gid).

I'm using a process which has set-uid to root; first I want to
change my id's to a project id to read project data, and then
back to those of the caller (to read his files). On BSD this
works fine - you toggle real and eff. via setre(g/u)id. But I
can't for the life of me get any effect on SVr2v2 which would
approximate to what the manual claims is possible.

HELP !!!!!! (I've got a deadline for this stuff ...)

Repeat-by :
Compile this short test program, install it set-uid to root,
and run it. Play around with the calls to reset to the users id's.

------------ 8< -------------------8< ----------------

#include <stdio.h>
main()
{
int c_uid, c_gid;

c_uid = getuid() ;
c_gid = getgid() ;

printf("Real uid = %d\n",getuid()) ;
printf("Eff. uid = %d\n",geteuid()) ;
printf("Real gid = %d\n",getgid()) ;
printf("Eff. gid = %d\n",getegid()) ;

/* Set other id's */
if (setgid(555) != 0)
   {
   printf("setgid proj\n") ;
   exit(0) ;
   }
else ;
if (setuid(555) != 0)
   {
   printf("setuid proj\n") ;
   exit(0) ;
   }
else ;

printf("Real uid = %d\n",getuid()) ;
printf("Eff. uid = %d\n",geteuid()) ;
printf("Real gid = %d\n",getgid()) ;
printf("Eff. gid = %d\n",getegid()) ;

/* Reset caller's id's */
if (setuid(0) != 0)    /* THIS WAS set-user ID from exec ??? */
   {
   printf("setuid 0\n") ;
   exit(0) ;
   }
else ;
if (setgid(c_gid) != 0)
   {
   printf("setgid user\n") ;
   exit(0) ;
   }
else ;
if (setuid(c_uid) != 0)
   {
   printf("setuid user\n") ;
   exit(0) ;
   }
else ;

exit(0) ;
}

rfrye@netxcom.UUCP (Rob Frye) (09/25/86)

In article <4100002@siedap.UUCP>, tim@siedap.UUCP writes:
> 
> The setuid() system call under SVr2v2 (on a 3B2) doesn't seem to do
> one thing which the manual claims it does :
> 
> > If the effective user id of the calling process is not super-user,
> > but the saved set-user (group) ID from exec(2) is equal to uid (gid),
> > the effective user (group) ID is set to uid (gid).
> 
> I'm using a process which has set-uid to root;

[ other info and code example given ]

Same is true on Xenix System V -- apparently you can give up root priv's
by turning on the set-uid bit on an executable owned by someone other
than root, but you can't get them back by doing a setuid() back to
the real uid of 0.  It does work correctly for all other real uid's.

Of course, if you're already root, why give up the privileges in the
first place?  (ie -- don't run setuid programs!)  In our case, we
just set the set-gid bit and have our directories and files 775 mode
for that group -- a normal user executing things becomes real/effective
uid = theirs, real gid = theirs, effective gid = gid of "DS".  When
root runs it, same thing happens and real/effective UID of 0 still
keeps all priv's!
-- 
---

"You can Telenet, but you can't tell it much!"

rml@hpfcdc.HP.COM (Bob Lenk) (09/26/86)

The manual does not reflect the implementation in three areas:

	1) If the caller's effective uid is 0, setuid sets
	   all of the effective, real, and saved uids.  Thus
	   there is no way to toggle back.

	2) A setuid(0) call fails if the current effective uid
	   is not 0, even if the real uid or saved set-user id
	   is 0 (the latter is actually impossible because of 
	   (1) above).

	3) The saved set-group id is not implemented.

This is true of all variants of S5R2 that I have seen (not necessarily
all versions that exist).  I believe that (2) and (3) are changed in
S5R3.  It seems that (1) causes your problems (although you would run
into (2) if (1) did not exist).

One possible workaround is to fork a child process and have it
setuid(getuid()) and do the file access.  Another is to use access(2).

		Bob Lenk
		{hplabs, ihnp4}!hpfcla!rml

guy@sun.uucp (Guy Harris) (09/26/86)

> Same is true on Xenix System V -- apparently you can give up root priv's
> by turning on the set-uid bit on an executable owned by someone other
> than root, but you can't get them back by doing a setuid() back to
> the real uid of 0.  It does work correctly for all other real uid's.

This is true on S5 as distributed by AT&T-IS, and presumably Microsoft left
that code alone.  The trouble is that there are really at least *two
different* "setuid" operations in modern UNIX systems:  one that sets the
real *and* effective *and* saved set-user IDs - this one is used by "login"
and "su", for setting the environment of a user - and one that sets *only*
the effective ID, used for giving up or regaining privileges in a set-UID
program.

Unfortunately, System V isn't modern enough; they didn't pick up the 4.2BSD
"setreuid" system call, which permits you to set both user IDs
independently.  Instead, they overloaded "setuid".  If the argument to
"setuid" is non-zero, and it matches either the real or saved set-user ID,
it is treated as the second kind of "setuid", which sets only the effective
UID.  Otherwise, it is treated as the first kind of "setuid", which sets
them both; this version is, of course, restricted to the super-user.

Thus, "setuid(0)" is always treated as the first kind of "setuid", and since
the set-UID program's effective UID isn't root, it fails.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)