· uid标记运行进程的用户
· gid标记用户组
· uid和gid是操作系统自主访问控制的基础
主体和客体的区别?
进程A发送消息给进程B,A是主体,B是客体。一般情况下主体凭证和客体凭证的值相同。
凭证的数据结构?
uid,euid,suid,fsuid + gid,egid,sgid,fsgid + 能力集成员 + 密钥串成员 + 强制访问控制相关成员
uid(ruid) #用于用户资源的统计和分配
euid #内核做特权判断时使用,决定了用户的操作权限,0为万能权限
suid #防止用户一直使用0权限,待用户使用0权限完毕后,euid和suid值交换,euid恢复为非0,
待用户需要特权值再将两者交换
fsuid #文件系统中判断访问权限许可
gid egid sgid fsgid类似
补充组id(supplier group ids):属于用户,一个用户可以属于多个组,用于访问控制权限的检查
gid和uid的区别?
gid无特权,euid为0即拥有全部特权,gid,egid不会这样。
用户态进程只能通过系统调用来查看和修改进程凭证,系统调用只能修改自己的uid和gid
设置uid相关系统调用:
int setuid(uid_t uid) #同时将uid,euid,suid修改为同一个值
int seteuid(uid_t euid) #只修改euid
int setreuid(uid_t uid,uid_t euid) #同时修改uid和euid,-1作为参数则表示保持不变,若修改了
uid或euid新值!=uid旧值,则令suid=euid
int setresuid(uid_t uid,uid_t euid,uid_t suid); #同时修改3个值
在设置euid时,系统会令fsuid=euid
int setfsuid(uid_t fsuid) #单独设置进程的fsuid
设置uid的系统调用需要遵守的原则:
1⃣️ 具备setuid特权的进程可以任意设置uid,euid,suid,fsuid
2⃣️ 不具备setuid特权的进程只能将uid/suid/euid设置成现有uid/suid/euid的值之一
3⃣️ 不具备setuid特权的进程只能将fsuid设置成uid/euid/suid/fsuid之一
gid相关系统调用:
与uid类似
获取uid相关系统调用:
uid_t getuid(void)
uid_t geteuid(void)
int getresuid(uid_t *ruid,uid_t *euid,uid_t *suid)
3.1 文件的标记
3.2 文件属性
3.3 系统调用
3.4 其他客体
3.5 其他客体的系统调用
>cat /proc/self/status #获取进程凭证
>man credentials #获得进程凭证的说明
1⃣️ 用户态进程如何获得自身的fsuid
在设置euid相关的系统调用中,内核代码会在设置euid的同时设置fsuid,让fsuid和euid保持一致,故查询euid即可。
uid_t geteuid(void)
2⃣️ 内核为什么这么设计
当进程的euid是root时,说明改进程当前拥有全部特权,有特权使用setuid,可随意修改uid,euid,suid和fsuid,故只需要将uid和suid页设置成root即可。
ps:显示瞬间进程状态
top:实时显示进程状态
一个文件只有一个uid和gid,标记文件的属主和属组,说明文件属于哪个用户哪个组
文件包含文件内容+元数据(属组、属主、存取访问方式等)
元数据存储在inode中,inode存储在内存中
修改属主和属组的系统调用
int chown(const char *path,uid_t owner,gid_t group);
int fchown(int fd,uid_t owner,gid_t group);
int lchown(const char *path,uid_t owner,gid_t group);
int fchownat(int dirfd,const char *pathname,uid_t owner,gid_t group,int flags);
chown一族系统调用可以同时修改文件的属主和属组,-1表示维持原值不变
· fsuid含义?
当进程uid=1000,fsuid=1001,该进程就拥有uid=1001用户的访问文件权限
· 何时进程可以访问文件?
当进程的fsuid和文件的属主uid匹配时,进程可以访问/修改文件
· 文件属主id修改规则?
当进程的fsuid和文件的属主uid匹配,且拥有特权chown时,才可以修改文件属主
· 如何理解更换文件的属主需要 sudo chown(特权chown)?
进程的fsuid和文件的属主的uid匹配,则该进程可以访问/修改文件,但如果没有特权chown,则不可以修改文件属主
· 为什么进程凭证中需要有四个uid(ruid,euid,suid,fsuid)?
使得进程在运行时暂时获得授权
· 属组id修改规则?
当进程的fsuid和文件的属主的uid匹配时,如没有特权chown,则可以将属组id改为自己进程凭证中四个uid之一;若拥有特权chown,则可以将属组id修改为任意值。
查看文件属性的系统调用:
int stat(const char *path,struct stat *buf);
int fstat(int fd,struct stat *buf);
int lstat(const char *path,struct stat *buf);
可以查看允许位
· 如何修改文件的属主和属组?
必须拥有特权chown,才能修改属主(root用户/sudo)
> chown new_owner_name file_name //改变属主
> chown :new_grouup_name file_name //改变属组
· 目录
· 管道:在内核中与文件无异
· 命名管道:与管道的区别是命名管道有名字,管道没有
· 设备:特殊文件
· 套接字socket:用于进程间通信
1. 通过系统调用socket生成套接字
2. 服务器使用bind系统调用将套接字与指定地址addr结合,生成套接字文件
3. 客户端进程使用connect系统判断当前进程能否写addr对应的套接字文件
· IPC:进程间通信,包括消息队列、共享内存、信号灯
· 密钥:数据结构中的uid和gid代表密钥的属主和属组
· IPC
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
int semctl(int semid,int semnum,int cmd,...);
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
当cmd为IPC_STAT,这三个函数用于显示IPC属性
当cmd为 IPC_SET,这三个函数用于设置IPC属性,可以设置允许位
· 密钥
long keyctl(int cmd,...);
根据cmd的不同值,该函数可实现更改密钥的属主和属组/通过参数返回密钥的属性
可以修改密钥的允许位
客体是数据,主体是进程,操作时进程对数据的操作,基本操作有读和写,还有额外操作
· 文件:执行,其本质是进程内存空间的置换,进程将文件的数据读入进程的代码内存空间和数据内存空间
· 目录:执行,即通过一个目录
读目录是读取该目录下的文件和子目录
写目录是在该目录下增删文件和子目录
· IPC:包括消息队列、信号灯和共享内存,只有读和写操作
· 密钥key
key类似文件,keyring类似目录
read读——读取key的密钥数据/读取keyring下的key和子keyring
write写——写key的密钥数据/keyring下的key和子keyring
search搜索——keyring搜索的许可和key被搜索的许可
link链接——将key链接到keyring上,需要key的链接许可,keyring的写许可
view查看——查看key/keyring的属性
setattr设置属性——修改key的属主/属组/允许位
根据属主和属组将所有用户分为三类:同主用户、同组用户、其他用户
· 进程和文件的关系
1)当进程的fsuid和文件的uid相同,则该进程为该文件的同主用户
2)当进程的fsuid和文件的gid相同,则该进程为该文件的同组用户
3)都不相同,且进程补充组中id也与文件gid不同,进程为其他用户
4)如果进程补充组中有id与文件gid相同,则进程为同组用户
· 文件有9bit的允许位
· IPC的允许位
1. IPC只有读写操作,故只有6bit允许位
2. IPC有属主id、属组id、创建者id、创建组id。进程的euid只要与属主id/创建者id相同,即为同主用户;进程的euid/补充组id 与属组id/创建组id相同,即为同组用户
· 拥有密钥的进程比密钥文件的同主进程有更多权限
setuid
该设置位目的是扩大进程权限:当进程调用exective执行一个setuid位为1的文件后,进程的fsuid和euid都被置为该文件的属主uid,从而该文件的内容被读入该进程的数据内存空间和代码内存空间,并将文件的部分数据读入进程凭证
· 如何让某文件可被所有进程执行?
将该文件的setuid设置为1
setgid
将进程凭证中的egid和fsuid设置为文件的gid
· setuid作用:无作用
· setgid作用:在该目录下创建的文件/子目录的属组id自动设置为该目录的属组id
· set-other-id作用:该目录下的文件/目录只能被该文件/目录的属主/属组删除
· 通过chmod 和 fchmod 可以修改文件/目录上的允许位
第五章 访问控制列表
5.1 简介
linux对于进程对文件的权限,除了分为同主用户、同组用户、其他,还可以定义某用户进程的权限、研发组进程的权限;同时分类可以动态的增加和删除。
5.2 扩展属性
文件的扩展属性和inode分开存储,inode中保留一个关联到扩展属性的索引。扩展属性可以动态的添加和删除,其是一个数组,分为扩展属性名和扩展属性值两部分,访问控制列表是扩展属性的一部分。
5.3 结构
访问控制列表是一个变长的数组,实现细粒度访问控制,其中每一个acl_entry结构如下
include/linux/posix_acl.h
struct posix_acl_entry{
short e_tag; //规定许可类型
unsigned short e_perm; //规定许可权限
union{
kuid_t e_uid; //uid
kgid_t e_gid; //gid
};
}
· tag=ACL_USER:规定某个特定用户的权限
· ACL_GROUP:规定某个特定组的权限
· ACL_USER_OBJ:属主权限
· ACL_GROUP_OBJ:属组权限
· ACL_OTHER:其他人权限
· ACL_MASK:user/group/group_obj内权限不得大于ACL_MASK
5.4 操作许可
属主 > acl_user > 属组+acl_group > acl_other
判断进程的fsuid是否与属主/acl_user中某个uid/gid+acl_group中某个gid相同,若存在则获得对应的权限(注意和acl_mask取交集),否则获得acl_other中的权限
5.5 两种ACL
ACCESS:用于判断进程对文件的/目录的访问控制权限
DEFAULT:用于对目录中新建的文件/子目录的access访问控制权限进行初始化
5.6 与允许位的关系
允许位的三种身份对应acl_user_obj、acl_group_obj、acl_other,属组需要注意一点,当acl_mask有定义时,属组权限需要在acl_group_obj和acl_mask权限之间取交集。
5.7 系统调用
acl本身没有系统调用,但可以用扩展属性的系统调用
· 设置扩展属性
int setxattr(const char *path,const char *name,const void *value,size_t size,int flags);
int lsetxattr(const char *path,const char *name,const void *value,size_t size,int flags);
int fsetxattr(int fd,const char *name,const void *value,size_t size,int flags);
· 获取扩展属性值
· 获取扩展属性名
· 删除扩展属性