12、SELinux策略常见错误与修复:denied日志分析,neverallow冲突解决,策略规则冲突排查,常见SELinux策略错误案例
各位同学,今天我们来聊聊SELinux策略开发中最让人头疼的部分——排错。说实话,我刚开始接触SELinux那会儿,最怕的就是系统启动到一半突然黑屏,或者某个服务莫名其妙起不来。打开dmesg一看,满屏的avc: denied,那感觉就像在迷宫里找出口。
但别怕,这些错误其实有规律可循。今天我就把这些年踩过的坑、总结的经验,一次性分享给你们。
12.1 denied日志分析:从看懂到看透
先说说最常见的avc: denied日志。很多新手一看到这个就慌,其实它是个好东西——它把问题明明白白告诉你了。
来看一条典型的日志:
avc: denied { read } for pid=1234 comm="logd" name="system.log" dev="mmcblk0p25" ino=5678 scontext=u:r:logd:s0 tcontext=u:object_r:log_data_file:s0 tclass=file permissive=0
这条日志里,关键信息就几个:
- denied { read }:被拒绝的操作是读取
- scontext=u:r:logd:s0:谁干的?logd这个进程
- tcontext=u:object_r:log_data_file:s0:对谁干的?log_data_file类型的文件
- tclass=file:操作对象是文件
- permissive=0:当前是强制模式,所以真的被拒绝了
我个人习惯是,先看scontext和tcontext,搞清楚是谁想访问谁。然后看tclass和denied的操作,就知道缺什么权限了。
audit2allow工具来自动生成允许规则。命令很简单:audit2allow -i /var/log/audit/audit.log -M mymodule。但注意,它生成的规则有时候太宽泛,需要人工审核。
12.2 neverallow冲突解决:绕不过的硬约束
接下来聊聊neverallow。这东西就像SELinux策略里的“宪法”,谁都不能违反。我见过不少开发者,辛辛苦苦写了一大堆allow规则,结果编译时被neverallow一巴掌拍回来。
举个例子,假设你在自己的.te文件里写了:
allow myapp system_data_file:file write;
但全局策略里有一条:
neverallow { untrusted_app } system_data_file:file write;
那编译就会报错。这时候怎么办?
我的经验是三步走:
- 先确认是不是真的需要这个权限——有时候换个思路,用其他方式实现功能,就能绕开冲突。
- 如果确实需要,那就得修改
neverallow规则本身。但注意,这通常需要平台级权限,不是随便改的。 - 或者换个角度:把你的进程类型从
untrusted_app改成其他域,比如system_app,前提是你的应用确实有系统级权限。
neverallow规则!我曾经见过有人这么干,结果导致系统安全漏洞,后来被安全团队追着改了一个月。
12.3 策略规则冲突排查:多规则叠加的陷阱
有时候,单个规则看起来没问题,但多个规则叠加在一起就出事了。这种情况最隐蔽,也最难排查。
我记得有一次,一个同事说他的服务在permissive模式下跑得好好的,一切到enforcing就崩溃。我帮他看了一天,最后发现是两条规则冲突了:
- 规则A:允许
my_service_t对cache_file_t执行write操作 - 规则B:
neverallow禁止my_service_t对cache_file_t执行write操作
等等,这看起来不是直接冲突吗?其实不是。规则A是在一个条件语句里的,只有在某个布尔值为真时才生效。而规则B是全局的。结果就是,当布尔值为真时,两条规则同时生效,neverallow优先,所以被拒绝了。
排查这类问题,我推荐用sesearch工具:
sesearch --allow -s my_service_t -t cache_file_t -c file -p write
sesearch --neverallow -s my_service_t -t cache_file_t -c file -p write
把两条命令的结果对比一下,就能看出问题所在。
12.4 常见SELinux策略错误案例
最后,我整理了几个我实际项目中遇到的典型案例,你们可以对照着看看。
| 错误类型 | 现象 | 根因 | 解决方案 |
|---|---|---|---|
| 类型未定义 | 编译报错:undefined type | .te文件中引用了未声明的类型 | 在type声明中添加,或检查拼写 |
| 属性缺失 | 规则不生效,但日志无denied | 目标类型缺少必要的属性 | 添加typeattribute声明 |
| 布尔值未定义 | 条件规则不生效 | 引用了未定义的布尔值 | 在bool声明中定义 |
| 文件上下文错误 | 文件标签不对,导致访问被拒 | file_contexts配置错误 | 检查并修正文件上下文映射 |
| 域转换缺失 | 进程启动后域未切换 | 缺少domain_trans规则 |
添加type_transition规则 |
嗯,这里我要特别说一下文件上下文错误。有一次,一个系统服务总是报avc: denied,我查了半天,发现是file_contexts里把某个目录的标签写错了。你想想看,一个字符的差异,就能让整个服务瘫痪。所以,写file_contexts的时候一定要仔细,最好用restorecon -R命令重新应用一下标签。
核心要点:
- denied日志是排错的第一手资料,学会看它等于学会了一半
- neverallow是硬约束,不要试图绕过,而是理解它为什么存在
- 规则冲突往往藏在条件语句和全局规则之间,用sesearch工具排查
- 常见错误类型要熟记于心,遇到问题能快速定位
好了,关于SELinux策略的常见错误和修复,我就讲到这里。这些内容都是我实际项目中一点一点积累出来的,希望能帮你们少走一些弯路。记住,排错的过程虽然痛苦,但每解决一个问题,你对SELinux的理解就会更深一层。