Process Credentials

实际用户 ID 和实际组 ID

实际用户 ID 和实际组 ID 确定了进程所属的用户和组。【登录 shell 会从/etc/passwd 文件中读取相应用户密码记录的第三和第四字段,作为其实际用户 ID 和实际组 ID】【创建新进程时,将从其父进程中继承这些 ID】

有效用户 ID 和有效组 ID

当进程尝试执行各种系统调用时,将结合有效用户 ID、有效组 ID 和辅助组 ID 一起确定授予进程的权限。【通常有效用户 ID 及组 ID 与其相应的实际 ID 相等】

Set-User-ID 和 Set-Group-ID 程序

set-user-ID 程序会将进程的有效用户 ID 置为可执行文件的用户 ID(属主),从而获得常规情况下并不具有的权限。set-group-ID 程序对进程有效组 ID 实现类似任务。【非特权用户能够对其拥有的文件进行设置,而特权用户能够对任何文件进行设置】

当使用 ls -l 命令查看文件权限时,如果为程序设置了 set-user-ID 权限位和 set-group-ID 权限位,那么通常用来表示文件可执行权限的 x 标识会被 s 标识所替换。

1
2
3
4
5
6
7
8
9
$ su
Password:
# ls -l prog
-rwxr-xr-x    1 root root   302585 Jun 26 15:05 prog
# chmod u+s prog // turn on set-user-ID permission bit
# chmod u+s prog // turn on set-group-ID permission bit

# ls -l prog
-rwsr-sr-x    1 root root   302585 Jun 26 15:05 prog

当允许 set-user-ID 程序【通过调用 exec()将 set-user-ID 程序加入进程的内存中】时,内核会将进程的有效用户 ID 设置为可执行文件的用户 ID。set-group-ID 行为类似。【换言之,执行该程序的用户,获得了常规情况下所不具有的权限】

保存 set-user-ID 和 保存 set-group-ID

  1. 若可执行文件的 set-user-ID(set-group-ID)权限位已开启,则将进程的有效用户(组)ID 置为可执行未见得属主。若未设置 set-user-ID(set-group-ID)权限位,则进程的有效用户(组)ID 将保持不变。
  2. saved set-user-ID 和 saved set-group-ID 的值由对应的有效 ID 复制而来。

文件系统用户 ID 和组 ID

文件系统用户 ID 和组 ID 决定了打开文件、改变文件属主、修改文件权限之类文件系统操作的操作权限。【通常文件系统用户 ID 和组 ID 的值等同于相应的有效用户 ID 和组 ID】

辅助组 ID

辅助组 ID 用于标识进程所属的若干附加的组

获取和修改进程凭证

获取和修改实际、有效和保存设置标识

1
2
3
4
5
6
7
8
9
#include <unistd.h>

uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);

int setuid(uid_t uid);
int setgid(gid_t git);

系统调用 getuid() 和 getgid() 分别返回调用进程的实际用户 ID 和组 ID。系统调用 geteuid() 和 getegid() 则对进程的有效 ID 实现类似功能。

setuid() 系统调用以给定的 uid 参数值来修改调用进程的有效用户 ID,也可能修改实际用户 ID 和保存 set-user-ID。系统调用 setgid()则对相应组 ID 实现了类似功能。

  1. 当非特权进程调用 setuid 时,仅能修改进程的有效用户 ID。
  2. 当特权进程以一个非 0 参数调用 setuid()时,其实际用户 ID、有效用户 ID 和保存 set-user-ID 均被置为 uid 参数所指定的值。

进程能够使用 seteuid() 和 setegid() 来修改其有效用户/组 ID。

1
2
3
4
#include <unistd.h>

int seteuid(uid_t uid);
int setegid(gid_t gid);
  1. 非特权进程仅能使其有效 ID 修改为相应的实际 ID 或保存设置 ID
  2. 特权级进程能够将其有效 ID 修改为任意值

setreuid() 和 setregid() 系统调用允许调用进程独立修改及实际和有效用户/组 ID

1
2
3
4
#include <unistd.h>

int setreuid(uid_t ruid, uid_t euid);
int setergid(gid_t rgid, gid_t egid);
  1. 非特权进程只能将其实际用户 ID 设置为当前实际用户 ID 或有效用户 ID,且只能将有效用户 ID 设置为当前实际用户 ID、有效用户 ID 或保存 set-user-ID
  2. 特权级进程能够设置其实际用户 ID 和有效用户 ID 位人一直
