内核漏洞挖掘技术系列(1)——trinity
字数 1721 2025-08-05 11:39:26
Trinity 内核漏洞挖掘工具详解
1. 工具概述
Trinity 是一个用于 Linux 内核模糊测试(Fuzz)的工具,在 Syzkaller 出现之前(2015年10月之前)是最流行的内核 Fuzz 工具。其特点包括:
- 首次提交于2006年3月,1.0版本发布于2012年8月
- 最新1.9版本发布于2019年1月
- 支持多种二次开发版本(如Android版本、perf_event_open专用版本等)
- 采用多进程架构进行系统调用模糊测试
2. 整体架构
2.1 主要组件
-
trinity-main:
- 执行各种初始化操作
- 创建执行系统调用的子进程
- 管理共享内存区域(记录全局信息和子进程信息)
-
子进程:
- 实际执行系统调用模糊测试
- 每个子进程有独立日志文件(trinity-childX.log)
-
共享内存区域:
- 记录全局信息(打开的文件描述符、系统调用统计等)
- 记录每个子进程的信息(pid、系统调用记录等)
2.2 监控机制
- 主进程监控子进程状态
- 检测到子进程终止或挂起时,杀死并重新创建
- 检查共享内存完整性
- 检测内核taint状态
3. 源代码结构
3.1 主要源文件
| 文件 | 功能 |
|---|---|
| child.c | 执行fuzz的子进程 |
| generate-args.c | 系统调用参数生成与处理 |
| shm.c | 共享内存管理 |
| syscall.c | 系统调用执行 |
| tables.c | 系统调用表管理 |
| log.c | 日志记录(支持本地文件和远程服务器) |
| main.c | 主循环逻辑 |
| objects.c | 文件描述符管理 |
| signals.c | 信号处理 |
3.2 重要子目录
- fds/:文件描述符操作实现
- ioctls/:ioctl相关模糊测试
- mm/:内存映射管理
- net/:网络相关模糊测试
- syscalls/:被测试的系统调用实现
- rand/:随机数生成相关
4. 核心实现细节
4.1 主进程流程
-
初始化阶段:
- 设置最大子进程数(默认为CPU核心数的4倍)
- 解析命令行参数
- 创建并初始化共享内存区域
- 初始化系统调用表
- 初始化文件描述符
-
主循环:
while (子进程运行中) { // 1. 处理子进程状态 handle_children(); // 2. 检查内核taint状态 check_tainted(); // 3. 检查共享内存完整性 check_shm_integrity(); // 4. 检查系统调用数量限制 check_syscall_limit(); // 5. 监控子进程状态 monitor_children(); // 6. 补充子进程数量 maintain_child_count(); }
4.2 子进程执行流程
-
系统调用选择:
- 随机选择系统调用
- 10%概率选择32位系统调用(如果启用)
- 跳过标记为AVOID_SYSCALL或NI_SYSCALL的系统调用
-
参数生成:
for (每个参数) { switch (参数类型) { case ARG_UNDEFINED: 随机生成数值; case ARG_NON_NULL_ADDRESS: 从共享内存区域分配; case ARG_SOCKETINFO: 从socket文件描述符池选择; // 其他参数类型处理... } } -
系统调用执行:
- 对特殊系统调用(如execve)使用fork执行
- 执行后立即检查taint状态
- 记录成功/失败结果
4.3 关键数据结构
-
syscallentry (include/syscallentry.h):
struct syscallentry { const char *name; // 系统调用名称 unsigned int nr; // 系统调用号 unsigned int nargs; // 参数个数 argtype arg1type; // 参数1类型 const char *arg1name; // 参数1名称 // ...其他参数定义 int (*init)(void); // 初始化函数 int (*sanitise)(void); // 参数清理函数 void (*post)(void); // 调用后处理函数 unsigned int flags; // 标志位 }; -
shm_s (include/shm.h):
struct shm_s { unsigned long total; // 总系统调用次数 unsigned long successes;// 成功次数 unsigned long fails; // 失败次数 childdata *children[MAX_CHILDREN]; // 子进程数据 // 其他全局统计信息... };
5. 使用与扩展
5.1 常用命令行参数
| 参数 | 说明 |
|---|---|
| -c syscall | 指定测试的系统调用 |
| -N count | 指定测试的系统调用数量 |
| -V dir | 指定目录,程序会随机打开其中的文件用于测试 |
| --enable-32bit | 启用32位系统调用测试 |
5.2 扩展方法
-
添加新系统调用测试:
- 在syscalls/目录下添加实现
- 定义syscallentry结构体
- 添加到系统调用表中
-
添加新参数类型:
- 在generate-args.c中添加处理逻辑
- 定义新的argtype枚举值
-
添加新文件描述符类型:
- 在fds/目录下添加实现
- 定义fd_provider结构体
6. 局限性
- 不能自动生成可复现的POC
- 支持的参数类型有限
- 不支持代码覆盖率指导(KCOV)
- 相比Syzkaller功能较为基础
7. 二次开发建议
- 集成KCOV支持代码覆盖率
- 增强参数生成能力
- 添加POC生成功能
- 针对特定子系统(如网络、文件系统)进行优化
8. 参考资料
- Trinity官方GitHub仓库
- 《LCA: The Trinity fuzz tester》文章
- 先知社区相关分析文章
- 看雪论坛相关讨论帖