9. SELinux基础(一):SELinux发展史、DAC与MAC的区别、安全上下文

好,咱们今天聊聊SELinux。说实话,这玩意儿刚出来的时候,我也觉得它挺烦人的。动不动就"avc: denied",日志里一堆看不懂的报错。但后来我真正吃透它之后,才发现——它是Android安全体系里最硬的一道防线。

你想想看,没有SELinux之前,系统靠什么保护自己?靠权限。但权限这玩意儿,说白了就是个"一锤子买卖"——你给了某个App读取SD卡的权限,它就能读你所有的照片。这合理吗?显然不合理。SELinux要解决的,就是这个"权限滥用"的问题。

9.1 SELinux的发展史:从NSA到Android

SELinux的全称是Security-Enhanced Linux。它最早是美国国家安全局(NSA)搞出来的。嗯,你没听错,就是那个NSA。2000年左右,他们发现Linux内核的权限模型太弱了,于是联合SELinux社区一起开发了一套强制访问控制机制。

我记得最早接触SELinux是在做嵌入式Linux的时候。那时候它还是个可选模块,很多发行版默认都不开。但到了Android 4.3(Jelly Bean),Google开始把它引入Android。到了Android 5.0(Lollipop),就全面强制开启了。

为什么会这样?因为Android的碎片化太严重了。厂商定制、第三方ROM、恶意App……光靠传统的权限模型根本防不住。SELinux的引入,相当于给系统加了一层"兜底"的保险。

关键时间节点:

  • 2000年:NSA发布SELinux初始版本
  • 2003年:SELinux进入Linux内核主线
  • 2013年:Android 4.3开始实验性引入
  • 2015年:Android 5.0全面强制开启SELinux

9.2 DAC与MAC的区别:权限模型的进化

要理解SELinux,得先搞清楚两个概念:DAC和MAC。

DAC(自主访问控制),就是咱们平时用的Linux权限模型。每个文件有owner、group、others三组权限。谁创建的文件,谁就能决定谁能访问它。听起来挺合理对吧?但问题在于——root用户不受限制。

我举个例子。你在手机上装了一个App,它申请了"读取联系人"的权限。你同意了。然后这个App被恶意利用了,攻击者拿到了它的进程ID。在DAC模型下,这个进程可以读取任何它有权访问的文件——包括你的短信、照片、甚至系统配置文件。只要它拿到了root权限,整个系统就裸奔了。

MAC(强制访问控制)就不一样了。它由系统管理员(或者安全策略)统一制定规则。每个进程和每个资源都有一个"安全上下文"。能不能访问,不是看你是谁,而是看你的安全上下文和资源的安全上下文是否匹配。

说白了,DAC是"你说了算",MAC是"规则说了算"。在MAC模型下,就算你拿到了root权限,也得遵守安全策略。你想读一个不该读的文件?不行,策略不允许。

特性 DAC MAC
控制主体 文件所有者 系统安全策略
root权限 无限制 受策略约束
灵活性 低(策略严格)
安全性
典型应用 普通Linux Android、Red Hat

我的经验:在Android系统里,DAC和MAC是共存的。DAC负责基础的权限控制,MAC负责更细粒度的安全策略。两者配合使用,才能达到最佳效果。我曾经在调试一个系统服务时,明明DAC权限都对了,但就是访问不了某个文件。查了半天,才发现是SELinux策略给拦了。

9.3 安全上下文:SELinux的核心概念

安全上下文(Security Context)是SELinux里最基础的概念。每个进程、每个文件、每个套接字……所有系统资源都有一个安全上下文。它长什么样呢?

user:role:type:level

嗯,就是四个字段,用冒号隔开。咱们一个一个来看。

user:SELinux用户。在Android里,通常只有一个用户——u。别跟Linux系统用户搞混了,这是SELinux自己的用户概念。

role:角色。用于基于角色的访问控制(RBAC)。在Android里,角色通常也是固定的,比如r

type:类型。这是最关键的字段。SELinux的强制访问控制,主要就是靠类型来实现的。每个进程有一个"域"(domain),每个文件有一个"类型"(type)。能不能访问,就看域和类型之间的策略规则。

level:安全级别。用于多级安全(MLS)或多类别安全(MCS)。Android里用得不多,但有些场景会用到。

举个例子。一个典型的Android进程安全上下文:

u:r:untrusted_app:s0:c15,c256,c512,c768

这个上下文表示:这是一个不受信任的App进程,运行在untrusted_app域中,安全级别是s0,带有一些MCS类别。

再看一个系统服务的:

u:r:system_server:s0

这是系统服务进程,运行在system_server域中。它的权限比普通App大得多。

核心逻辑:SELinux的策略就是定义"哪个域可以访问哪个类型"。比如:

allow untrusted_app app_data_file:file read;

这条规则的意思是:允许untrusted_app域中的进程,读取类型为app_data_file的文件。

9.4 安全上下文在Android中的实际应用

咱们来看看实际系统里,安全上下文是怎么用的。我随便找一个文件看看:

$ ls -Z /data/data/com.example.app/
u:object_r:app_data_file:s0:c15,c256,c512,c768  cache
u:object_r:app_data_file:s0:c15,c256,c512,c768  databases
u:object_r:app_data_file:s0:c15,c256,c512,c768  files

注意看,ls -Z会显示SELinux上下文。这里的object_r表示这是一个对象(文件)的角色。类型是app_data_file,跟进程的untrusted_app域是配对的。

再看一个系统文件:

$ ls -Z /system/bin/
u:object_r:system_file:s0  app_process
u:object_r:system_file:s0  sh
u:object_r:system_file:s0  toolbox

系统文件的类型是system_file,只有系统服务域(如system_server)才能访问。普通App想读?门都没有。

注意:我曾经遇到过一个坑。有个App需要读取/proc下的某个文件,DAC权限明明给了,但就是读不到。一查SELinux日志,发现是untrusted_app域没有proc类型的读权限。后来在策略里加了一条allow untrusted_app proc:file read;才解决。嗯,这种问题在调试第三方App时特别常见。

9.5 知识体系总览

下面这张图,把咱们这一章的核心逻辑串起来了。你可以看到SELinux从发展史到核心概念的完整脉络。

SELinux基础(一)知识体系 SELinux发展史 NSA → Linux内核 → Android DAC vs MAC 自主访问控制 vs 强制访问控制 安全上下文 user:role:type:level 2000年 NSA发布 2003年 进入Linux内核 2013年 Android 4.3引入 2015年 Android 5.0强制 DAC(自主访问控制) 所有者决定权限,root无限制 MAC(强制访问控制) 策略决定权限,root也受限 两者共存,DAC + MAC 双重防护 user: SELinux用户 role: 角色(RBAC) type: 类型(核心) level: 安全级别(MLS/MCS) 核心:安全上下文 → 域与类型 → 策略规则 → 访问控制

嗯,这一章的内容就到这儿。SELinux的基础概念其实不难理解,关键是要把"安全上下文"这个核心概念吃透。后面咱们会深入策略编写和调试技巧,到时候你就知道这东西有多强大了。

避坑指南:刚开始学SELinux,最容易犯的错误就是——把DAC和MAC搞混。记住一句话:DAC管"能不能看到",MAC管"能不能访问"。我曾经有个同事,调试一个文件访问问题,折腾了两天,最后发现DAC权限给了,但SELinux策略没写。嗯,从那以后他再也不敢忽略SELinux了。

公众号:蓝海资料掘金营,微信deep3321