每个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”有什么用呢?下节会介绍。