2. SELinux denials 基础知识:类型、审计日志与 AVC 消息解析

在排查渲染管道延迟问题时,识别 SELinux denial 是常见但极易被忽略的一环。本章围绕 现象识别 → 数据采集 → 原因定位 → 修复动作 → 复测 → 预防 的主线,系统介绍 denial 类型、审计日志格式与 AVC 消息解析方法。掌握这些基础后,你才能在后续章节中快速关联 denial 事件与渲染性能退化。

2.1 Denial 类型速查表

SELinux 的 access vector cache(AVC)在判定访问被拒绝时会生成 denial 消息。不同 denial 类型对应不同的策略根源。下表列出主要类型及其与渲染管线的典型关联:

类型审计日志关键词典型渲染场景策略根因
权限拒绝
(avc: denied)
{ open } { read } { write } { execmod } { ioctl }渲染进程无法打开 GPU 设备文件 /dev/dri/* 或 /dev/nvidia*目标类型缺少对应权限
类型转换拒绝
(avc: denied { transition })
{ transition } { dyntransition }子渲染线程无法切换到预期域,导致初始化挂起源域无目标域的 transition 权限
文件创建拒绝
(avc: denied { create })
{ create } { link } { setattr }渲染管道写入临时帧缓冲区或共享内存段被拒绝目标目录类型无对应文件创建权限
已授权访问
(avc: granted)
{ read } { write } (审计默认不产生 granted)当策略启用 allow 且 auditallow 时才出现,通常不标注渲染延迟信息性,非拒绝
来自用户空间访问控制
(user space access control, 简称 userspace)
userspace_avc: denied使用了 libselinux 接口的应用(如容器管理器)拒绝内部操作应用侧未正确设置安全上下文
排查要点: 渲染管道延迟最常见的 denial 类型为 权限拒绝 中的 { open } 和 { ioctl },它们直接影响帧缓冲区的读写和同步操作。遇到延迟异常时,优先搜索 avc: denied { open } 或 avc: denied { ioctl }。

2.2 审计日志格式全解析

SELinux 审计日志通常写入 /var/log/audit/audit.log(若 auditd 运行)或 /var/log/messages(非 auditd 环境)。一条典型 denial 日志的结构如下:

type=AVC msg=audit(1712345678.123:456): avc:  denied  { open } for  pid=7890 comm="render_thread" path="/dev/dri/card0" dev="devtmpfs" ino=12345 scontext=system_u:system_r:render_domain_t:s0 tcontext=system_u:object_r:dri_device_t:s0 tclass=chr_file permissive=0

按字段拆解如下:

日志字段示例值含义
type=AVCAVC / USER_AVC审计记录类型,AVC 表示内核访问向量缓存,USER_AVC 表示用户空间拒绝
msg=audit(…)1712345678.123:456时间戳(秒.毫秒): 序列号,用于关联多行记录
avc: denied { 权限 }denied { open }拒绝的权限集合,大括号内为权限集(可能包含多个权限如 { read write })
forpid=7890发起请求的进程 PID
comm"render_thread"进程名(截断至 16 字符)
path"/dev/dri/card0"被访问的目标路径(仅当目标为文件/目录时存在)
dev"devtmpfs"文件系统名称
ino12345inode 号
scontextsystem_u:system_r:render_domain_t:s0源安全上下文(进程的上下文,格式:用户:角色:类型:级别)
tcontextsystem_u:object_r:dri_device_t:s0目标安全上下文(被访问对象的上下文)
tclasschr_file对象类别,如 chr_file(字符设备文件)、file、dir、fd、process 等
permissive0 或 10=强制模式(实际拒绝),1=宽容模式(仅记录不拒绝)
数据采集动作(现象识别阶段): 当渲染延迟事件发生后,立即执行以下命令拉取最近 denial 日志并过滤渲染相关进程:
sudo ausearch -m AVC -ts recent | grep -E 'render|dri|nvidia|compositor' | head -50
sudo journalctl -k -f -g 'avc:  denied' --since '5 minutes ago'
如果 ausearch 不可用,直接搜索日志文件:
grep 'avc:  denied' /var/log/audit/audit.log | tail -20

2.3 AVC 消息解析与决策树

解析一条 AVC 拒绝消息需要快速提取 源类型(scontext)、目标类型(tcontext)、权限(permission set)和 对象类(tclass)。这四要素精确对应 SELinux 策略规则 allow 源类型 目标类型:对象类 { 权限 };。以下决策树帮助你定位策略缺口:

AVC 消息解析决策树 AVC 消息解析与策略缺口定位 A. 获取四要素 四要素提取(示例日志) 1. 源类型:scontext 中的第三段(类如 render_domain_t) 2. 目标类型:tcontext 中的第三段(如 dri_device_t) 3. 对象类:tclass(如 chr_file) 4. 权限集:{ open } B. 权限是否已 allow? 检查策略数据库 C. 对象类 分类匹配 D. 上下文来源 进程 vs 文件标签是否正确? B 决断 → 若已被 allow 检查 permissive=0/1 及条件性拒绝 C 决断 → 类别与策略不匹配 需要调整 tclass 或添加新规则 D 决断 重新标记文件 输出:修复策略规则所需参数

2.4 关键排查规则与提示

  • 规则 1: 若 permissive=0,denial 真实生效,需立即生成策略。若 permissive=1,系统处于宽容模式,denial 未阻塞操作但可能预示后续风险。
  • 规则 2: 渲染管道中 tclass=chr_file 且权限为 { open } 或 { ioctl } 的 denial,几乎总是对 GPU 设备节点(如 /dev/dri/card*)访问受限。优先检查 源类型 是否缺少 dri_device_t 的 chr_file:open 权限。
  • 规则 3: 使用 audit2allow 快速产生策略补丁:
    sudo grep 'avc:  denied' /var/log/audit/audit.log | audit2allow -M render_domain_policy
    生成的 render_domain_policy.pp 即为可加载的自定义策略模块。
  • 规则 4: scontext 中的域如果为 unconfined_t,通常表示进程未受 SELinux 约束,此时 denial 往往来自其他子进程或过渡域。应检查进程树中所有线程的上下文是否一致。
常见误判点: 不要看到 avc: denied 就认为策略必须放行。某些 denial 是正常行为(如容器隔离引起的拒绝),需结合渲染延迟的时间窗口与 PID 确认是否属于同一条调用链。在修复前,先在测试环境执行 setenforce 0 确认 denial 消失后延迟恢复,再正式修复策略。

2.5 复测与预防建议

  1. 复测: 加载新策略后,运行 ausearch -m AVC -ts today | grep -v 'granted' | wc -l 确保同类 denial 不再出现。同时对渲染管线执行压力测试,确保帧率恢复。
  2. 预防: 将自定义策略模块纳入版本管理(如 Git),并在 CI 中自动执行 checkmodule -M -m -o render_domain_policy.mod render_domain_policy.te && semodule_package -o render_domain_policy.pp -m render_domain_policy.mod 验证语法。
  3. 监控: 部署 fail2ban 或 audisp 实时告警,当 denial 频率超过阈值(如 5 条/分钟)时触发渲染延迟告警。

掌握本章内容后,你已具备快速识别和解析 SELinux denial 的能力。下一环节将把这些日志数据与渲染管道延迟的实际调用链进行关联,进入深度的原因定位阶段。