SELinux 是什么,为什么安卓关不掉也绕不开
前面几篇聊了 root、权限模型这些话题,里面反复提到”UID 0 能绕过大部分权限限制”,但严格来说,现在的安卓设备上,拿到 root 权限并不等于真的能为所欲为——中间还挡着一层叫 SELinux 的机制。这篇讲讲它是什么。
传统权限模型的局限
前面提过,安卓沿用的 Linux 权限体系,靠的是基于 UID 的自主访问控制(DAC)——本质是”谁拥有这个文件/资源,谁就有权决定谁能访问它”,而 root(UID 0)作为特殊身份,直接绕过这套基于所有权的检查。
这套模型有个天然的弱点:一旦某个进程拿到了 root 权限(不管是合法提权还是被攻击者利用漏洞拿到的),它几乎可以不受约束地访问系统上的任何资源。换句话说,DAC 模型里,root 是一个”全有或全无”的开关,没有更细的约束层。
SELinux 加了一层”强制访问控制”
SELinux(Security-Enhanced Linux)是 Linux 内核里的一个安全模块,提供的是另一套独立的权限检查体系,叫强制访问控制(MAC,Mandatory Access Control)。和 DAC 不一样,MAC 不看”谁拥有这个资源”,而是由系统管理员(在安卓这里就是厂商)预先定义好一整套策略,规定”哪个类型的进程,只能对哪些类型的资源,执行哪些具体操作”,这套策略对所有进程一视同仁地生效——即便是 UID 0 的 root 进程,如果它尝试执行的操作不在策略允许范围内,SELinux 依然会拦下来。
具体做法是给系统里的每个进程、每个文件都打上一个”安全上下文标签”(Context),内核在处理每一次访问请求时,除了原本的 DAC 检查,还会额外查一遍:发起请求的这个上下文标签,有没有被策略明确允许对目标的这个上下文标签执行这个操作。DAC 和 SELinux 这两层检查是”与”的关系,必须同时通过,访问才会被放行。
Enforcing 和 Permissive 两种状态
SELinux 通常有几种工作模式,安卓上常见的是:
- Enforcing(强制模式):严格按策略拦截不合规的访问请求,这也是现在所有正式出厂的安卓设备强制要求使用的模式
- Permissive(宽松模式):不合规的访问请求不会被真的拦下来,但会记录到日志里,通常只在开发调试阶段使用
谷歌从 Android 4.4 前后开始,就逐步把 Enforcing 模式作为设备通过官方兼容性认证(CTS)的硬性要求之一。这意味着即便某个应用或者攻击代码想办法拿到了 root 权限,只要 SELinux 策略没有针对性地开放,它依然没法访问策略之外的资源,大幅缩小了单纯靠”提权”就能造成的破坏范围。
和刷机、root 有什么关系
这也是为什么一些深度定制操作(比如某些自定义模块、老旧的 root 方案)有时候需要连带修改 SELinux 策略,或者临时把状态切到 Permissive 才能生效——不是 DAC 层面的权限不够,而是 SELinux 这层策略没有把这个具体操作纳入允许范围。像 Magisk 这类现代方案,做法通常是精细地给自己需要用到的操作单独打补丁、追加策略规则,而不是粗暴地整体关闭 SELinux,这样既能让功能正常工作,也不会把设备整体的安全边界拆掉。
小结
SELinux 相当于在传统的”谁拥有就归谁管”的权限模型之上,又加了一层”不管你是谁,规则里没写的事一律不能做”的强制约束,而且这层约束连 root 都不能例外。理解了这一层,就知道为什么现在拿到 root 权限,也不等于设备失去了所有安全边界——真正兜底的,其实是这套很少被人注意到的策略系统。