A documentação em credentials(7)
esclarece isso um pouco para os sistemas Linux:
User and group identifiers
Each process has various associated user and group IDs. These IDs are integers, respectively represented using the types
uid_t
andgid_t
(defined in<sys/types.h>
).On Linux, each process has the following user and group identifiers:
Real user ID and real group ID. These IDs determine who owns the process. A process can obtain its real user (group) ID using
getuid(2)
.Effective user ID and effective group ID. These IDs are used by the kernel to determine the permissions that the process will have when accessing shared resources such as message queues, shared memory, and semaphores. On most UNIX systems, these IDs also determine the permissions when accessing files. However, Linux uses the filesystem IDs described below for this task. A process can obtain its effective user (group) ID using
geteuid(2)
.Saved set-user-ID and saved set-group-ID. These IDs are used in set-user-ID and set-group-ID programs to save a copy of the corresponding effective IDs that were set when the program was executed (see
execve(2)
). A set-user-ID program can assume and drop privileges by switching its effective user ID back and forth between the values in its real user ID and saved set-user-ID. This switching is done via calls toseteuid(2)
,setreuid(2)
, orsetresuid(2)
. A set-group-ID program performs the analogous tasks usingsetegid(2)
,setregid(2)
, orsetresgid(2)
. A process can obtain its saved set-user-ID (set-group-ID) usinggetresuid(2)
.[...]
Eu fiz um programa de teste para ver o que acontece:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
int getuids(uid_t *uids) {
if(getresuid(&uids[0], &uids[1], &uids[2]) == -1) {
perror("Unable to get UIDs\n");
return 0;
}
return 1;
}
int getgids(gid_t *gids) {
if(getresgid(&gids[0], &gids[1], &gids[2]) == -1) {
perror("Unable to get GIDs\n");
return 0;
}
return 1;
}
int main(void) {
uid_t uids[3];
gid_t gids[3];
if(getuids(uids) && getgids(gids)) {
printf("Real ID: user %d, group %d\n", (int)uids[0], (int)gids[0]);
printf("Effective ID: user %d, group %d\n", (int)uids[1], (int)gids[1]);
printf("Set-ID: user %d, group %d\n", (int)uids[2], (int)gids[2]);
seteuid(uids[0]);
getuids(uids);
getgids(gids);
printf("Effective ID: user %d, group %d\n", (int)uids[1], (int)gids[1]);
}
return 0;
}
Aqui está o arquivo:
server /home/erik # ls -l perms
-r-sr-sr-x 1 nobody nobody 8280 Apr 26 00:36 perms
Executando como root
:
server-calgary /home/erik # ./perms
Real ID: user 0, group 0
Effective ID: user 65534, group 65534
Set-ID: user 65534, group 65534
Effective ID: user 0, group 65534
Executando como erik
:
erik@server ~ $ ./perms
Real ID: user 1000, group 1000
Effective ID: user 65534, group 65534
Set-ID: user 65534, group 65534
Effective ID: user 1000, group 65534
Como meu programa de teste mostra, se um arquivo é set-ID, o EUID / EGID começa com o proprietário / grupo no arquivo (somente as permissões set-UID e set-UID + GID funcionam!), mas pode ser alterado entre isso e o ID real do chamador se o programa quiser.