[comp.bugs.sys5] setuid

ccement@rivm.UUCP (Martien F v Steenbergen) (02/16/88)

According to the (System V) manuals from AT&T, Uniq, Nuxi and
Xenix the chapter about the setuid(2) system call lists:

	"...<Setuid> will fail if the real user ID of the
	calling process is not equal to <uid> and its effective
	user ID is not super-user. [EPERM]..."

If this is true, then the last command in the following sequence
should be unsuccessful (assuming the use of legal user IDs):

	$ pr -n -t setuidbug.c
	    1	extern int errno;
	    2	
	    3	main()
	    4	{
	    5		errno = 0;
	    6		if (setuid(100) == -1)
	    7			perror("setuid");
	    8		return 0;
	    9	}
	$ make setuidbug
	cc -O  setuidbug.c -o setuidbug
	$ chmod u+s setuidbug
	$ id
	uid=100(jim) gid=101(cce)
	$

...at this time jim logs out and john logs in...

	$ ls -l setuidbug
	-rwsr-xr-x   1 jim      cce         3295 Feb 16 09:04 setuidbug
	$ id
	uid=139(john) gid=171(pharm)
	$ setuidbug
	$

This last setuidbug call should result in something like:

	setuid: Not owner

but it doesn't. So there's either a bug in Unix or in the manuals
(or in me?). (This bug won't do you any harm, it results in a no op.)
Comment please.


Martien.
________________________________________________________________
Martien F. van Steenbergen
National Institute of Public Health and Environmental Protection
dept. RIVM/CCE
PO Box 1
3720 BA Bilthoven
The Netherlands

tel: (31) 30 742819
email: ...!mcvax!rivm!martien
___________________________MSDOSN'T_____________________________

rikki)) (02/18/88)

From article <679@rivm05.UUCP>, by ccement@rivm.UUCP (Martien F v Steenbergen):
> 
> According to the (System V) manuals from AT&T, Uniq, Nuxi and
> Xenix the chapter about the setuid(2) system call lists:
> 
> 	"...<Setuid> will fail if the real user ID of the
> 	calling process is not equal to <uid> and its effective
> 	user ID is not super-user. [EPERM]..."
> 
The paragraph right before the above says:

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

	By having the setuid bit on in the executable, you are forcing
the job to run as jim (effective ID = 100) which is equal to <uid>.  Looks
like it does what it should to me.

-- 
Rikki Welsh
Centel Information Systems
5515 Security Lane, Rockville, Maryland, 20852, (301) 984-3636
UUCP:	decuac!macom1!rikki

