Path: utzoo!utgpu!water!watmath!clyde!rutgers!mit-eddie!bloom-beacon!think!ames!amdcad!sun!pitstop!sundc!seismo!uunet!munnari!kre From: kre@munnari.oz (Robert Elz) Newsgroups: comp.unix.wizards Subject: Re: setreuid() functionality in sysV Message-ID: <1962@munnari.oz> Date: 23 Jan 88 09:00:39 GMT References: <1988Jan19.192854.3411@jarvis.csri.toronto.edu> <172@hudson.acc.virginia.edu> Organization: Comp Sci, Melbourne Uni, Australia Lines: 61 In article <172@hudson.acc.virginia.edu>, slb@hudson.acc.virginia.edu (Sandy Bryant) writes: > Problem is that whenever *root* calls setuid(), > everything - real uid, effective uid, AND the saved set_user id field in > the user struct are all set to the new uid, so you can never go back to > being root again. To do otherwise creates a security hole, I guess. Not really. If a root process really wants to do something as another user, and then come back, it can easily enough in any case ... if (fork() == 0) { setuid(someome); do_whatever(); exit(0); } wait(&status); (plus some error checking) will do it every time. Allowing root to just switch uid's and then switch back cannot possibly create any bigger "security hole". Once you're root, security is gone anyway. I suspect that the reason for the limitation is just pragmatics, combined with a liberal dose of stupidity. The Sys V developers at AT&T saw the need (correctly) for this facility, (that is, real and effective uid switching) .. its been added to unix ever since Waterloo (and probably others) did it in V6. However, they seem to have a real phobia about adding anything new, so rather than add a new system call, which could have worked sanely, without annoying limitations, they just added the internal, hidden, saved set_user value, and allowed the old setuid() sys call to use that whenever it wanted. Now we get to the potential security hole ... From time immemorial (since Jan 1 00:00:00 1970 GMT ?) setuid processes have always believed that "setuid(getuid())" is a safe and permanent way to remove any special privileges they may have had, after which its safe to assume that no special checking on path names, etc, is needed. If a process that was setuid root did this, and the definition of setuid(getuid()) was changed to allow a later setuid(0), then a clever user might be able to break through all kinds of new security holes, that didn't used to exist. This is known as "breaking working programs", and is, naturally, something to be avoided. Thus the restriction: if a process that is setuid root does setuid(x), where x != 0, then all of the uid's are changed, and the security hole is closed. And for anyone silly enough to believe that the setuid bit could ever have been intended to be used with user id's other than zero, well, tough! This problem is even worse if the saved set_user id is retained through exec (which my V.2 man pages very cleverly neglect to say anything about, my V.3 manuals aren't accessible at the minute, so I can't check those). The moral: when you want to add something new, add something new, don't modify something that exists already, and pretend that everything is magically going to be compatible. kre