《Linux模块安全内核深入剖析》读书笔记[持续更新]

第二章 主体标记与进程凭证

2.1 进程凭证

· uid标记运行进程的用户

· gid标记用户组

· uid和gid是操作系统自主访问控制的基础

主体和客体的区别?

        进程A发送消息给进程B,A是主体,B是客体。一般情况下主体凭证和客体凭证的值相同。

凭证的数据结构?

        uid,euid,suid,fsuid + gid,egid,sgid,fsgid + 能力集成员 + 密钥串成员 + 强制访问控制相关成员

2.2 详述

2.2.1 uid和gid

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不会这样。

   2.2.2 系统调用

        用户态进程只能通过系统调用来查看和修改进程凭证,系统调用只能修改自己的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:实时显示进程状态

第三章 客体标记与文件属性

3.1 文件的标记

        一个文件只有一个uid和gid,标记文件的属主和属组,说明文件属于哪个用户哪个组

3.2 文件属性

        文件包含文件内容+元数据(属组、属主、存取访问方式等)

        元数据存储在inode中,inode存储在内存中

3.3 系统调用

修改属主和属组的系统调用

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     //改变属组

3.4 其他客体

· 目录

· 管道:在内核中与文件无异

· 命名管道:与管道的区别是命名管道有名字,管道没有

· 设备:特殊文件

· 套接字socket:用于进程间通信

        1. 通过系统调用socket生成套接字

        2. 服务器使用bind系统调用将套接字与指定地址addr结合,生成套接字文件

        3. 客户端进程使用connect系统判断当前进程能否写addr对应的套接字文件

· IPC:进程间通信,包括消息队列、共享内存、信号灯

· 密钥:数据结构中的uid和gid代表密钥的属主和属组

3.5 其他客体的系统调用

· 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的不同值,该函数可实现更改密钥的属主和属组/通过参数返回密钥的属性

        可以修改密钥的允许位

· 第四章 操作和操作许可

4.2 操作许可与操作分类

        客体是数据,主体是进程,操作时进程对数据的操作,基本操作有读和写,还有额外操作

· 文件:执行,其本质是进程内存空间的置换,进程将文件的数据读入进程的代码内存空间和数据内存空间

· 目录:执行,即通过一个目录

                读目录是读取该目录下的文件和子目录

                写目录是在该目录下增删文件和子目录

· 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的属主/属组/允许位

4.3 允许位

        根据属主和属组将所有用户分为三类:同主用户、同组用户、其他用户

· 进程和文件的关系

        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相同,即为同组用户

· 拥有密钥的进程比密钥文件的同主进程有更多权限

4.4 设置位

4.4.1 文件

setuid

        该设置位目的是扩大进程权限:当进程调用exective执行一个setuid位为1的文件后,进程的fsuid和euid都被置为该文件的属主uid,从而该文件的内容被读入该进程的数据内存空间和代码内存空间,并将文件的部分数据读入进程凭证

 · 如何让某文件可被所有进程执行?

        将该文件的setuid设置为1

setgid

        将进程凭证中的egid和fsuid设置为文件的gid

4.4.2 目录

· 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);

                        

· 获取扩展属性值

· 获取扩展属性名

· 删除扩展属性

你可能感兴趣的:(linux)