Subject: Re: Emulating Ultrix setuid semantics
To: Chris G. Demetriou <cgd@alpha.bostic.com>
From: Theo de Raadt <deraadt@fsa.ca>
List: port-pmax
Date: 08/19/1994 22:14:53
> and it should do so _only_ in the ultrix compat code. (not only
Unfortunately not true. At the very least, SunOS compatibility needs
it fixed as well.
I suspect other compatibility packages will want it too. Didn't 0.9
have setreuid? If it did, the emulation in kern_prot.c isn't
sufficient. (BSDI binaries?) The code doesn't seem `correct' for the
COMPAT_43 case either.
Actually, I should have run into this problem in SunOS emulation
before. But.. SunOS binaries don't do setreuid(N, M) as often as
Ultrix does... SunOS doesn't have saved-ids either. I don't think 100%
emulation is neccessary or doable; just a bit more than is currently
in kern_prot.c. The, er, setreuid(N, N) case in particular.
> (not only
> that, if it does it there, it can do the emulation more cleanly,
> and without hacking up any common code.)
I think all the setreuid/setregid emulations are going to be
identical. I'm afraid someone might write a setreuid() implimentation
that hacks the euid directly, and create a case of uid != 0, euid == 0.
> (1) prohibit a person writing compat code from implementing
> them fully (though i'd argue against that), or
Exactly what I'm afraid of. I'd rather put a canonical "safe" version
in kern_prot.c. We're going to be leaving the COMPAT_43 code intact
for a time, no?
Here's an attempt at setreuid that I've been playing at..
#if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_ULTRIX)
struct setreuid_args {
int ruid;
int euid;
};
/* ARGSUSED */
osetreuid(p, uap, retval)
register struct proc *p;
struct setreuid_args *uap;
int *retval;
{
register struct pcred *pc = p->p_cred;
struct seteuid_args seuidargs;
struct setuid_args suidargs;
/*
* There are four cases, and we attempt to emulate them in
* the following fashion:
* -1, -1: return 0. This is correct emulation.
* -1, N: call seteuid(N). This is correct emulation.
* N, -1: if we called setuid(N), our euid would be changed
* to N as well. the theory is that we don't want to
* revoke root access yet, so we call seteuid(N)
* instead. This is incorrect emulation, but often
* suffices enough for binary compatibility.
* N, M: call setuid(N), and assume M==N. This is close to
* correct emulation.
*/
if (uap->ruid == (uid_t)-1) {
if (uap->euid == (uid_t)-1)
return (0); /* -1, -1 */
seuidargs.euid = uap->ruid; /* -1, N */
return (seteuid(p, &seuidargs, retval));
}
if (uap->euid == (uid_t)-1) {
if (uap->ruid != pc->p_ruid && /* N, -1 */
uap->ruid != pc->p_svuid)
return (EPERM);
seuidargs.euid = uap->ruid;
return (seteuid(p, &seuidargs, retval));
}
suidargs.uid = uap->ruid; /* N, M */
return (setuid(p, &suidargs, retval));
}
------------------------------------------------------------------------------