文章目录
- 什么规则库,SELinux如何保存规则文件
- 规则库
- 规则库的组成
- 验证
- 验证标签转换规则是否正确
- 规则库的初始化 avtab_alloc
- 规则库的插入
- 规则库的删除
- 规则库的查询
在《SElinux内核态的实现-avc、avd的设计篇》 ,我们深入了解了SELinux如何使用AVC缓存机制来支撑高效权限检查,包括AVC缓存的的初始化、插入、查找和回收的整个生命周期管理。
本文将着重讲解缓存没有命中的情况下SELinux的处理逻辑,即基于规则文件的权限查找与计算。
同样的,由于avc_has_perm
内涉及内容过于庞大,本文将仅仅介绍规则库实现部分
什么规则库,SELinux如何保存规则文件
既然有SELinux是管控工具,则其管控肯定是基于一定规则放行或者拒绝的。存放放行和拒绝的规则的内存,我称为规则库,而基于条件的规则库,则称为条件规则库(也就是可以通过bool来打开和关闭的规则)。
SELinux的规则库存放在policydb->te_avtab
,条件规则库存放在policydb->te_cond_avtab
规则库
规则库的组成
规则库类型avtab
是一个柔性数组,柔性数组可以简单理解为一个长度可变的数组,用于存放总量不固定的数据。
内核提供了
flex_array_put_ptr(fa, nr, src, gfp)
将src的地址保存在柔性数组中的的下标为nr的位置#define flex_array_put_ptr(fa, nr, src, gfp) flex_array_put(fa, nr, (void *)&(src), gfp)
同时提供
flex_array_get_ptr(fa, nr)
来获取柔性数组中的的下标为nr的位保存的地址。
柔性数组的每个节点为哈希表中某个哈希链表的头节点,每个节点的的内容为strcut avtab_node
strcut avtab_node
以及其内部元素avtab_key
avtab_datum
定义如下:
类型 | 名称 | 含义 |
u16 | source_type | 源SID |
u16 | target_type | 目标SID |
u16 | target_class | CLASS ID |
u16 | specified | 规则类型 |
这里着重需要解析下specified
specified
用于备注此规则的用途与限制。
主要提供了以下标志:
- 本规则的datum保存的是权限检查结果:
- 本规则的datum保存的是type转换的结果:
- 本规则的datum保存的是扩展权限检查结果:
- 是否启用当前规则结果,主要用于条件规则库:
在这里我们可以知晓,规则库中除了表示权限规则外,还保存了type转换的规则。
验证
来看是不是胡扯,我们直接按照上述规则来分析core_dump内存的某个avtab_node信息,并查看是否有实际的配置规则。
这里随便找个avtab
继续往下找到了一个同sid 、tid、class id的规则
可以发现其sid= 4644 ,tid=1358,class id =7,有两条avtab规则。
区别为一个specified为1,表示为AVTAB_ALLOWED
即allow规则。
一个specified为16,即AVTAB_TRANSITION
表示为标签转换
验证标签转换规则是否正确
首先看标签转换的规则
翻译过来就是id=4644的标签 对 id=1358 的标签 的 class id = 7 操作时候将会切换到 id=4646 的标签
首先看看id 为 7 的class是file
然后看看id 为 4644的 type为 ifconfig_t
然后看看id 为1358的 type为 var_run_t
然后看看id 为4646的 type为 ifconfig_var_run_t
所以 *(struct avtab_node *) 0xffff8e91266e8570
翻译过来就是
我们找下selinux-policy规则文件内是否有这条语句。
经过多次接口调用files_pid_filetrans
-> filetrans_pattern
-> filetrans_pattern
发现规则文件中确实生成了语句
规则库的初始化 avtab_alloc
输入参数:
struct avtab *h
: 指向AVTable结构的指针,该结构需要被分配内存。u32 nrules
: 需要存储的检查结果数量。
计算哈希桶数量:
首先,通过移位操作确定需要多少位来表示nrules
(结果保存在shift变量),然后在使用shift
来通过(1<< shift - 2)的方式得到哈希表中哈希链表(nslot)的数量并。确保nslot
不超过预定义的最大值MAX_AVTAB_HASH_BUCKETS
,以防止过度分配。
最后计算mask,用于快速定位哈希链表头节点,它是nslot减1的结果。
分配内存与初始化:
使用flex_array_alloc动态分配内存,成功分配内存后,
初始化AVTable结构的一些成员:
- nel(当前已有的条目数)设为0,
- nslot和mask分别设置为之前计算的哈希链表数量和掩码。
规则库的插入
这部分代码比较简单,查询是否已有数据(不匹配AVTAB_ENABLED|AVTAB_ENABLED_OLD
因为这两个值运行中可能会变动,导致与原始数据不一致),如果找到则报错,没有则新建.
只是其匹配过程进行了查询的优化,由于规则库内数据是按照ID递增的,比如下面这个权限规则链表可以发现source id是递增的
所以可以通过
在查找的id小于规则库内的id的时候快速跳出,找到其按照递增规则处于的最高的位置,便于avtab_insert_node
插入。
规则库的删除
这里代码也很简单,遍历链表并删除所有节点。
规则库的查询
规则库查询逻辑需要与type的查找逻辑一起,所以后面在type查找逻辑中一起讲解。