第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 分析帧率相关拒绝并生成优化建议的完整工作流:

audit2why 帧率拒绝分析与优化工作流 AVC 拒绝日志 audit.log 帧率相关事件 1 audit2why 解析 语义分析与策略对比 2 拒绝类型分类 mmap │ ioctl │ shm 3 原因解释输出 违反类型强制规则详情 4 优化建议生成 te 规则 │ 布尔值调整 5 策略调整实施 编译加载 & 帧率验证 6 输入 解析 分类 解释 建议 实施 💡 每轮分析只处理一条 AVC 记录;批量分析时使用 ausearch | 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,它们直接影响显存映射、设备控制和进程间帧数据传递。下表对比各类型的影响特征:

拒绝类型系统调用影响机制典型场景帧率影响程度
mmapmmap()阻止进程映射 DRM/dri 设备内存,导致纹理上传与缓冲区访问失败OpenGL/Vulkan 纹理加载、显存分配高(直接阻塞渲染管线)
ioctlioctl()阻止 GPU 命令提交、显示模式设置、VSync 控制等设备操作DRM_IOCTL_MODE_SETCRTC、提交命令缓冲区极高(导致画面冻结或撕裂)
shmshmget()/shmat()阻止共享内存附加,中断视频解码帧数据传递VA-API/VDPAU 解码、多进程渲染管道中(解码帧延迟累积掉帧)
semsemop()同步信号量被拒绝,导致渲染线程同步饥饿多线程渲染 fence 同步中(微卡顿)
msgmsgsnd()/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 给出的优化建议后,必须重新编译策略并验证帧率是否恢复。以下是标准调试流程:

  1. 生成规则文件:将 audit2why 输出的 allow 语句写入自定义 .te 文件。
  2. 编译并加载策略模块:
# 创建策略模块
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

# 立即生效,无需重启
  1. 验证帧率恢复:使用 vblank_mode=0 glxgears 或 mesa_ci 等工具测试帧率,确认不再掉帧。
  2. 确认无新拒绝:
# 验证优化后是否仍有拒绝
ausearch -m avc -ts recent | audit2why

# 若输出为空,说明所有帧率相关拒绝已解决
调试阶段验证命令预期结果
优化前