This is a set-root-uid program
$ls -l
-rwsr-sr-x 1 root root 7406 2011-12-13 22:37 ./x*
Code:
#define _GNU_SOURCE
#include
#include
void print_uid(char *str, int ret)
{
uid_t ruid;
uid_t euid;
uid_t suid;
getresuid(&ruid, &euid, &suid);
printf("%s ret:%d\n"
"Real:%4d Effective:%4d Saved:%4d\n",
str, ret, ruid, euid, suid);
}
int main(void)
{
int ret = 0;
print_uid("init", ret); /* Real:1000 Effective: 0 Saved: 0 */
ret = seteuid(600);
print_uid("seteuid(600)", ret); /* Real:1000 Effective: 600 Saved: 0 */
ret = setuid(1000);
print_uid("setuid(1000)", ret); /* Real:1000 Effective:1000 Saved: 0 */
ret = setuid(0);
print_uid("setuid(0)", ret); /* Real:1000 Effective: 0 Saved: 0 */
ret = setuid(1000);
print_uid("setuid(1000)", ret); /* Real:1000 Effective:1000 Saved:1000 */
ret = setuid(0);
print_uid("setuid(0)", ret); /* Real:1000 Effective:1000 Saved:1000 */
return 0 ;
}
sudo chown root setuid_feature
sudo chmod +s setuid_feature
There are three uids for a process in Linux: REAL uid, EFFECTIVE uid, SAVED uid.
Cond 1. When euid is root, setuid or seteuid can be set to any uid, but there is a side effect, when using setuid(not seteuid), all of the three can be set to the same uid which is not ROOT, and then the process can't regain ROOT privilege.
Cond 2. When euid is not root, setuid or seteuid can be set to ruid or suid, and only euid is changed.
| seteuid | setuid
Cond 1. (euid == root) | set euid to any uid | set all three uids to any uid
Cond 2. (euid != root) | set euid to ruid or suid | set euid to ruid or suid
so, there are 5 setuid or seteuid process there in code, let me classify them:
1. seteuid(600): Cond 1, set euid to 600
2. setuid(1000): Cond 2, set euid to 1000
3. setuid(0) : Cond 2, set euid to 0(suid)
4. setuid(1000): Cond 1, set all three uids to 1000
5. setuid(0) : Cond 2, all three uids is not equal 0, so can't set to 0, failed with ret = -1