jonl@sco.COM (ScoMole #192-1232A) (02/20/88)

+-I seem to recall ccement@rivm.UUCP (Martien F v Steenbergen) writing:
|
| According to the (System V) manuals from AT&T, Uniq, Nuxi and
| Xenix the chapter about the setuid(2) system call lists:
| 
| 	"...<Setuid> will fail if the real user ID of the
| 	calling process is not equal to <uid> and its effective
| 	user ID is not super-user. [EPERM]..."
| 
| If this is true, then the last command in the following sequence
| should be unsuccessful (assuming the use of legal user IDs):
| 
| 	< short program and exmaples deleted >
| 
| Comment please.
| 
| Martien.

Hmm. I tried out your example, and it appears that only one's effective uid
must be equal to "uid" in 'setuid (uid)', and the chmod u+s on the executeable
set that to be true. It seems to me that this is how it should work and the
documentation should be changed. off hand, i don't see any kind of security
problem with only checking for the effective uid instead of the real uid.
After all, who really needs to set their uid to what it already is?

if a fish's eye was a telephone pole, it would swim lopsided.
===============================================================================
jon luini || WORK: 408-425-7222    || HOME: 408-423-2917
Disclaimer|| You don't think SCO would agree with THAT, do you?????
Work:     || jonl@sco.com          || ...!{uunet, ihnp4, ucbvax!ucscc}!sco!jonl
Evil:     || niteowl@ssyx.ucsc.edu || ...!{ucbvax}!ucscc!ssyx!niteowl
===============================================================================

bsteve@occrsh.ATT.COM (02/23/88)

The program gives the expected response on my 3b2 running SVR3.1. Could
this be a bug from a previous release or a bug in a particular vendor
kernel implementation?

  Steve Blasingame ihnp4!gorgo!bsteve (bsteve@gorgo.att.com)
  AT&T Itasca, Illinois
  (312) 250-5376

igb@Fulcrum.BT.CO.UK (Ian G Batten) (03/15/89)

Should the following program work or not, on System Five?  This is a
common idiom in the source code of HoneyDanber uucp, and two local System
Five machines refuse to honour the second setuid.  The manual page implies
they should.  Please, no flames --- just mail me an answer.  I've been
sweating blood over the code all day and I hope I can lodge this as a
kernel problem.

ian

main ()
{
  int uid, euid;

  printf ("uid = %d; euid = %d\n", uid = getuid (), euid = geteuid ());
  if (setuid (uid) != 0)
    perror ("setuid (uid)");
  printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
  if (setuid (euid) != 0)
    perror ("setuid (euid)");
  printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
}
-- 
Ian G Batten, BT Fulcrum - igb@fulcrum.bt.co.uk - ...!uunet!ukc!fulcrum!igb

les@chinet.chi.il.us (Leslie Mikesell) (03/18/89)

In article <123@cat.Fulcrum.BT.CO.UK> igb@Fulcrum.BT.CO.UK (Ian G Batten) writes:

>Should the following program work or not, on System Five?  This is a
>common idiom in the source code of HoneyDanber uucp, and two local System
>Five machines refuse to honour the second setuid.  The manual page implies
>they should.  Please, no flames --- just mail me an answer.  I've been
>sweating blood over the code all day and I hope I can lodge this as a
>kernel problem.

 >main ()
 >{
 >  int uid, euid;
 >
 >  printf ("uid = %d; euid = %d\n", uid = getuid (), euid = geteuid ());
 >  if (setuid (uid) != 0)
 >    perror ("setuid (uid)");
 >  printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
 >  if (setuid (euid) != 0)
 >    perror ("setuid (euid)");
 >  printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
 >}

If your current effective uid is 0 and you execute setuid(anything_but_0) then
there is no way back.  Other combinations of different uid and euid
can flip back and forth as desired.  You have to fork off a child
process if you are root and want to do something as another id and
go back to being root (or just assume that root's permissions are
sufficient anyway and chown() any files that you create..)

Les Mikesell

dwd@cbnewsc.ATT.COM (david.w.dykstra) (03/21/89)

From article <123@cat.Fulcrum.BT.CO.UK>, by igb@Fulcrum.BT.CO.UK (Ian G Batten):
- 
- Should the following program work or not, on System Five?  This is a
- common idiom in the source code of HoneyDanber uucp, and two local System
- Five machines refuse to honour the second setuid. 
- 
- main ()
- {
-   int uid, euid;
- 
-   printf ("uid = %d; euid = %d\n", uid = getuid (), euid = geteuid ());
-   if (setuid (uid) != 0)
-     perror ("setuid (uid)");
-   printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
-   if (setuid (euid) != 0)
-     perror ("setuid (euid)");
-   printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
- }
This works on my System V 3.2.1 system only if the program is not
set-uid to root.  If it is set-uid to something else (like uucp in the
HoneyDanber stuff) then it works.  I'm not sure why it shouldn't work
for root.

- Dave Dykstra
  AT&T Bell Labs, Skokie, IL   att!ttrdf!dwd

jeffj@pedsga.UUCP (03/21/89)

In Message-ID: <123@cat.Fulcrum.BT.CO.UK>, Ian G Batten asks:
>Should the following program work or not, on System Five?  This is a
>common idiom in the source code of HoneyDanber uucp, and two local System
>Five machines refuse to honour the second setuid.  The manual page implies
>they should.  Please, no flames --- just mail me an answer.  I've been
>sweating blood over the code all day and I hope I can lodge this as a
>kernel problem.
>
>ian
>
>main ()
>{
>  int uid, euid;
>
>  printf ("uid = %d; euid = %d\n", uid = getuid (), euid = geteuid ());
>  if (setuid (uid) != 0)
>    perror ("setuid (uid)");
>  printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
>  if (setuid (euid) != 0)
>    perror ("setuid (euid)");
>  printf ("uid = %d; euid = %d\n", getuid (), geteuid ());
>}
>-- 

Sounds like a kernel bug to me.
A problem setting the SAVED SET-UID to be precise.
Let me explain:

Assuming this is not run as UID 0, let's look at the manual.
A process has a REAL UID that identifies the person running the process.
	Only root can change this, so this is invariant.
The EFFECTIVE UID determines the permissions.
	It is the same as the REAL UID, unless the SET UID bit is on,
	then the EFFECTIVE UID is that of the file.
The SAVED SET-UID is the effective UID of the process before
	an exec().  If the previous process was not SET-UID,
	the SAVED-SET UID is the same as the effective UID.
	This is to allow the effective UID to alternate between
	the real UID and its previous value.

So, setuid() as a non-root allows the process to set the EFFECTIVE
UID to the REAL UID, or the SAVED UID.

Let's say this a.out has no set-uid.
This runs okay, telling me uid=euid=44 all the time.

Now try this a.out set-UID 44, run it as UID 33.
The output is
	REAL	EFFECTIVE
	33	44
	33	33
	33	44
The first setuid sets the effective UID from 44 to the real (33).
Now you want to set it back.
The secret hidden SAVED SET-UID holds the UID 44, so the second call
succeeds.  Unless, of course, this was exec'd from something
set-UID something-not-UID 44.
Perhaps crash(1M) displays the saved set-uid?
Perhaps the saved-uid was erroneously set to the real UID?

__________
		UN*X
		UNIX (ver 6, ver 7, PWB, Sys III, Sys V)
		AIX
		BSD (4.0, 4.1, 4.2, 4.3)
		MINIX
		REGIS
		RTU
		T/PIX
		ULTRIX
		UTS
		VNIX
		XENIX
		XINU
		your-version-here
	
Jeffrey Jonas

INTERNET: jeffj@pedsga.tinton.ccur.com
USENET: allegra!io!mtune ---------> petsd!pedsga!jeffj
        decvax!mcnc!rutgers _____/

stevea@laidbak.UUCP (Steve Alexander) (03/22/89)

In article <822@pedsga.UUCP> jeffj@pedsga.UUCP writes:
>Perhaps the saved-uid was erroneously set to the real UID?

I believe that if the current effective id is root, the saved set-uid is set to
the new uid along with the effective uid and the real uid when the setuid() is 
done.  Thus, the following will not work:

	root -> user -> root

This is only true for effective uid 0.  Otherwise, the saved set-uid is
left alone.

For non-zero uid's, the setuid() proceeds if the new uid is equal to
either the real uid or the saved set-uid.

-- 
Steve Alexander, TCP/IP Development | stevea%laidbak@sun.com
Lachman Associates, Inc.            | ...!sun!laidbak!stevea

guy@auspex.UUCP (Guy Harris) (03/24/89)

>This works on my System V 3.2.1 system only if the program is not
>set-uid to root.  If it is set-uid to something else (like uucp in the
>HoneyDanber stuff) then it works.  I'm not sure why it shouldn't work
>for root.

It shouldn't work for root because they decided not to make it work for
root.

The problem is that "setuid" can mean two things:

	1) "I'm running set-UID, but want to change back - possibly
	   temporarily - to my real UID, and then be able to change to
	   my original set-UID effective UID again;"

	2) "I'm a program such as 'login', and am running as root; I
	   want to set the user ID for a newly created session - real,
	   effective, and original set-UID effective UIDs - to some
	   value."

