Question

According to the man pages for issetugid, the call is supposed to either (1) alert to uid/gid changes; or (2) alert to a possible tainted environment. The function name suggests a third purpose.

First question: what is it purpose?

When I look at the implementations available (for example, on Linux system as a library since Linux kernel does not provide the API), I find the following:

if (getuid() != geteuid()) return 1; 
if (getgid() != getegid()) return 1; 
return 0; 

On Solaris, it looks as follows:

return ((curproc->p_flag & SUGID) != 0);

I'm a bit suspicious, but that's partially because its difficult understand what functions like geteuid and getegid return across all platforms - for example, BSD, Linux, Unix and Solaris.

Second question: is the Linux code semantically equivalent to Solaris code?

Third question: are geteuid and getegid implemented the same across platforms? How about for systems that have I three id's play - real, effective, and saved?

Fourth question: is the effective id the only id's that matter here?

If a process starts as UID = 0 and temporarily drops privileges, then the saved id's come into play. A process that temporarily drops root does not need to exec and should not be tainted.

Fifth question: is a process that temporarily drops root tainted?

Sixth question: should a process whose effective id is the saved id be considered tainted?

Était-ce utile?

La solution

Six questions is a bit much to answer in a system designed for one question to answer, especially if no one person knows the answers to all six, but I'll try...

1) The purpose of issetugid() is to let libraries know if they're being used in a program that was run with raised privileges so they can avoid risky behavior such as trusting LD_LIBRARY_PATH, NLSPATH, etc. environment variables that would let the caller load modules that can abuse the raised privileges. You can see some historical discussions on it like this ncurses 4.1 security bug thread.

2) That code appears to be less secure than the BSD & Solaris versions, since it doesn't take into account the saved setid bits.

3) They probably have different implementations on different kernels - look at the platform source code to find out.

4, 5 & 6) No, yes, yes - a process that can change its euid or egid back to higher levels should still not trust environment variables that cause it to load user-provided code to exploit them.

Autres conseils

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top