I don't know issetugid()
, but I can learn by reading BSD or Solaris manual pages. The function comes from OpenBSD.
1) OpenBSD's manual for issetugid(2) says, "The issetugid() function returns 1 if the process was made setuid or setgid as the result of the last or other previous execve() system calls. Otherwise it returns 0." It then suggests using issetugid() to check whether files named in environment variables are safe to open.
2) No, your Linux and Solaris code are not equivalent. A process running setuid might set its real uid to its effective uid without cleaning its environment variables. For example, uid_t uid = geteuid(); setresuid(uid, uid, uid);
would set both real uid and saved uid to effective uid. Then your Linux issetugid() would return 0, but Solaris issetugid() would return 1.
Solaris checks the SUGID
process flag at exec time. Illumos, the free fork of Solaris, sets SUGID in src/uts/common/os/exec.c when executing a file. OpenBSD has similar logic. OpenBSD's manual says,
If a child process executes a new executable file, a new issetugid status will be determined. This status is based on the existing process's uid, euid, gid, and egid permissions and on the modes of the executable file. If the new executable file modes are setuid or setgid, or if the existing process is executing the new image with uid != euid or gid != egid, the new process will be considered issetugid.
Solaris and OpenBSD compare the ids at exec time. Your Linux code delays the comparison until the call to issetugid(), so it is not equivalent.
3) The geteuid()
and getegid()
functions seem to do the same thing everywhere; they simply return the effective user id and the effective group id.
4) The saved ids don't matter. The process might have changed those ids without cleaning its environment variables. None of the real, effective, or saved ids tell us who set the environment variables for the current process.
5) At least on OpenBSD and Solaris, a process that temporarily drops root does not become tainted. OpenBSD's manual page says,
The issetugid() system call's result is unaffected by calls to setuid(), setgid(), or other such calls. In case of a fork(), the child process inherits the same status.
The status of issetugid() is only affected by execve().
When a process temporarily drops root with setuid() or seteuid(), it does not execute a file, so its issetugid() value does not change.
But FreeBSD, DragonFly BSD, and NetBSD define issetugid() more strictly. FreeBSD's manual for issetugid(2) says,
A process is tainted if it was created as a result of an execve(2) system call which had either of the setuid or setgid bits set (and extra privileges were given as a result) or if it has changed any of its real, effective or saved user or group ID's since it began execution.
With these systems, a process dropping root does force its issetugid() value to 1.
6) No, an effective id equal to a saved id does not taint a process. If it did, then every process would be tainted, because every process has its saved id set to its effective id at exec time.