2. 策略语言入门:te 文件语法、规则类型、allow 与 auditallow
2.1 te 文件语法基础
SELinux 策略的核心载体是类型强制(Type Enforcement,TE)文件,后缀为 .te。一个标准的 te 文件遵循固定的结构,由模块声明、类型/属性声明、规则列表三部分组成。所有策略语句都必须以分号结尾,注释使用 #。
- 模块声明:
policy_module(模块名, 版本号),每个独立策略包必须以此为开头。 - 类型/属性声明:
type 类型名;/attribute 属性名;,定义主体与客体的安全标签。 - 规则列表:由 allow、auditallow、dontaudit、neverallow 等规则构成,描述访问控制矩阵。
最小 te 文件骨架:
policy_module(myapp, 1.0.0)
type myapp_t;
type myapp_data_t;
type myapp_exec_t;
allow myapp_t myapp_data_t:file read;
allow myapp_t myapp_exec_t:file execute;
2.2 规则类型总览
SELinux 提供四种核心规则类型,分别对应不同的授权与审计策略。下表从授权效果、审计行为和编译期检查三个维度进行对比:
| 规则类型 | 授权效果 | 审计行为 | 编译期检查 | 典型用途 |
|---|---|---|---|---|
| allow | 授予访问权限 | 不记录(默认静默) | 无 | 日常正常访问路径 |
| auditallow | 授予访问权限 | 强制记录成功访问 | 无 | 合规审计、敏感操作 |
| dontaudit | 拒绝访问(不授权) | 不记录(静默拒绝) | 无 | 压制预期内的拒绝噪声 |
| neverallow | 编译期禁止规则存在 | 不适用 | 强制校验 | 安全基线、全局约束 |
关键区分:allow 只授权不审计;auditallow 授权且强制审计;dontaudit 拒绝且不记录;neverallow 在编译时禁止某类规则出现,是静态约束,不产生运行时效果。
2.3 策略语言体系结构
下图完整展示了 te 文件到规则类型的层次关系,以及 allow 与 auditallow 在策略体系中的位置:
2.4 allow 规则详解
allow 是策略中使用最频繁的规则类型,格式为:
allow source_type target_type:class perm_set;
- source_type:主体类型(通常是进程域)。
- target_type:客体类型(文件、套接字、进程等)。
- class:客体类别(file、dir、tcp_socket、unix_stream_socket 等)。
- perm_set:权限集合,可以是单个权限或花括号包裹的权限列表。
实际示例:
# 允许 myapp_t 读取 myapp_data_t 类型的文件
allow myapp_t myapp_data_t:file read;
# 允许 myapp_t 创建并连接 TCP 套接字
allow myapp_t self:tcp_socket { create bind connect listen accept };
# 允许 myapp_t 对 data 目录执行搜索与遍历
allow myapp_t myapp_data_t:dir { search read getattr };
权限集合支持使用通配符 *(表示该类下的所有权限)和 ~(表示排除指定权限后的所有权限)。但生产环境应遵循最小权限原则,避免过度授权。
性能提醒:过度使用通配符会扩大攻击面,同时增加策略缓存压力。建议始终显式列出所需的最小权限集。
2.5 auditallow 规则详解
auditallow 的语法与 allow 完全一致,区别在于:每当规则匹配成功时,内核会强制向 /var/log/audit/audit.log 写入一条 AVC 审计记录。格式:
auditallow source_type target_type:class perm_set;
典型应用场景:
- 合规审计:记录所有对敏感配置文件的写操作。
- 安全监控:记录域转换、特权提升等高危操作。
- 策略调试:临时开启 auditallow 验证规则是否命中。
审计日志示例:
# 对日志文件启用 auditallow
auditallow myapp_t myapp_log_t:file { write append };
# 触发写入时,audit.log 中会出现:
type=AVC msg=audit(1712345678.123:456): \
avc: granted { write } for pid=1234 \
comm="myapp" path="/var/log/myapp/app.log" \
scontext=system_u:system_r:myapp_t:s0 \
tcontext=system_u:object_r:myapp_log_t:s0 \
tclass=file
最佳实践:auditallow 会产生大量日志,高流量路径上请谨慎使用。建议先通过 audit2allow 从日志中提取必要规则,再决定哪些操作需要永久审计。
2.6 规则调试与验证
当策略行为不符合预期时,通过以下流程快速定位:
- 查看审计日志:
ausearch -m avc -ts recent或grep AVC /var/log/audit/audit.log - 使用 audit2allow 生成候选规则:
# 从日志中提取缺失的 allow 规则
grep "denied" /var/log/audit/audit.log | audit2allow -M mylocal
# 直接查看建议的 te 规则文本
grep "denied" /var/log/audit/audit.log | audit2allow
- 应用规则并重载策略:
semodule -i mylocal.pp - 确认规则生效:
sesearch --allow -s myapp_t -t myapp_data_t -c file
快速验证单条规则是否生效:
# 使用 sesearch 检查策略中是否存在指定规则
sesearch --allow -s myapp_t -t myapp_data_t -c file -p read
# 输出示例:
Found 1 semantic av rule:
allow myapp_t myapp_data_t : file { read };
2.7 常见错误与避坑
| 错误类型 | 典型表现 | 解决方案 |
|---|---|---|
| 类型未声明 | 编译报错:unrecognized type |
在规则前添加 type 类型名; 声明 |
| 类别/权限拼写错误 | 编译报错:unknown class 或 unknown permission |
查阅 selinux-class-permissions 支持列表 |
| 通配符权限过于宽泛 | 安全审计失败,或策略无法加载 | 替换 * 为显式权限列表,遵循最小权限 |
| auditallow 日志洪泛 | 磁盘空间被审计日志迅速填满 | 移除高频路径的 auditallow,改用 allow |
| 规则顺序依赖 | 先 deny 后 allow 导致意外拒绝 | 策略编译器按文件顺序合并,尽量将通用规则前置 |
避坑口诀:先声明后引用,类别权限要对照,通配慎用显式好,审计开关看场景,编译错误查拼写,运行问题看日志。
掌握 te 文件语法和规则类型是编写 SELinux 策略的基石。下一层将深入类型声明与属性机制,理解如何利用属性简化大规模策略的维护。