第3章 应用域隔离设计原则
SELinux 应用域隔离的核心在于通过 最小权限、类型划分 和 域边界定义 三个原则,将系统划分为相互隔离的运行时环境。每个应用进程运行在独立的域中,仅能访问为其显式授权的资源,从而限制攻击面并防止水平提权。本章从原理、实现流程、配置指令、调试方法到常见错误,系统讲解这三条原则如何在策略编写中落地。
知识前置:域(Domain)在 SELinux 中即进程的安全上下文(security context)首要字段“类型”(type),例如
httpd_t、mysqld_t。域隔离通过类型强制访问控制(TE)实现,每个域对应一组访问向量规则。
3.1 最小权限原则
原理:每个域只能获得完成其任务所必需的最小权限集,任何非必要文件、端口、IPC 对象均被拒绝。在 SELinux 策略中,这表现为精确的目标规则(targeted allow rules),而非通配符。
实现流程:
- 列举应用所有访问行为(读文件、写日志、连接端口、执行程序等)。
- 为每种行为编写
allow规则,避免使用self或*代替具体客体类型。 - 使用
neverallow断言确保未授权的访问不会被意外打开。
配置示例(策略片段 .te 文件):
type myapp_t;
type myapp_data_t;
files_type(myapp_data_t)
# 仅允许读取 /var/myapp 下的文件
allow myapp_t myapp_data_t:file { read getattr open };
# 禁止写入(除非显式添加)
neverallow myapp_t myapp_data_t:file write;
# 仅允许监听 9999 TCP 端口
allow myapp_t self:tcp_socket { create bind listen accept };
corenet_tcp_bind_all_nodes(myapp_t)
corenet_tcp_bind_generic_port(myapp_t)
gen_tunable(allow_myapp_extra_port, false)
调试命令: 使用
sesearch -A -s myapp_t 列出所有允许规则,检查是否出现意外的大范围权限。使用 seinfo -tmyapp_t -x 查看类型属性。
3.2 类型划分原则
原理:每个应用域拥有唯一的安全上下文类型(如 myapp_t),其管理的文件、进程、套接字也使用独立的类型标签(如 myapp_data_t、myapp_log_t)。类型划分是域隔离的基础,避免类型复用导致的权限泄露。
常用类型命名规范与划分策略:
| 资源类别 | 类型命名示例 | 说明 |
|---|---|---|
| 进程域 | myapp_t | 应用主进程类型 |
| 数据文件 | myapp_data_t | 应用私有数据,仅本域可读写 |
| 日志文件 | myapp_log_t | 日志输出,通常只写不读 |
| 临时文件 | myapp_tmp_t | /tmp 下临时文件,使用 tmpfile 域 |
| 网络套接字 | myapp_port_t | 绑定的 TCP/UDP 端口 |
类型声明示例(.te 文件):
type myapp_t;
type myapp_data_t;
type myapp_log_t;
type myapp_tmp_t;
type myapp_port_t;
# 标记文件目录
fs_manage_files_pattern(myapp_t, myapp_data_t, myapp_data_t)
fs_manage_dirs_pattern(myapp_t, myapp_data_t, myapp_data_t)
3.3 域边界定义原则
原理:域边界通过 域转换(domain transition) 和 显式允许规则 严格定义。一个进程只能通过执行转换规则(type_transition 或 domain_auto_trans)进入其他域,且必须同时具备源域和目标域的 entrypoint 与 fdtrans 权限。跨域访问(如域A读取域B的文件)默认被拒绝,除非策略显式写入 allow 规则。
域边界定义的关键策略元素:
- 域转换入口:
domain_entry_file(myapp_t, myapp_exec_t)声明可执行文件的类型作为入口。 - 自动转换规则:
domain_auto_trans(init_t, myapp_exec_t, myapp_t)使 systemd 启动时自动切换域。 - 类型边界(typebounds): 用于隔离子域,防止父域权限丢失。
实现流程:
- 定义入口文件类型
myapp_exec_t,并关联到可执行文件。 - 编写
domain_auto_trans或显式type_transition规则。 - 使用
allow myapp_t myapp_exec_t:file { read getattr execute }赋予执行权限。 - 使用
neverallow禁止非预期的域转换(如neverallow ~myapp_t myapp_t:process transition)。
type myapp_exec_t;
files_type(myapp_exec_t)
# 域自动转换:从 init_t 执行 /usr/bin/myapp 时自动进入 myapp_t
domain_auto_trans(init_t, myapp_exec_t, myapp_t)
# 确保只有本域才能进入
allow myapp_t myapp_exec_t:file entrypoint;
allow init_t myapp_exec_t:file { read getattr execute };
3.4 调试与验证方法
- 查看域当前上下文:
ps -eZ | grep myapp确认进程运行在myapp_t域。 - 检查类型边界:
sesearch -d -s myapp_t -c process -p transition列出域转换规则。 - 模拟访问检查:
sechecker -a /etc/selinux/targeted/policy/policy.* 2>&1 | grep myapp扫描冲突。 - AVC 审计日志:
ausearch -ts recent -m avc -tsc all | grep myapp查看拒绝事件。
3.5 常见错误与优化建议
| 错误场景 | 原因 | 解决方案 |
|---|---|---|
进程启动后仍为 init_t | 缺少域转换规则或入口文件类型错误 | 确认 domain_auto_trans 与 entrypoint 权限 |
| AVC 拒绝访问数据文件 | 未授权 read 或 write | 添加 allow myapp_t myapp_data_t:file { read open } |
| 跨域读文件被拒绝 | 域边界原则禁止,需显式授权 | 评估是否为合法需求,若必须则编写有限的跨域规则 |
| 性能问题:大量域转换 | 频繁执行类型转换导致上下文切换 | 合并子域或使用 typebounds 限制转换频次 |
稳定性要点:域边界定义不宜过细,避免产生数百个小型域导致策略加载缓慢。推荐每个独立应用至少一个域,共享库型进程可归入同一域。使用
typebounds 控制继承关系,确保父域权限不被子域破环。