This is a set-root-uid program
$ls -l
-rwsr-sr-x 1 root root 7406 2011-12-13 22:37 ./x*
int main(void) {
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
seteuid(600);
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
setuid(1000);
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
setuid(0); // HOW DOES THIS SUCCEED IN SETTING THE EUID BACK TO 0
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
return 0 ;
}
UID GID
Real 1000 Real 1000
Effective 0 Effective 0
UID GID
Real 1000 Real 1000
Effective 600 Effective 0
UID GID
Real 1000 Real 1000
Effective 1000 Effective 1000
UID GID
Real 1000 Real 1000
Effective 0 Effective 1000
The man page states that setuid will change the real,saved and effective uid.
So after the calling setuid(1000)
, all three change to 1000
.
How is that setuid(0)
let's me change euid
to 0
?
There are two cases,
- You want to temporarily drop root privilege while executing setuid program
- You want to permanently drop root privilege while executing setuid program...
Case 1:
After a setuid program starts executing
1.seteuid(600);
2.setuid(1000);
3.setuid(0);
For this case the root privilege can be gained back again.
+----+------+------------+
| uid|euid |saved-uid |
|----|------|------------|
1.|1000| 0 | 0 |
2.|1000| 600 | 0 |
3.|1000| 1000 | 0 |
4.|1000| 0 | 0 |
| | | |
+------------------------+
Case 2:
After a setuid program starts executing,
1.setuid(1000);
2.setuid(0);
+----+------+------------+
| uid|euid |saved-uid |
|----|------|------------|
1.|1000|0 | 0 |
2.|1000|1000 | 1000 |
| | | |
+------------------------+
In this case you cannot get back the root privilege. This can be verified by the following command,
cat /proc/PROCID/task/PROCID/status | less
Uid: 1000 0 0 0
Gid: 1000 0 0 0
This command will display a Uid and Gid and it will have 4 fields( the first three fields are the one we are concerned with). Something like the above
The three fields represent uid,euid and saved-user-id. You can introduce a pause (an input from user) in your setuid program and check for each step the cat /proc/PROCID/task/PROCID/status | less
command. During each step you can check the saved uid getting changed as mentioned.
If you're euid is root and you change the uid, the privileges gets dropped permanently.If effective user id is not root then saved user id is never touched and you can regain the root privilege back anytime you want in your program.