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
?
So, the real user id is who you really are (the one who owns the process), and the effective user id is what the operating system looks at to make a decision whether or not you are allowed to do something (most of the time, there are some exceptions).
The saved user ID ( suid ) is used when a program running with elevated privileges needs to do some unprivileged work temporarily; changing euid from a privileged value (typically 0 ) to some unprivileged value (anything other than the privileged value) causes the privileged value to be stored in suid .
Effective UserID : It is normally the same as Real UserID, but sometimes it is changed to enable a non-privileged user to access files that can only be accessed by a privileged user like root.
The Effective UserID is identical to the Real UserID, but it could be modified to permit a non-privileged person to use the documents that are typically accessible only to privileged users such as the root. It is used by the computing system to determine if you are allowed to do a particular task or not.
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.
DESCRIPTION setuid() sets the effective user ID of the calling process. If the effective UID of the caller is root, the real UID and saved set-user-ID are also set.
Under Linux, setuid() is implemented like the POSIX version with the _POSIX_SAVED_IDS feature. This allows a set-user-ID (other than root) program to drop all of its user privileges, do some un-privileged work, and then reengage the original effective user ID in a secure manner.
If the user is root or the program is set-user-ID-root, special care must be taken. The setuid() function checks the effective user ID of the caller and if it is the superuser, all process-related user ID's are set to uid. After this has occurred, it is impossible for the program to regain root privileges.
Thus, a set-user-ID-root program wishing to temporarily drop root privileges, assume the identity of an unprivileged user, and then regain root privileges afterward cannot use setuid(). You can accomplish this with seteuid(2).
(from the Linux Programmers' Manual, 2014-09-21, page setuid.2
)
O! These functions are difficult to use correctly.
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.
That is the case if and only if you are euid 0. At the time you call setuid(0)
, however, you are euid 1000 and saved uid 0 (check getresuid(2)
, for example). That's why you're able to regain privileges.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With