[comp.unix.wizards] 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_____________________________

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
===============================================================================

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

root@spdyne.UUCP (03/21/89)

In article <123@cat.Fulcrum.BT.CO.UK> igb@Fulcrum.BT.CO.UK (Ian 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.

    I know that on BSD they added a very useful call: setreuid, which
allows the setting of both real and effective uid.  [I'm pretty sure that
I got that name right, but it's been 4 years since I did anything with BSD]
I seem to remember a fantastic call that switched your uid and euid! This
was a VERY good idea on someone's part!

    What I want to be able to do is this:

From program SETUID Notes, Switch to UID of person who ran program [Real UID]

old_uid = geteuid(); - Save the UID of the Notes.

setuid (getuid ()) - Switch to UID of original person.
                     Save a file to disk, with access restricted whatever the
                     original person had.

setuid (old_uid)   - Get back to Notes effective uid.

    The last one will of course fail.  [The notes source as posted has the
problem that if you want to save a file, you have to have the notes account
have write access to the directory that you want to save it in.]


If I understand the manuals correctly:

   Uid    Euid        (2 = original user id, program setuid to uid 3)

    2        3

setuid (2)

    2        2        Manual says it changes BOTH.. Bummer!

[Save file/whatever]
setuid (3)
    2        2        Will fail as neither your Real or your Effective UID is
                      3 anymore.

    Any solutions?

        -Chert Pellett
         root@spdyne

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

jfh@rpp386.Dallas.TX.US (John F. Haugh II) (03/22/89)

In article <1800008@spdyne> root@spdyne.UUCP writes:
>    I know that on BSD they added a very useful call: setreuid, which
>allows the setting of both real and effective uid.  [I'm pretty sure that
>I got that name right, but it's been 4 years since I did anything with BSD]
>I seem to remember a fantastic call that switched your uid and euid! This
>was a VERY good idea on someone's part!

setreuid()  allows you to specify both the real and the effective UID's
separately.  The syntax from the manpage is

setreuid (ruid, euid)
int ruid, euid;

where ruid and euid are the real and effective UID's respectively.

This system call only allows you to change the effective UID to the
real UID, unless you are root.
-- 
John F. Haugh II                        +-Quote of the Week:-------------------
VoiceNet: (214) 250-3311   Data: -6272  | "Do not drink and bake"
InterNet: jfh@rpp386.Dallas.TX.US       |         -- Arnold Swartzenegger
UucpNet : <backbone>!killer!rpp386!jfh  +--------------------------------------

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".

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

>If I understand the manuals correctly:

The old manuals, anyway.  The new manuals should explain the new version
of "setuid", which uses the "saved set-user ID", which is set when a
set-UID program is executed.  It basically remembers to whom the process
was originally set-UID, so that if you do

	setuid(real uid);

it still remembers that you had some other effective UID and thus lets
you do

	setuid(effective uid);

later.  Unfortunately, for reasons given in another posting, a

	setuid(0);

will set the "saved set-user ID" to 0, so you can't go home again.

By adopting the "setreuid" call mentioned earlier in your posting, S5R4
may end up fixing this (again, see my other posting).

>    Any solutions?
>
>        -Chert Pellett
>         root@spdyne

Yes, just keep running as "root", and you won't have to worry about any
of this - if you're "root", you shouldn't have to bother with set-UID
stuff at all, right? :-)

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?

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

root@spdyne.UUCP (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".

How about:

    setuid (id);                /* old method, not of much use... */

    setruid (real uid);         /* ONLY change the real uid */
    seteuid (Eff uid);          /* ONLY change the effective uid */
    setsuid (Saved - Set-uid);  /* ONLY change the saved set-uid */


This would enable people to write easy to follow, easy to write programs
that run setuid and do I/O that runs as the original user.  None of this
Junk about root being special...


    -Chert Pellett
     root@spdyne.... Or chert@spdyne if you are setuid...:-)

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

rbj@dsys.icst.nbs.gov (Root Boy Jim) (05/10/89)

? From: Doug Gwyn  <gwyn@smoke.brl.mil>
? Date: 24 Mar 89 14:45:30 GMT

? 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?

Have y'all suddenly become economists? :-)

Actually, none of this really matters. Saved set-UID's are merely
convenient. If root wants to do something as l'user, he can just
fork and give away his privilege. The parent is still privileged.

	Root Boy Jim is what I am
	Are you what you are or what?

les@chinet.chi.il.us (Leslie Mikesell) (05/12/89)

In article <19534@adm.BRL.MIL> rbj@dsys.icst.nbs.gov (Root Boy Jim) writes:

>Actually, none of this really matters. Saved set-UID's are merely
>convenient. If root wants to do something as l'user, he can just
>fork and give away his privilege. The parent is still privileged.

Yeah, and it's merely inconvenient that the program has to have a
very different way to determine the results of the activity of the
forked child than what would be used it the program did the work
itself.  Fortunately, root's permissions are usually sufficient for
most things...

Les Mikesell

steve@nuchat.UUCP (Steve Nuchia) (05/16/89)

In article <19534@adm.BRL.MIL> rbj@dsys.icst.nbs.gov (Root Boy Jim) writes:
>? In article <1196@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>? >Both BSD and S5 flavors of "setuid" can be implemented atop "setreuid".

>Actually, none of this really matters. Saved set-UID's are merely
>convenient. If root wants to do something as l'user, he can just
>fork and give away his privilege. The parent is still privileged.

Not all setuid programs want to be setuid root.  The principle
of least priveledge argues for most of them not being owned by root.

Being able to keep both userids (invoker and owner) around is
enormously convenient and leads to better (more secure) utility
programs.
-- 
Steve Nuchia	      South Coast Computing Services
uunet!nuchat!steve    POB 890952  Houston, Texas  77289
(713) 964 2462	      Consultation & Systems, Support for PD Software.

skl@van-bc.UUCP (Samuel Lam) (10/10/89)

Could some setuid() or Xenix expert please help?

I am trying to port the letest (Rick Adams) version of the Berkeley FTP
server to run on SCO Xenix 386 2.3.2 and need to imitate the seteuid()
calls in the code with setuid()'s, since Xenix doesn't have seteuid().

What I need to be able to do is essentially the following:

 - Start with euid(root).
 - ...
 - Switch to euid(arbitrary_uid).
 - ...
 - Revert back to euid(root).
 - ...

Through the course of the program, the real uid can either remain
root or switches following the euid.

I have already spent part of the night trying out various schemes
which I thought would work, but none of them did -- I always had
trouble switching back to root after switching to the arbitrary
uid.  Could someone tell me how this is done?

Thank you very much for your help.

...Sam
-- 
Samuel Lam     <skl@wimsey.bc.ca> or {uunet,ubc-cs}!wimsey.bc.ca!skl

ghelmer@dsuvax.uucp (Guy Helmer) (03/08/91)

I've modified MINIX to allow one to allow a program to set the user id to
the effective user id.  I've seen some obscure references that say this
might be a security problem.  My question: is there a good reason
to not allow setuid(geteuid())?

-- 
Guy Helmer                       | helmer@sdnet.bitnet
Dakota State University          | dsuvax!ghelmer@wunoc.wustl.edu
(605) 256-5264, (605) 256-2788   | uunet!dsuvax!ghelmer