(The "original set-UID effective UID" is generally referred to as
something like the "saved set-user ID" in S5 documentation.)

Instead of providing new calls based on the 4.2BSD "setreuid" call -
that call can independently set the real and effective UIDs, and can be
told to leave one of the UIDs alone by supplying -1 as an argument -
they overloaded "setuid".  They did so by making it act differently for
an effective UID of 0 (or maybe it was real UID, our S5R3 sources aren't
on-line at the moment) than for other effective UIDs.

I suspect S5R4 and 4.4BSD may end up following the SunOS lead on this
one; "setreuid" was enhanced to support an S5-style "saved set-user ID",
so that you can do the following in a set-UID program:

	ruid = getuid();
	euid = geteuid();
	<stuff with the effective user ID equal to the set-user ID>
	seteuid(ruid);
	<stuff with the effective user ID equal to the real user ID>
	seteuid(euid);
	<stuff with the effective user ID equal to the set-user ID>

regardless of whether the effective or real user ID is 0 or not.

Both BSD and S5 flavors of "setuid" can be implemented atop "setreuid".

davidsen@steinmetz.ge.com (Wm. E. Davidsen Jr) (03/24/89)

  The setuid behavior gets to be a real pain in the case where a program
is running setuid (not root) and needs to run another program to perform
some task. The execed program runs with its uid and euid set to the uid
rather than the euid, and there's no reasonable way to change this, such
as setuid(geteuid()) in BSD.

  I hit this all the time on a BBS, where the bbs program runs setuid to
