SELinux策略:域转换与类型继承

发布于:2025-09-12 ⋅ 阅读:(20) ⋅ 点赞:(0)

一. 域(Domain)转换

域转换是 SELinux 中一个基础且强大的安全概念。它控制着一个进程如何从一种安全上下文(域)切换到另一种,通常是获取更高权限的过程

为什么需要域转换?

在 Android 中,你绝不希望一个普通的应用进程(运行在 untrusted_app 域)直接执行一个位于 /system/bin 的二进制文件并继承 system_server 的权限。这将是巨大的安全漏洞。域转换确保了这种权限提升必须通过明确的、被策略允许的路径发生

域转换发生的条件

一个成功的域转换需要满足三个条件,通常通过 domain_auto_trans 宏来声明,该宏会一次性添加所有三条规则

  1. 执行权限(Execute Permission)
    ○ 父进程(在源域 source_domain)必须对要执行的可执行文件(具有目标类型 target_type)有 execute 权限
    规则类型allow source_domain target_type:file execute;
  2. 入口权限(Entrypoint Permission)
    ○ 新的进程(即将运行在目标域 new_domain)必须能够将其入口点(即它所执行的那个程序文件)标识为被允许的入口
    ○ 这相当于说:“只有被标记为类型 T 的文件,才能作为进入域 D 的入口”
    ○ 规则类型allow new_domain target_type:file entrypoint;
  3. 转换权限(Transition Permission)
    ○ 父进程(源域)必须被允许将子进程转换到新的域
    ○ 规则类型allow source_domain new_domain:process transition;

此外,还有一个隐含条件:系统必须知道执行该文件后应该切换到哪个新域。这是通过文件的安全上下文实现的。可执行文件必须本身就被标记为正确的目标类型(target_type),而这个 target_type 会通过策略规则映射到 new_domain

实际案例:zygote 启动 system_server

这是 Android 中最经典的域转换例子

  1. 参与者
    源域zygote (一个特权进程,负责孵化新进程)
    可执行文件/system/bin/app_process64 (被标记为 app_exec_type,例如 system_file)
    目标域system_server (Android 核心系统进程的域)
  2. 转换过程
    ○ zygote 进程 fork 自身
    ○ 在子进程中,它准备执行 /system/bin/app_process64 并指定参数以启动 system_server
    ○ 在执行 (execve) 之前,SELinux 检查策略
    ○ 策略中会有一条规则(通常由 domain_auto_trans 宏生成):
    # 这通常隐藏在宏中,但效果如下:
    allow zygote app_exec_type:file execute;
    allow system_server app_exec_type:file entrypoint;
    allow zygote system_server:process transition;
    # 最关键的一步:自动转换规则
    domain_auto_trans(zygote, app_exec_type, system_server)

    ○ 由于可执行文件 app_exec_type 是进入 system_server 域的有效 entrypoint,并且所有权限都满足,执行后子进程的安全上下文就从 zygote 成功转换为了 system_server

手动转换:domain_trans

有时转换不是自动的,需要进程主动调用 setcon()。这时使用 domain_trans 规则,它只包含 transition 权限,而不触发自动转换

二. 类型(Type)继承

类型继承是 SELinux 策略语言中用于代码重用简化策略管理的重要特性。它允许你创建一个新的类型属性(Attribute),并让它继承现有属性的所有规则

为什么需要类型继承?

想象一下,你有 100 个不同的服务域(service_a_domainservice_b_domain, ...),它们都需要访问设备节点(dev_type)。没有继承,你需要写 100 条 allow 规则:

allow service_a_domain dev_type:chr_file rw;
allow service_b_domain dev_type:chr_file rw;
...
allow service_zz_domain dev_type:chr_file rw;

这非常冗长且难以维护。类型继承解决了这个问题

如何工作:属性(Attributes)

继承的核心是属性。一个属性是一组类型的集合

  1. 定义属性:在 attributes 文件中声明一个属性
    # attributes
    attribute my_custom_domain;
    attribute my_custom_file_type;
  2. 将类型与属性关联:在 .te 文件中,使用 type 语句并加上 attributes 参数
    # 将 service_a_domain 类型关联到 my_custom_domain 属性
    type service_a_domain, domain, my_custom_domain;
    
    # 将 service_a_exec 类型关联到 my_custom_file_type 属性
    type service_a_exec, exec_type, file_type, my_custom_file_type;
  3. 为属性编写规则:现在,你可以编写一条针对属性的规则,所有属于该属性的类型都会自动生效
    # 一条规则覆盖所有!
    allow my_custom_domain my_custom_file_type:file entrypoint;
    allow my_custom_domain dev_type:chr_file rw;
    allow my_custom_domain kernel:system syslog_read;

    这等价于为 service_a_domainservice_b_domain 等所有标记了 my_custom_domain 的类型分别写了上述三条规则

在 Android 中的实际应用

Android 广泛使用属性来管理策略

  • coredomain: 几乎所有核心 Android 系统进程域(如 system_serverservicemanagersurfaceflinger)都继承了这个属性。一条针对 coredomain 的规则会应用到所有这些重要的域上
    # 允许所有核心域使用系统日志
    allow coredomain kernel:system syslog_read;
  • appdomain: 所有应用域(platform_appuntrusted_app)都继承自此属性。可以用来定义所有应用都应遵守的通用规则
  • net_domain: 所有需要网络的域继承自此属性。可以用来集中管理网络访问规则

注意:属性是集合的集合,规则中的属性可以出现在源(subject)或目标(object)的位置,极大地增强了策略的灵活性和可维护性

总结与关系

特性 域转换(Domain Transition) 类型继承(Type Inheritance)
目的 控制进程权限提升,确保安全边界 简化策略管理,实现规则重用和集中化管理
机制 通过 executeentrypointtransition 权限和控制可执行文件标签来实现自动或手动的域切换 通过属性(Attribute) 将类型分组,允许为整个组编写统一的 allow 规则
关键规则 domain_auto_trans(source_domain, target_type, new_domain) type my_type, attribute1, attribute2; allow attribute1 attribute2:class perm;
类比 函数调用:有严格的参数和权限检查才能进入 面向对象编程中的继承:一个子类(具体类型)继承父类(属性)的所有特性(规则)

两者如何协同工作

在复杂的 Android 系统中,这两种机制紧密结合。例如,一个服务的可执行文件类型可能继承自 service_exec_type 属性,这使得所有服务二进制文件自动获得作为 entrypoint 所需的规则。而启动该服务的进程(如 init 或 zygote)则通过域转换规则,被允许转换到该服务域,而这个服务域本身可能又继承自 coredomain 属性,从而自动拥有核心域的一系列权限


网站公告

今日签到

点亮在社区的每一天
去签到