15. Android SELinux(四):neverallow规则、策略调试与审计
各位同学,今天我们来聊聊SELinux策略里最“硬核”的部分——neverallow规则、策略调试与审计。说实话,这部分内容在平时开发中可能不常用,但一旦遇到问题,它就是你的救命稻草。我自己在项目里就吃过不少亏,今天把这些经验分享给你。
15.1 neverallow规则:策略的“红线”
neverallow规则,说白了就是SELinux策略里的“红线”。它定义了什么操作是绝对不允许的。比如,你写了一条allow规则,允许某个域访问某个资源,但如果这条规则触发了neverallow,编译就会直接报错。
为什么会这样?因为neverallow是策略编译时的硬性检查。它不是为了运行时拦截,而是为了在策略开发阶段就堵住漏洞。我刚开始接触时,总觉得它多此一举,直到有一次我写了一条过于宽松的规则,差点让系统暴露在风险中。
核心要点:neverallow规则是策略的“安全底线”,任何违反它的规则都无法通过编译。
15.1.1 neverallow的语法
neverallow的语法和allow很像,但含义完全相反。看个例子:
neverallow { domain -untrusted_app } self:process execmem;
这条规则的意思是:除了untrusted_app之外,任何域都不能执行可执行内存(execmem)。如果你试图给system_server添加execmem权限,编译就会失败。
我个人习惯在写策略前,先看看已有的neverallow规则。这样能避免走弯路。你想想看,如果一条规则注定通不过,何必浪费时间呢?
15.1.2 常见的neverallow陷阱
我在项目中遇到过这样一个坑:给一个系统服务添加了访问网络设备的权限,结果编译报错。查了半天,发现是neverallow规则禁止了非网络域直接访问网络设备。解决办法是让这个服务通过netd来间接访问。
避坑指南:我曾经因为没仔细看neverallow规则,写了一条看似合理但实际违规的规则。结果编译失败,排查了整整一天。建议你在写新规则前,先用checkpolicy工具检查一下。
15.2 策略调试:从“黑盒”到“白盒”
策略调试是SELinux开发中最头疼的部分。系统跑着跑着突然报avc: denied,你根本不知道哪里出了问题。别急,我来教你几招。
15.2.1 启用permissive模式
permissive模式是调试的“神器”。在这个模式下,SELinux只记录违规操作,但不拦截。你可以通过以下命令启用:
adb shell setenforce 0
但要注意,permissive模式会降低安全性。我建议只在开发机上使用,千万别在生产环境里这么干。
15.2.2 分析avc日志
avc日志是调试的核心。当SELinux拒绝一个操作时,会打印类似这样的日志:
avc: denied { read } for pid=1234 comm="app_process" name="secret.txt" dev="mmcblk0p1" ino=5678 scontext=u:r:untrusted_app:s0 tcontext=u:object_r:secret_file:s0 tclass=file
这条日志告诉你:untrusted_app想读取secret_file,但被拒绝了。你需要添加一条allow规则:
allow untrusted_app secret_file:file read;
嗯,这里要注意:avc日志里的scontext和tcontext一定要看仔细。我见过有人把源和目标搞反,结果规则写错了,问题依旧。
15.2.3 使用audit2allow工具
audit2allow是个自动化工具,能根据avc日志生成对应的allow规则。用法很简单:
adb shell dmesg | audit2allow -p policy.conf
但我不建议完全依赖它。因为audit2allow生成的规则往往过于宽松。我曾经用它生成了一条规则,结果允许了不必要的权限,差点引入安全漏洞。所以,用它作为参考,然后手动优化。
15.3 审计:谁在做什么?
审计是SELinux的“监控摄像头”。它能记录系统中所有敏感操作,帮你发现异常行为。
15.3.1 配置审计规则
审计规则通过auditallow语句定义。比如:
auditallow untrusted_app secret_file:file read;
这条规则会让SELinux在untrusted_app读取secret_file时,打印一条审计日志。注意,auditallow不会阻止操作,它只是记录。
我个人习惯在关键资源上开启审计。比如,系统配置文件、用户数据目录等。这样一旦有人越权访问,我能第一时间发现。
15.3.2 审计日志分析
审计日志和avc日志类似,但多了audit字样。你可以用logcat或dmesg查看。举个例子:
audit: avc: granted { read } for pid=1234 comm="app_process" name="secret.txt" dev="mmcblk0p1" ino=5678 scontext=u:r:untrusted_app:s0 tcontext=u:object_r:secret_file:s0 tclass=file
这条日志告诉你:untrusted_app成功读取了secret_file。如果你发现这个操作不应该发生,那就说明策略有问题,需要收紧。
小技巧:审计日志会占用系统资源,别开太多。我建议只审计那些真正敏感的操作,比如访问密码文件、修改系统设置等。
15.4 知识体系图:neverallow、调试与审计的关系
下面这张图展示了本章的核心逻辑。你可以看到,neverallow是策略的“红线”,调试是解决问题的“工具”,审计是监控的“眼睛”。三者相辅相成,共同保障系统安全。
15.5 实战:一个完整的调试案例
最后,我给你分享一个我实际遇到的案例。有一次,系统启动时总是报avc: denied,导致某个服务无法正常运行。我通过以下步骤解决了问题:
- 启用permissive模式:先让系统跑起来,收集所有违规日志。
- 提取avc日志:用
dmesg | grep avc过滤出所有拒绝记录。 - 分析日志:发现是system_server试图访问一个自定义的socket文件。
- 编写规则:手动添加了一条allow规则,并检查是否违反neverallow。
- 编译测试:重新编译策略,部署后问题解决。
你看,整个过程并不复杂。关键是你要理解neverallow、调试和审计这三者的关系。嗯,今天的内容就到这里。记住,SELinux策略开发没有捷径,多动手、多分析日志,你也能成为专家。