1
2
3
4
5
6
7
#define _GNU_SOURCE
#include <unistd.h>

int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
int setresuid(uid_t ruid, uid_t euid, uid_t suid);
int setresgid(gid_t rgid, gid_t egid, gid_t sgid);

getresuid() 和 getresgid() 系统调用将调用进程的当前实际用户/组 ID、有效用户/组 ID 和保存 set-user-ID/set-group-ID 值返回至给定的三个参数所指定的位置。

setresuid() 和 getresgid() 系统调用允许调用进程独立修改器三个用户/组 ID 的值。

获取和修改文件系统 ID

1
2
3
4
#include <sys/fsuid.h>

int setfsuid(uid_t fsuid);
int setfsgid(gid_t fsgid);

setfsuid() 和 setfsgid() 系统调用将进程文件系统用户/组 ID 修改为参数所指定的值。

获取和修改辅助组 ID

1
2
3
#include <unistd.h>

int getgroups(int gidsetsize, gid_t grouplist[]);

getgroups 仅返回调用进程的辅助组 ID

若进程属组的数量常熟 gidsetsize,则 getgroups 将返回错误【EINVAL】。可将 grouplist 数组的大小调整为常量 NGROUPS_MAX+1 以避免这种情况。

1
2
3
4
5
#define _BSD_SOURCE
#include <grp.h>

int setgroups(size_t gidsetsize, const gid_t *grouplist);
int initgroups(const char* user, gid_t group);

setgroups 系统调用使用 grouplist 数组所指定的集合来替换调用进程的辅助组 ID。

initgroups 函数将扫描 /etc/groups 文件,为 user 创建属组列表,一次初始化调用进程的辅助组 ID。

显示进程凭证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/fsuid.h>
#include <limits.h>
#include "ugid_functions.h" /* username_from_id() & group_name_from_id() */
#include "tlpi_hdr.h"

#define SG_SIZE (NGROUPS_MAX + 1)

int main(int argc, char *argv[])
{
    uid_t ruid, euid, suid, fsuid;
    gid_t rgid, egid, sgid, fsgid;
    gid_t suppGroups[SG_SIZE];
    int numGroups, j;
    char *p;

    if (getresuid(&ruid, &euid, &suid) == -1)
        errExit("getresuid");
    if (getresgid(&rgid, &egid, &sgid) == -1)
        errExit("getresgid");

    /* Attempts to change the file-system IDs are always ignored
       for unprivileged processes, but even so, the following
       calls return the current file-system IDs */

    fsuid = setfsuid(0);
    fsgid = setfsgid(0);

    printf("UID: ");
    p = username_from_id(ruid);
    printf("real=%s (%ld); ", (p == NULL) ? "???" : p, (long)ruid);
    p = username_from_id(euid);
    printf("eff=%s (%ld); ", (p == NULL) ? "???" : p, (long)euid);
    p = username_from_id(suid);
    printf("saved=%s (%ld); ", (p == NULL) ? "???" : p, (long)suid);
    p = username_from_id(fsuid);
    printf("fs=%s (%ld); ", (p == NULL) ? "???" : p, (long)fsuid);
    printf("\n");

    printf("GID: ");
    p = group_name_from_id(rgid);
    printf("real=%s (%ld); ", (p == NULL) ? "???" : p, (long)rgid);
    p = group_name_from_id(egid);
    printf("eff=%s (%ld); ", (p == NULL) ? "???" : p, (long)egid);
    p = group_name_from_id(sgid);
    printf("saved=%s (%ld); ", (p == NULL) ? "???" : p, (long)sgid);
    p = group_name_from_id(fsgid);
    printf("fs=%s (%ld); ", (p == NULL) ? "???" : p, (long)fsgid);
    printf("\n");

    numGroups = getgroups(SG_SIZE, suppGroups);
    if (numGroups == -1)
        errExit("getgroups");

    printf("Supplementary groups (%d): ", numGroups);
    for (j = 0; j < numGroups; j++)
    {
        p = group_name_from_id(suppGroups[j]);
        printf("%s (%ld) ", (p == NULL) ? "???" : p, (long)suppGroups[j]);
    }
    printf("\n");

    exit(EXIT_SUCCESS);
}
Licensed under CC BY-NC-SA 4.0
Get Things Done
Built with Hugo
Theme Stack designed by Jimmy