Messages in this thread |  | | From | "A.N.Kuznetsov" <> | Subject | Re: BEWARE! Linux seteuid is broken! | Date | Sun, 16 Jun 1996 19:27:13 +0400 (MSD) |
| |
Hello!
> Huh? seteuid() was never implemented; it's not in 1.2.x. Cannot believe :-)...(searching through old kernels)... Yes. I'm sorry.
> > seteuid() is also not a POSIX function; it's not defined in POSIX. So > if you use it, you must be using it because you're interested in BSD > compliance. > > Keep in mind that the whole notion of "effective" uid is non-POSIX. So > trying to mix effective uid and saved-uid is invariably going to cause > problems. Formally, you are right. Reading Stevens's book, I missed word "proposed" before POSIX.1 and was sure that it is in POSIX.1. But really, the most important point is that POSIX.1 does not specify "super-user", so that in POSIX domain setuid() is exactly UNIX (BSD and SVR4, but not Linux) seteuid().
> I deliberately had setreuid() set the saved-uid because this > would seem to avoid certain security problems. See the comments in > kernel/sys.c for my justification for doing this.
Linux setreuid is broken too!!!
Example (from real life, it is function key_call() called from set-uid root program):
main() { int uid = getuid(); printf("%d %d\n", getuid(), geteuid()); seteuid(uid);
/* key_call */ printf("%d %d\n", getuid(), geteuid()); setreuid(uid,uid); printf("%d %d\n", getuid(), geteuid()); setreuid(uid,uid); printf("%d %d\n", getuid(), geteuid()); /* key_call returns */
seteuid(0); printf("%d %d\n", getuid(), geteuid()); }
BSD/SVR4 (2018 is my uid): 2018 0 2018 2018 2018 2018 2018 0
Linux: 2018 0 2018 2018 2018 2018 2018 2018
That's all. Linux faults. Until now I believed that it is one of numerous bugs in RPC library, but now I checked key_call under FreeBSD and Solaris. It works there. It is bug in Linux kernel.
Emulation of seteuid(.) by setreuid(-1,.) in libc is another bug. Moreover, it is impossible to emulate BSD/SVR4 (well, not POSIX :-)) seteuid() without kernel support.
Just compile the following program, make it set-uid root and run on any UNIX (I checked FreeBSD and Solaris2.3,2.4) and Linux:
main() { printf("%d %d\n", getuid(), geteuid()); seteuid(1); printf("%d %d\n", getuid(), geteuid()); seteuid(0); printf("%d %d\n", getuid(), geteuid()); }
BSD/SVR4 output: 2018 0 2018 1 2018 0
Linux output: 2018 0 2018 1 2018 1
Do you keep to insist that Linux uid handling is correct? 8)
Alexey Kuznetsov.
Example of correct seteuid/setreuid (FreeBSD).
struct seteuid_args { uid_t euid; }; /* ARGSUSED */ int seteuid(p, uap, retval) struct proc *p; struct seteuid_args *uap; int *retval; { register struct pcred *pc = p->p_cred; register uid_t euid; int error;
euid = uap->euid; if (euid != pc->p_ruid && euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) return (error); /* * Everything's okay, do it. Copy credentials so other references do * not see our changes. */ pc->pc_ucred = crcopy(pc->pc_ucred); pc->pc_ucred->cr_uid = euid; p->p_flag |= P_SUGID; return (0); }
struct setreuid_args { int ruid; int euid; }; /* ARGSUSED */ int setreuid(p, uap, retval) register struct proc *p; struct setreuid_args *uap; int *retval; { register struct pcred *pc = p->p_cred; struct seteuid_args args; int error;
if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid && uap->ruid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) return (error); if (uap->euid != (uid_t)-1 && pc->pc_ucred->cr_uid != uap->euid) { args.euid = uap->euid; if ((error = seteuid(p, &args, retval))) return (error); if (pc->pc_ucred->cr_uid != pc->p_ruid) pc->p_svuid = pc->pc_ucred->cr_uid; } if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid) { (void)chgproccnt(pc->p_ruid, -1); (void)chgproccnt(uap->ruid, 1); pc->p_ruid = uap->ruid; pc->p_svuid = pc->pc_ucred->cr_uid; p->p_flag |= P_SUGID; } return (0); }
|  |