内核漏洞挖掘技术系列(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 主要组件

  1. trinity-main

    • 执行各种初始化操作
    • 创建执行系统调用的子进程
    • 管理共享内存区域(记录全局信息和子进程信息)
  2. 子进程

    • 实际执行系统调用模糊测试
    • 每个子进程有独立日志文件(trinity-childX.log)
  3. 共享内存区域

    • 记录全局信息(打开的文件描述符、系统调用统计等)
    • 记录每个子进程的信息(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 重要子目录

  1. fds/:文件描述符操作实现
  2. ioctls/:ioctl相关模糊测试
  3. mm/:内存映射管理
  4. net/:网络相关模糊测试
  5. syscalls/:被测试的系统调用实现
  6. rand/:随机数生成相关

4. 核心实现细节

4.1 主进程流程

  1. 初始化阶段

    • 设置最大子进程数(默认为CPU核心数的4倍)
    • 解析命令行参数
    • 创建并初始化共享内存区域
    • 初始化系统调用表
    • 初始化文件描述符
  2. 主循环

    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 子进程执行流程

  1. 系统调用选择

    • 随机选择系统调用
    • 10%概率选择32位系统调用(如果启用)
    • 跳过标记为AVOID_SYSCALL或NI_SYSCALL的系统调用
  2. 参数生成

    for (每个参数) {
        switch (参数类型) {
            case ARG_UNDEFINED: 随机生成数值;
            case ARG_NON_NULL_ADDRESS: 从共享内存区域分配;
            case ARG_SOCKETINFO: socket文件描述符池选择;
            // 其他参数类型处理...
        }
    }
    
  3. 系统调用执行

    • 对特殊系统调用(如execve)使用fork执行
    • 执行后立即检查taint状态
    • 记录成功/失败结果

4.3 关键数据结构

  1. 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;     // 标志位
    };
    
  2. 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 扩展方法

  1. 添加新系统调用测试

    • 在syscalls/目录下添加实现
    • 定义syscallentry结构体
    • 添加到系统调用表中
  2. 添加新参数类型

    • 在generate-args.c中添加处理逻辑
    • 定义新的argtype枚举值
  3. 添加新文件描述符类型

    • 在fds/目录下添加实现
    • 定义fd_provider结构体

6. 局限性

  1. 不能自动生成可复现的POC
  2. 支持的参数类型有限
  3. 不支持代码覆盖率指导(KCOV)
  4. 相比Syzkaller功能较为基础

7. 二次开发建议

  1. 集成KCOV支持代码覆盖率
  2. 增强参数生成能力
  3. 添加POC生成功能
  4. 针对特定子系统(如网络、文件系统)进行优化

8. 参考资料

  1. Trinity官方GitHub仓库
  2. 《LCA: The Trinity fuzz tester》文章
  3. 先知社区相关分析文章
  4. 看雪论坛相关讨论帖
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倍) 解析命令行参数 创建并初始化共享内存区域 初始化系统调用表 初始化文件描述符 主循环 : 4.2 子进程执行流程 系统调用选择 : 随机选择系统调用 10%概率选择32位系统调用(如果启用) 跳过标记为AVOID_ SYSCALL或NI_ SYSCALL的系统调用 参数生成 : 系统调用执行 : 对特殊系统调用(如execve)使用fork执行 执行后立即检查taint状态 记录成功/失败结果 4.3 关键数据结构 syscallentry (include/syscallentry.h): shm_ s (include/shm.h): 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》文章 先知社区相关分析文章 看雪论坛相关讨论帖