the BBS uid, and a file transfer using a protocol program is to be done.
I found a way by it, but it's ugly, and the only thing in the whole
system which requires root permission (to install not run).
-- 
	bill davidsen		(wedu@crd.GE.COM)
  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/24/89)

In article <1196@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>Both BSD and S5 flavors of "setuid" can be implemented atop "setreuid".

I don't think the "saved set-UID" feature can be emulated using setreuid().
Ron Natalie and I looked into this a few years ago and decided that a
simple semantic extension to setreuid() could be made that would enable
full emulation of saved set-UID, and that our extension would not cause
any new security holes.  However, we never got around to it and I have
since forgotten the details.  Maybe for 4.4BSD?

aeh@j.cc.purdue.edu (Dale Talcott) (03/25/89)

> It shouldn't work for root because they decided not to make it work for
> root.

Does anyone know what security holes are plugged by this behavior?  We
have some applications where it would be nice to be able to bounce back
and forth between root and a given user.  Before I change the kernel,
though, it would be prudent to know what I'm letting us in for.

From looking at the source, it seems as if the only processes which end
up with curtailed permissions because of the SYS V behavior are the
current process (which has root permission already until it setuid()'s
to something else) and its children, until they exec().

Protecting one part of a program from other parts of itself doesn't make
sense to me, so there must be a backdoor I am missing.  Can someone shed
some light?

Dale Talcott, Purdue University Computing Center
aeh@j.cc.purdue.edu, j.cc.purdue.edu!aeh, aeh@purccvm.bitnet

les@chinet.chi.il.us (Leslie Mikesell) (03/26/89)

In article <13416@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
>
>  The setuid behavior gets to be a real pain in the case where a program
>is running setuid (not root) and needs to run another program to perform
>some task. The execed program runs with its uid and euid set to the uid
>rather than the euid, and there's no reasonable way to change this, such
>as setuid(geteuid()) in BSD.

