第4章 使用 audit2why 解释拒绝原因并生成优化建议
4.1 audit2why 工作原理
audit2why 是 SELinux 策略套件中的诊断工具,专门用于将 AVC(Access Vector Cache)拒绝日志翻译为人类可读的原因描述,并直接输出可执行的策略优化建议。与 audit2allow 只生成 allow 规则不同,audit2why 会结合策略数据库进行语义分析,指出拒绝发生的根本原因——是缺少类型强制规则、布尔值未启用,还是安全上下文标记错误。在帧率波动场景中,GPU/DRM 设备、共享内存和视频解码相关的系统调用频繁被 SELinux 拦截,使用 audit2why 可以快速定位是哪一类操作被阻止,从而精准修复帧率抖动。
| 工具 | 功能 | 输出粒度 | 适用场景 |
|---|---|---|---|
| audit2allow | 生成允许规则 | 直接输出 allow 语句 | 已知需要放行的操作 |
| audit2why | 解释拒绝原因 + 生成建议 | 原因描述 + 修复建议 | 排查未知拒绝、帧率相关系统调用分析 |
| ausearch | 检索审计日志 | 原始 AVC 记录 | 日志过滤与提取 |
核心原理:audit2why 读取 AVC 拒绝记录中的 scontext、tcontext、tclass 和 requested 权限,与当前加载的策略二进制对比,判断冲突来源于 ① 缺少显式 allow 规则、② 布尔值处于关闭状态、③ 类型边界冲突。输出中包含“Was caused by:”段落直接指出修复方向。
4.2 实现流程:从 AVC 日志到优化建议
下图展示使用 audit2why 分析帧率相关拒绝并生成优化建议的完整工作流:
实现流程的核心是管道组合:
ausearch -m avc -ts recent | audit2why 一步完成日志检索、语义分析和建议输出。帧率调试时建议先过滤出与 GPU/显示/共享内存相关的进程。4.3 命令与 API 详解
audit2why 本身是命令行工具,无独立 API,但其分析逻辑可被 Python 库 setools 调用。以下为常用命令模式:
| 命令 | 功能 | 帧率调试应用 |
|---|---|---|
ausearch -m avc -ts recent \| audit2why | 分析最近一条 AVC 拒绝 | 快速确认当前帧率抖动是否由 SELinux 引起 |
ausearch -m avc -c game_process \| audit2why | 按进程名过滤 | 专门分析游戏/渲染进程的拒绝 |
ausearch -m avc -ts 09:00 -te 09:05 \| audit2why | 按时间窗口过滤 | 对比帧率掉帧时刻的拒绝事件 |
ausearch -m avc --raw \| audit2why -p | 输出策略补丁格式 | 直接生成可粘贴到 .te 文件的规则 |
audit2why -i avc.log | 从文件读取 AVC 记录 | 离线分析已收集的日志 |
# 最常用的一行分析命令
ausearch -m avc -ts recent | audit2why
# 指定进程名 + 输出详细原因
ausearch -m avc -c xorg | audit2why -v
# 生成策略补丁格式(可直接用于编译)
ausearch -m avc -ts 14:00:00 -te 14:30:00 | audit2why -p
4.4 常见帧率相关拒绝类型分析
帧率波动场景中最常出现的三种拒绝类型为 mmap、ioctl 和 shm,它们直接影响显存映射、设备控制和进程间帧数据传递。下表对比各类型的影响特征:
| 拒绝类型 | 系统调用 | 影响机制 | 典型场景 | 帧率影响程度 |
|---|---|---|---|---|
| mmap | mmap() | 阻止进程映射 DRM/dri 设备内存,导致纹理上传与缓冲区访问失败 | OpenGL/Vulkan 纹理加载、显存分配 | 高(直接阻塞渲染管线) |
| ioctl | ioctl() | 阻止 GPU 命令提交、显示模式设置、VSync 控制等设备操作 | DRM_IOCTL_MODE_SETCRTC、提交命令缓冲区 | 极高(导致画面冻结或撕裂) |
| shm | shmget()/shmat() | 阻止共享内存附加,中断视频解码帧数据传递 | VA-API/VDPAU 解码、多进程渲染管道 | 中(解码帧延迟累积掉帧) |
| sem | semop() | 同步信号量被拒绝,导致渲染线程同步饥饿 | 多线程渲染 fence 同步 | 中(微卡顿) |
| msg | msgsnd()/msgrcv() | 消息队列被阻止,影响轻量级 IPC 帧同步 | 合成器与窗口管理器通信 | 低~中 |
mmap 拒绝在帧率问题中具有欺骗性——应用可能不会立即崩溃,而是降级为软件渲染(如 llvmpipe),帧率从 60 fps 骤降至 5~15 fps。audit2why 能直接指出是否因 mmap 权限缺失导致 Mesa 回退。
4.4.1 mmap 拒绝实例
# AVC 日志原始记录
type=AVC msg=audit(1711987654.123:789): avc: denied { mmap } for
pid=5678 comm="renderer" path="/dev/dri/card0" dev="devtmpfs" ino=12345
scontext=unconfined_u:unconfined_r:unconfined_t:s0
tcontext=system_u:object_r:dri_device_t:s0 tclass=chr_file
# 使用 audit2why 分析
$ ausearch -m avc -ts recent -c renderer | audit2why
type=AVC msg=audit(1711987654.123:789): avc: denied { mmap } for
pid=5678 comm="renderer" path="/dev/dri/card0" dev="devtmpfs" ino=12345
scontext=unconfined_u:unconfined_r:unconfined_t:s0
tcontext=system_u:object_r:dri_device_t:s0 tclass=chr_file
Was caused by:
Missing mmap permission on chr_file /dev/dri/card0.
You can fix this by adding
'allow unconfined_t dri_device_t:chr_file mmap;' to your policy.
优化建议直接给出 allow 规则。对于帧率敏感场景,建议同时检查是否缺少 { read write } 权限,因为 mmap 通常需要与读写权限配合:
# 更完整的修复规则
allow unconfined_t dri_device_t:chr_file { mmap read write };
4.4.2 ioctl 拒绝实例
# AVC 原始记录
type=AVC msg=audit(1711987700.456:812): avc: denied { ioctl } for
pid=5678 comm="renderer" path="/dev/dri/card0" dev="devtmpfs" ino=12345
ioctlcmd=0x6402 scontext=unconfined_u:unconfined_r:unconfined_t:s0
tcontext=system_u:object_r:dri_device_t:s0 tclass=chr_file
# audit2why 分析结果
$ ausearch -m avc -ts recent -c renderer | audit2why
Was caused by:
Missing ioctl permission on chr_file /dev/dri/card0.
ioctlcmd=0x6402 (DRM_IOCTL_MODE_SETCRTC) is used for display mode setting.
You can fix this by adding
'allow unconfined_t dri_device_t:chr_file ioctl;' to your policy.
ioctlcmd=0x6402 对应 DRM_IOCTL_MODE_SETCRTC,与显示模式切换和 VSync 配置直接相关。帧率波动如果发生在窗口切换或分辨率变更时刻,极大概率是此 ioctl 被拒绝。
4.4.3 shm 拒绝实例
# AVC 原始记录
type=AVC msg=audit(1711987800.789:845): avc: denied { attach } for
pid=9123 comm="vaapi_decoder" path="/dev/shm/memfd" dev="tmpfs" ino=67890
scontext=unconfined_u:unconfined_r:unconfined_t:s0
tcontext=unconfined_u:unconfined_r:unconfined_t:s0 tclass=shm
# audit2why 分析结果
$ ausearch -m avc -ts recent -c vaapi_decoder | audit2why
Was caused by:
Missing attach permission on shm.
Shared memory attachment is required for VA-API decoded frame transport.
You can fix this by adding
'allow unconfined_t unconfined_t:shm { attach shm } ;' to your policy.
4.5 调试与验证方法
应用 audit2why 给出的优化建议后,必须重新编译策略并验证帧率是否恢复。以下是标准调试流程:
- 生成规则文件:将 audit2why 输出的 allow 语句写入自定义 .te 文件。
- 编译并加载策略模块:
# 创建策略模块
mkdir -p /tmp/fix_fps
cat > /tmp/fix_fps/fix_fps.te << 'EOF'
policy_module(fix_fps, 1.0.0)
require {
type unconfined_t;
type dri_device_t;
class chr_file { mmap read write ioctl };
}
allow unconfined_t dri_device_t:chr_file { mmap read write ioctl };
EOF
# 编译并安装
make -f /usr/share/selinux/devel/Makefile fix_fps.pp
semodule -i fix_fps.pp
# 立即生效,无需重启
- 验证帧率恢复:使用
vblank_mode=0 glxgears或mesa_ci等工具测试帧率,确认不再掉帧。 - 确认无新拒绝:
# 验证优化后是否仍有拒绝
ausearch -m avc -ts recent | audit2why
# 若输出为空,说明所有帧率相关拒绝已解决
| 调试阶段 | 验证命令 | 预期结果 |
|---|---|---|
| 优化前 |