UNIX process UID model
In UNIX environment, each process has three user id: real user id, effective user id, saved set-user-id. How these three UID are set is depended on whether the setuid bit of executable file has been set. The table bellow shows how these three UID will change after a exec system call.
| setuid bit | real user id | effective user id | saved set-user-id |
|---|---|---|---|
| set | unchanged | the owner of executable file | copy from effective user id |
| unset | unchanged | unchanged | copy from effective user id |
Here is a demo, I first compile a simple program into a.out, then use chown root:root a.out to change the ower of the executable file, after that I use chmod +s a.out to set setuid bit. The output of ls -l a.out is: -rwsrwsr-x 1 root root 14600 Apr 24 08:02 a.out. After start a.out, the output of ps -o pid,ppid,euid,ruid,suid,cmd -p 16990,17210 is:
| PID | PPID | EUID | RUID | SUID | CMD |
|---|---|---|---|---|---|
| 16990 | 16989 | 1001 | 1001 | 1001 | -bash |
| 17210 | 16990 | 0 | 1001 | 0 | ./a.out |
We can notice that EUID of a.out is root, RUID keeps same as its parent process, SUID is same as EUID.
Permission check is based on effective user id. UNIX system provides these system calls to manipulate these three UID: setuid, seteuid. How these system call affect three UID is based on whether the process has root privilege.
| system call | ID | root privilege | non root privilege |
|---|---|---|---|
setuid(uid) |
real user id | set to uid | unchanged |
setuid(uid) |
effective user id | set to uid | set to uid. uid must equal to ruid or suid, else return error |
setuid(uid) |
saved set-user-id | set to uid | unchanged |
| system call | ID | root privilege | non root privilege |
|---|---|---|---|
seteuid(uid) |
real user id | unchanged | unchanged |
seteuid(uid) |
effective user id | set to uid | set to uid. uid must equal to ruid or suid, else return error |
seteuid(uid) |
saved set-user-id | unchanged | unchanged |
One use case of this model is a program we all familiar with: sudo, ll /usr/bin/sudo: -rwsr-xr-x 1 root root 149080 Jan 18 2018 /usr/bin/sudo.
We can see that sudo has setuid bit setted. What happened after we type sudo some-command. The shell will start sudo with some-command as its arguments. As sudo has setuid bit set, so sudo will have ruid set to normal user, euid and suid set to root. Then sudo call setuid(0) change all three UID to root, after that sudo will fork and exec our command, so our command will be executed as all three UID set to root. This is just a brief process, permission check and ask password stuff all ignored.