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:当前是强制模式,所以真的被拒绝了

我个人习惯是,先看scontexttcontext,搞清楚是谁想访问谁。然后看tclassdenied的操作,就知道缺什么权限了。

小技巧:我经常用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;

那编译就会报错。这时候怎么办?

我的经验是三步走:

  1. 先确认是不是真的需要这个权限——有时候换个思路,用其他方式实现功能,就能绕开冲突。
  2. 如果确实需要,那就得修改neverallow规则本身。但注意,这通常需要平台级权限,不是随便改的。
  3. 或者换个角度:把你的进程类型从untrusted_app改成其他域,比如system_app,前提是你的应用确实有系统级权限。
警告:千万不要为了省事直接注释掉neverallow规则!我曾经见过有人这么干,结果导致系统安全漏洞,后来被安全团队追着改了一个月。

12.3 策略规则冲突排查:多规则叠加的陷阱

有时候,单个规则看起来没问题,但多个规则叠加在一起就出事了。这种情况最隐蔽,也最难排查。

我记得有一次,一个同事说他的服务在permissive模式下跑得好好的,一切到enforcing就崩溃。我帮他看了一天,最后发现是两条规则冲突了:

  • 规则A:允许my_service_tcache_file_t执行write操作
  • 规则B:neverallow禁止my_service_tcache_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的理解就会更深一层。

SELinux策略错误排查知识体系 denied日志分析 • 查看scontext/tcontext • 识别tclass和操作 • 使用audit2allow • 人工审核规则 neverallow冲突 • 确认是否必要 • 修改neverallow规则 • 更换进程域类型 • 不可直接注释 规则冲突排查 • 条件规则叠加 • 全局vs局部冲突 • 使用sesearch • 对比allow/neverallow 常见错误案例 • 类型未定义 • 属性缺失 • 文件上下文错误 • 域转换缺失 排错 核心原则 看懂日志 → 理解约束 → 排查冲突 → 积累案例 推荐工具 audit2allow | sesearch | restorecon | dmesg | logcat
公众号:蓝海资料掘金营,微信deep3321