Subject: Re: setreuid() and setregid()
To: der Mouse <mouse@Collatz.McRCIM.McGill.EDU>
From: Greg Hudson <ghudson@mit.edu>
List: tech-kern
Date: 05/25/1996 12:17:35
(Apologies if I'm one of N people to respond.)

> So, I can almost hear you saying, why bother with having multiple
> UIDs at all?  The first need is for the ruid, so that a setuid
> program can tell who invoked it.  The suid one arguably does not
> actually need; I don't quite understand why POSIX added it, but like
> the other POSIX braindamages, we appear to be stuck with it for now,
> because it's not quite braindamaged enough to make core dump it.

The saved uid is not present in NetBSD because of POSIX.  In fact,
NetBSD does not define _POSIX_SAVED_IDS, because of a disagreement
over what should happen to setuid executables owned by someone other
than root (POSIX makes it impossible to permanently revoke the
privileges of the non-root user you're setuid to without doing an
exec()).  We have the saved uid for the sake of allowing a process to
temporarily revoke privileges without corrupting the purpose of the
ruid.

	POSIX model (with "process having appropriate privileges"
	interpreted as "process euid is 0"):

		- For a setuid root executable, setuid(getuid())
		  permanently revokes root privileges, setting
		  suid=euid=ruid.
		- For a setuid joe executable, setuid(getuid())
		  temporarily revokes joe privileges, setting
		  euid=ruid.  (exec() sets suid=euid, but short of
		  that, you can't avoid having an suid of joe.)

		It's becoming increasingly clear to me that the POSIX
		model is dictated by a particular interpretation of
		the C2 security guidelines; revoking joe privileges is
		not "lowering your clearance," so you can do it
		temporarily, but revoking root privileges is, so you
		can only do it permanently.

	NetBSD model:

		- For all setuid executables, setuid(getuid())
		  permanently revokes privileges, setting
		  suid=euid=ruid.
		- For all setuid executables, seteuid(getuid())
		  temporarily revokes privileges, setting euid=ruid.

Fortunately, the NetBSD model is consistent with the POSIX model
(albeit without defining _POSIX_SAVED_IDS, so you have to explicitly
test for NetBSD) for the case of setuid root executables.

> The reasons for allowing a setuid process to switch its uid back to
> that of the invoker while still retaining the potential to return to
> what it had are (a) convenience of programming - it limits, to some
> extent, the damage bugs can do, and (b) the closing of some race
> windows.

(a) is not a terribly useful guideline, since any stack-smash bug can
be exploited to do a setuid() back to root.  (b) is the important
issue; there are cases where you really want to do operations as a
non-root user (making sure you don't do anything to the filesystem
that said user can't do) before you're ready to revoke root
privileges.  Doing a fork() and setuid() for such operations doesn't
always work when there are library interfaces in the way.