自定义 su 的 SELinux 域——App Profile 逃逸与 NO_NEW_PRIVS 防范
SELinux 是什么
SELinux 是强制访问控制(MAC)机制,按默认拒绝原则运行:任何未经明确允许的行为都被拒绝。它有两种全局模式——宽容模式(只记录不拦截)与强制模式(记录并拦截)。
现代 Android 极度依赖 SELinux 保障安全,不要使用任何以宽容模式运行的自定义系统,那与裸奔无异。其完整工作方式较复杂,想深入可自行查阅 SELinux 的百科词条与 Redhat、ArchLinux 的系统文档。
KernelSU 里的自定义域
应用执行 su 后,默认切进一个不受限制的域(如 u:r:ksu:s0)。Root Profile 可以把它切到自定义域并为其定制规则,例如:
type app1
enforce app1
typeattribute app1 mlstrustedsubject
allow app1 * * *
注意示例中的 allow app1 * * * 仅作演示——它放行一切,与宽容模式差别不大,实际不应这样写。规则应当逐项列出真正需要的访问权限。
逃逸:配置不当的连锁反应
如果 Root Profile 配置不合理,限制可能意外失效。经典场景:
- 你给 ADB shell 用户(UID 2000)允许了 root——这是相当常见的配置;
- 你给某普通应用允许 root,但把它的 profile UID 设为 2000;
- 结果:应用第一次
su被降到 UID 2000,第二次su时它已是「2000 用户」,命中第 1 条规则,拿到完整 root!
两次 su,逃出生天。根因是权限链路里出现了「可提权的中转身份」。
防范手段
- 在自定义 App Profile 中启用 NO_NEW_PRIVS 标志:阻止该进程再次通过 su 提升权限;
- 但注意:该标志只拦 KernelSU 的 su 提权,进程仍可能借助其他 Linux 机制逃逸;
- 根本原则是自查权限链:凡是「允许 root」的身份,都不能出现在其他应用的降级 profile 里。
配置思路总览见 App Profile 总览,实践建议与 Capabilities 权能 配合阅读。