Merge branch 'setresuid' into 'main'

Fix setuid testing for MacOS

See merge request tpo/core/arti!691
This commit is contained in:
Nick Mathewson 2022-08-25 11:42:00 +00:00
commit 709543bb48
1 changed files with 43 additions and 17 deletions

View File

@ -39,24 +39,50 @@ impl<'a, T: StateMgr + 'a> StateMgrUnlockGuard<'a, T> {
pub(crate) fn running_as_setuid() -> bool {
#[cfg(target_family = "unix")]
{
// Use `libc` to find our real, effective, and saved UIDs and GIDs.
let mut resuid = [0, 0, 0];
let mut resgid = [0, 0, 0];
unsafe {
// We ignore failures from getresuid or getresgid: these syscalls
// can only fail if we give them bad pointers, if they are disabled
// via a maddened sandbox, or something like that. In that case, we'll
// just assume that the user knows what they're doing.
let _ = libc::getresuid(&mut resuid[0], &mut resuid[1], &mut resuid[2]);
let _ = libc::getresgid(&mut resgid[0], &mut resgid[1], &mut resgid[2]);
}
#[cfg(not(target_os = "macos"))]
{
// Use `libc` to find our real, effective, and saved UIDs and GIDs.
//
// On systems with setresuid, a caller can (and people sometimes do)
// arrange for ruid==euid != saveduid, and that is still set-id:
// the process can retain privilege.
let mut resuid = [0, 0, 0];
let mut resgid = [0, 0, 0];
unsafe {
// We ignore failures from getresuid or getresgid: these syscalls
// can only fail if we give them bad pointers, if they are disabled
// via a maddened sandbox, or something like that. In that case, we'll
// just assume that the user knows what they're doing.
let _ = libc::getresuid(&mut resuid[0], &mut resuid[1], &mut resuid[2]);
let _ = libc::getresgid(&mut resgid[0], &mut resgid[1], &mut resgid[2]);
}
// The user can change any of their (real, effective, saved) IDs to any
// of their (real, effective, saved) IDs. Thus, privileges are elevated
// if there is any difference between these IDs.
let same_resuid = resuid.iter().all(|uid| uid == &resuid[0]);
let same_resgid = resgid.iter().all(|gid| gid == &resgid[0]);
!(same_resuid && same_resgid)
// The user can change any of their (real, effective, saved) IDs to any
// of their (real, effective, saved) IDs. Thus, privileges are elevated
// if there is any difference between these IDs.
let same_resuid = resuid.iter().all(|uid| uid == &resuid[0]);
let same_resgid = resgid.iter().all(|gid| gid == &resgid[0]);
!(same_resuid && same_resgid)
}
#[cfg(target_os = "macos")]
{
// Unaccountably, MacOS lacks setresuid/setresgid, which were invented literally
// decades ago to save people navigating the almost-incomprehensible swamp that is
// the behaviour of set{,e,re}{u,g}id.
//
// MacOS does actually *have* the saved set-id - you just can't find out what it is.
// I *think* it is even possible to create a situation where ruid==euid != saveduid.
// But it is not possible to detect it (other than maybe by experimentally
// guessing that saved set-id is zero and trying to seteuid(0) - a bad move).
//
// So, use test for euid==ruid instead, which is about the best we can do.
// We "sort of" ignore failures: in each case, we insist that both calls succeed,
// giving the same answer, or both calls fail. This ought to work well enough.
let same_reuid = libc::geteuid() == libc::getuid();
let same_regid = libc::getegid() == libc::getgid();
!(same_reuid && same_regid)
}
}
#[cfg(not(target_family = "unix"))]
{