I've had similar problems trying to bundle files with cpio and using
uux to restore them at other sites.  The problem is that cpio runs
/bin/mkdir (even under SysVr3 where it doesn't have to) to create
any needed directories, and /bin/mkdir decides that the owner should
be the real uid.  The real uid of uux is likely to be anyone who
recently sent mail, so the next time something is delivered to that
directory, uux (same euid, different real uid) can't write there.
The only way I can make this work without putting setuid programs
on other people's machines is to make sure all the directories are
writable by everyone before cpio'ing them.

Les Mikesell

les@chinet.chi.il.us (Leslie Mikesell) (03/26/89)

In article <9915@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:

>>Both BSD and S5 flavors of "setuid" can be implemented atop "setreuid".

>I don't think the "saved set-UID" feature can be emulated using setreuid().
>Ron Natalie and I looked into this a few years ago and decided that a
>simple semantic extension to setreuid() could be made that would enable
>full emulation of saved set-UID, and that our extension would not cause
>any new security holes.

How about a 3-argument function to set effective, real, and saved set-uid
that is only allowed for root.  Then a process running as root could
start a child which would be allowed to flip between two different ids,
neither required to be 0. 


Les Mikesell

guy@auspex.UUCP (Guy Harris) (03/26/89)

>>Both BSD and S5 flavors of "setuid" can be implemented atop "setreuid".
>
>I don't think the "saved set-UID" feature can be emulated using
>setreuid().

OK, let me state it better, making explicit an implicit part of my
statement:

	Both BSD and S5 flavors of "setuid" can be (and have been)
	implemented atop "setreuid" *if you put the saved set-UID
	feature into your system in the fashion described in my
	article in the parts preceding the statement.*

This isn't emulating the saved set-user ID feature using a vanilla
"setreuid"; it's emulating both the BSD and S5 behaviors of "setuid"
atop a "setreuid" that works with a saved set-user ID feature already in
the system.

>Maybe for 4.4BSD?

As I said, they may end up picking up a SunOS-style "saved set-user ID"
implementation (as I presume S5R4 will).

chris@mimsy.UUCP (Chris Torek) (03/26/89)

>In article <1196@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>>Both BSD and S5 flavors of "setuid" can be implemented atop "setreuid".

In article <9915@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>I don't think the "saved set-UID" feature can be emulated using setreuid().

If you are willing to substitute your own getuid(), geteuid(), and
access() for the `real' versions, it can.  (Obviously you also have
to substitute setuid and seteuid.)

In any case, Mike K. has talked about having 4.4 have `saved setuid
done right'.  The real problem with the SysV version is that it
overloads setuid(), and can tell `set all IDs including saved effective
uid' from `set real and effective uid' only when the caller is not root.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy@auspex.UUCP (Guy Harris) (03/27/89)

>Does anyone know what security holes are plugged by this behavior?

Are you assuming the reason that behavior was specified was to plug
security holes? As far as I know, there *aren't* any security holes
plugged by that behavior, and that the reason it was specified wasn't
security - it was backwards compatibility with programs such as "su"
that ran set-UID "root" and that used "setuid" to set the effective
*and* real UIDs to that of the specified user; those programs were
trying to create a new environment with that UID, and would want to set
all the UIDs, including the saved set-user ID, to the specified value. 

>Protecting one part of a program from other parts of itself doesn't make
>sense to me, so there must be a backdoor I am missing.

Why do you assume that there is such a backdoor, or that you're missing
something? Perhaps it was System V that was missing something, namely a
procedure that can be told explicitly to set only the effective UID or
to set all the UIDs for a process. 

rml@hpfcdc.HP.COM (Bob Lenk) (04/05/89)

As numerous folks have said, the saved ID is overwritten when the euid
of the calling process is 0.  Also, in System V Release 2 (all versions
that I know of) a call to setuid(0) was never honored for a
non-superuser, even if the saved uid is 0.  This was not documented, and
I never understood or ascertained a good reason for this, and it was
apparently changed in release 3.  This could explain why one System V
port did not work the same as another.

		Bob Lenk
		hplabs!hpfcla!rml
		rml%hpfcla@hplabs.hp.com