SELinux策略配置在Android内核中的实战应用 - 第1节

1.1 什么是 SELinux

SELinux(Security-Enhanced Linux)是一个由美国国家安全局(NSA)开发的 Linux 内核安全模块,它通过强制访问控制(MAC)机制,为系统提供细粒度的权限管理。在 Android 系统中,SELinux 被集成到内核中,用于限制进程和用户对文件、设备、网络等资源的访问,即使进程以 root 权限运行,也无法绕过 SELinux 的策略约束。

核心思想:SELinux 遵循“默认拒绝”原则——任何未被明确允许的访问操作都会被阻止。这与传统 Linux 的“默认允许”权限模型形成鲜明对比。

SELinux 的工作模式

SELinux 支持三种工作模式,在 Android 中通常使用 Enforcing 模式以确保安全策略强制执行:

模式 行为 Android 默认状态
Enforcing 强制执行策略,拒绝违规操作并记录日志 Android 5.0+ 默认启用
Permissive 不阻止违规操作,仅记录警告日志 仅用于调试或开发阶段
Disabled 完全关闭 SELinux,不进行任何检查 不推荐,会降低系统安全性
实战提示:在开发自定义 SELinux 策略时,建议先在 Permissive 模式下收集审计日志(avc: denied),确认所有必要的访问权限都被正确允许后,再切换到 Enforcing 模式。

1.2 MAC 与 DAC 的区别

理解 SELinux 的关键在于区分自主访问控制(DAC)和强制访问控制(MAC)。传统 Linux 使用 DAC,而 SELinux 在 DAC 之上叠加了 MAC 层。

DAC(自主访问控制)

在 DAC 模型中,资源的拥有者可以自行决定谁可以访问该资源。例如,文件所有者可以通过 chmod 命令设置文件权限(rwx)。DAC 的局限性在于:

  • 权限提升漏洞:一旦进程获得 root 权限,它可以访问系统上所有资源。
  • 粗粒度:权限仅基于用户、组、其他三类,无法精确控制“某个特定进程”对“某个特定文件”的操作。
  • 无类型强制:无法区分“系统服务”和“用户应用”的访问行为。

MAC(强制访问控制)

MAC 由系统管理员(或策略文件)统一制定规则,所有主体(进程)和客体(文件、端口等)都被赋予安全上下文(Security Context)。访问决策基于预定义的策略,而非资源拥有者的意愿。MAC 的优势:

  • 最小权限原则:即使进程以 root 运行,也只能访问策略允许的资源。
  • 细粒度控制:可以精确到“哪个进程”对“哪个文件”进行“哪种操作”(读、写、执行等)。
  • 隔离性:不同安全域的应用和服务被严格隔离,防止横向移动攻击。

对比表格

特性 DAC(传统 Linux) MAC(SELinux)
控制粒度 用户/组/其他(3 类) 进程 × 文件 × 操作(任意组合)
权限继承 子进程继承父进程权限 子进程拥有独立的安全上下文
root 用户限制 无限制(root 可做任何事) 受策略约束(root 也无法绕过)
策略管理 由资源所有者管理 由系统策略文件统一管理
默认行为 允许(除非明确拒绝) 拒绝(除非明确允许)
常见误区:很多开发者认为“只要关闭 SELinux 或设为 Permissive 模式,应用就能正常工作”。实际上,这会导致系统安全防护降级,且无法通过 CTS(兼容性测试套件)认证。正确的做法是为应用编写合适的 SELinux 策略。

1.3 SELinux 在 Android 安全体系中的角色

Android 的安全体系是一个多层防御模型,SELinux 位于最底层的内核安全层,与其他安全机制协同工作:

Android 安全体系架构 应用沙箱层 每个应用运行在独立的 UID/GID 沙箱中,通过 Linux DAC 隔离 Android 框架层 权限管理(Android Permissions)、应用签名验证、Keystore Linux 内核层 DAC(标准 Linux 权限)、命名空间、seccomp-bpf SELinux 强制访问控制层 基于安全上下文的 MAC 策略,覆盖所有内核对象(文件、进程、套接字等) 硬件安全层 TEE(可信执行环境)、硬件密钥、Verified Boot DAC 隔离 UID/GID 沙箱 权限检查 运行时权限 MAC 策略 安全上下文

SELinux 在 Android 中的关键作用

  1. 限制系统服务:即使系统服务(如 mediaserver、surfaceflinger)被攻破,SELinux 策略也能阻止其访问非授权的文件或设备。
  2. 隔离应用数据:不同应用之间的数据访问受到严格限制,即使它们拥有相同的 UID,SELinux 也能通过类型强制(Type Enforcement)进行二次隔离。
  3. 保护内核对象:控制对 /proc、/sys 等敏感文件系统的访问,防止恶意进程篡改内核参数或获取系统信息。
  4. 支持多用户场景:在 Android 多用户或工作资料(Work Profile)模式下,SELinux 确保不同用户的数据完全隔离。

安全事件处理流程

当 SELinux 阻止一个访问请求时,会生成一条审计日志(通常包含 avc: denied 关键字)。开发者可以通过分析这些日志来调整策略:

# 查看 SELinux 审计日志(需要 root 权限)
adb shell dmesg | grep "avc: denied"

# 示例输出:
# type=1400 audit(123456.789:0): avc: denied { read } for pid=1234 comm="app_process" name="secret.txt" dev="mmcblk0" ino=5678 scontext=u:r:untrusted_app:s0 tcontext=u:object_r:app_data_file:s0 tclass=file permissive=0
实战技巧:在开发阶段,可以使用 adb shell setenforce 0 临时切换到 Permissive 模式,然后运行应用并收集所有 avc: denied 日志。将这些日志导入 audit2allow 工具,可以自动生成所需的 SELinux 策略规则。

SELinux 与 Android 安全机制的协同

安全机制 层级 与 SELinux 的关系
应用沙箱(UID/GID) 应用层 SELinux 在 DAC 之上提供第二层隔离,防止 UID 泄露后的越权访问
Android 权限系统 框架层 SELinux 控制底层资源访问,Android 权限控制高层 API 调用
seccomp-bpf 内核层 seccomp 限制系统调用,SELinux 限制内核对象访问,两者互补
Verified Boot 硬件层 确保系统分区完整性,SELinux 策略文件在验证后加载
重要提醒:SELinux 不是万能的。它无法防御内核漏洞(如内核提权漏洞),也无法阻止应用层的逻辑攻击。SELinux 是纵深防御体系中的一环,必须与其他安全机制配合使用才能发挥最大效果。