每个Linux进程都包含这些属性,这些属性共同决定了该进程访问文件的权限 :
1. real user id
2. real group id
3. effective user id
4. effective group id
5. saved set-user-id
6. saved set-group-id
1,2 简称ruid、rgid ,由启动进程的用户决定,通常是当前登录用户(运行可执行文件的用户);
3,4 简称euid/egid ,一般在进程启动时,直接由1,2复制而来;或者是当进程对应的可执行文件的set-user-id/set-group-id(chmod u+s)标志位为true时,为该文件的所属用户/组,这组属性决定了进程访问文件的权限;
5,6 简称suid/sgid,从euid/egid复制。
下面这张图描述了进程启动时,这些属性是怎么赋值的:
1-2 : 由登录用户启动运行可执行文件,启动进程;
3: 设置进程的rid/rgid为当前登录用户的uid/gid;
4:设置进程的eid/egid,根据可执行文件的set-user-id/set-group-id属性(红色:0, 紫色:1),为1时,设为可执行文件的uid/gid,否则从rid/rgid拷贝。
/* sample1.c, 打印本进程的ruid, euid, suid */ #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <pwd.h> int main() { struct passwd* ruser = NULL; struct passwd* euser = NULL; struct passwd* suser = NULL; uid_t uid, euid, suid; /* get uid euid suid */ if(getresuid(&uid, &euid, &suid) != 0) { perror(0); return 1; } /* get name of id */ ruser = getpwuid(uid); printf("real user: %s\n", ruser->pw_name); euser = getpwuid(euid); printf("effective user: %s\n", euser->pw_name); suser = getpwuid(suid); printf("saved set-user-id user: %s\n", suser->pw_name); return 0; }编译生成a.out。
执行ls -l a.out,查看可执行文件属性:
执行./a.out, 可以看到三个用户均为当前登录用户:
若执行sudo ./a.out, 则三个用户全为root用户
设置set-user-id位为1: 执行chmod u+s a.out, 可以看到user的x属性变成了s:
执行sudo ./a.out, rid为登录用户,euid/suid和a.out文件的uid一致,此时进程虽然用sudo启动,但读写文件时只具有普通用户(euid: xuwei)的权限:
以上仅以user id为例, 对于相应的group id, 其原理是一样的。
本文提到“effective id”实际决定文件读写权限,“real id”和“saved id”有什么用呢?下节会介绍。