Код:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
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
В Linux существует три uid процесса: REAL UID, EFFECTIVE uid, SAVED uid.
Конд 1. Когда euid является root, setuid или seteuid могут быть установлены на любой uid, но при использовании setuid (не seteuid) все три могут быть установлены на один и тот же uid, который не является ROOT, и тогда процесс не может восстановить привилегию ROOT.
Конд 2. Когда euid не является root, setuid или seteuid могут быть установлены в ruid или suid, и изменяется только euid.
| 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
Итак, в коде есть 5 процессов setuid или seteuid, позвольте мне их классифицировать:
1. seteuid (600): Cond 1, установите euid на 600
2. setuid (1000): Cond 2, установите euid на 1000
3. setuid (0): Cond 2, установите для euid значение 0 (suid)
4. setuid (1000): Cond 1, установите все три идентификатора 1000
5. setuid (0): Cond 2, все три идентификатора не равны 0, поэтому не могут быть установлены в 0, сбой с ret = -1