Subject: Re: weird setuid behavior
To: Noriyuki Soda <soda@sra.co.jp>
From: David Laight <david@l8s.co.uk>
List: tech-kern
Date: 01/25/2004 20:47:48
On Sun, Jan 25, 2004 at 02:41:26PM -0500, Niels Provos wrote:
> On Fri, Jan 23, 2004 at 06:11:18PM +0900, Noriyuki Soda wrote:
> > I tested the program on NetBSD-1.4.2 and NetBSD-1.6_STABLE,
> > and the setuid(2) call failed on both systems with EPERM.
> > It failed on Solaris-2.6 and Linux-2.4, too.
> > 
> > Is such change really made at last year?

The code all changed, but the behaviour shouldn't have.

> I guess that I am mistaking, but then my question still remains,
> why can't setuid() set my uid to my euid?

Basically because that particular transition isn't allowed.

Each process has 3 uids, the 'real', 'effective' and 'saved'.
The 'saved' uid is set for setuid programs, and allows the process
to flip between the original and setuid values.
Permission checks are always done with the effective uid.

So your program would be running with:
	real_uid = 0   effective = 0   saved = 0
you call seteuid(100) and the become:
	real_uid = 0   effective = 100 saved = 0
you now try to call setuid(100), the man page clearly states:

  The setuid() function is permitted if the specified ID is equal to the
  real user ID of the process, or if the effective user ID is that of the
  super user.

So the request fails.
Note that the pair:
	setuid(0); setuid(100);
will (and does) work. As should:
	setruid(100); setuid(100);

Note also that setuid() is non-portable, see the notes on:
www.opengroup.org/onlinepubs/007904975/functions/setuid.html
					 
It is possible that Linux implements all the setxxxuid functions in terms
of a single system call that allows any user to set any of the uid values
to match any other.  Which could be where you thought it worked.

	David

-- 
David Laight: david@l8s.co.uk