Trinity 源码阅读
0x00 介绍
Trinity是一个Linux内核系统调用fuzz软件。
本文依照文件夹来进行源码阅读。
0x01 shm.c
1.void create_shm(void)
作用
创建了一块共享内存,是系统页面大小的整数倍。页面大小通过getpagesize()获取;共享内存大小通过shm_size = (sizeof(struct shm_s) + page_size - 1) & PAGE_MASK;计算;PAGE_MASK=(~(page_size-1))
创建的shm为整个进程共享。
2.void init_shm(void)
作用
决定是否开启debug,初始化部分数据(种子,调用总数)
0x02 output.c
1.void output(char level, const char *fmt, ...)
2.void outputerr(const char *fmt, ...)
作用
将可变参数根据fmt输出到标准错误输出中。
3.void outputstd(const char *fmt, ...)
作用
将可变参数根据fmt输出到标准输出中。
0x03 param.c
1.static void usage(void)
作用
打印各参数功能。
其他
--arch -a:指定系统架构位数(32 or 64),只调用相关系统调用(32位系统调用int 80h,64位syscall,并且系统调用号不同)
--bdev -b:参数没有实现具体功能
--children -C:指定子进程的
--debug -D:开启debug
--dropprivs -X:降低权限
--exclude -x:排除某个系统调用
--ftrace-dump-file:用于指定ftrace缓冲区在内核被污染时转储到的文件。当内核发生崩溃时,这个文件可以帮助分析崩溃的原因。
--group -g:该选项允许用户指定要运行的系统调用所属的组。例如,-g vfs 选项将只运行与文件系统操作有关的系统调用,而 -g vm 选项将只运行与虚拟内存操作有关的系统调用。这可以帮助用户针对特定组进行系统调用的测试,而不是运行所有系统调用的测试。
--ioctls -I:这个选项会列出所有可用的ioctl。
--kernel_taint -T:控制应该考虑哪些内核污点标志。支持以下标志名称:PROPRIETARY_MODULE、FORCED_MODULE、UNSAFE_SMP、FORCED_RMMOD、MACHINE_CHECK、BAD_PAGE、USER、DIE、OVERRIDDEN_ACPI_TABLE、WARN、CRAP、FIRMWARE_WORKAROUND和OOT_MODULE。例如,要将Trinity设置为仅监视BAD、WARN和MACHINE_CHECK标志,应该指定“-T BAD,WARN,MACHINE_CHECK”参数。
flags解释可以看:https://zhuanlan.zhihu.com/p/472025483
--list -L:输出本机架构下已知的syscall。
--logging -l:日志记录
--domain -P:前者指定socket的domain,后者指定协议族
--no_domain -E: 指定排除的domain
--quiet -q:更少的输出
--random -r#:随机选取n个系统调用进行fuzz
--stats:在退出前显示每个系统调用的错误码分布情况
--syslog -S: 表示将重要信息记录到系统日志。
--verbose -v: 增加输出详细度
--victims -V:受害文件路径,默认遍历/dev,/sys,/proc。
-c# @:指定某个特定的系统调用fuzz。可以指定位宽。-copenat,64仅测试64位下的openat系统调用。
-s#:选种子,不然以当天时间做种子。
-N#:执行#系统调用然后退出。
以上均usage参数解释,部分参考readme文档,后续会根据代码阅读情况进行更改。
2.void parse_args(int argc, char *argv[])
作用
解析参数。
其他
0x04 tables.c
1.void toggle_syscall(const char *arg, bool state)
作用
如果支持64位和32位,宏定义ARCH_IS_BIARCH=1,调用toggle_syscall_biarch。
2.void toggle_syscall_biarch(const char *arg, bool state)
作用
激活系统调用的32位和64位
3.void check_user_specified_arch(const char *arg, char **arg_name, bool *only_64bit, bool *only_32bit)
作用
如果有,,则判断指定的系统调用是32位还是64位,将系统调用名赋给arg_name参数。
这里如果找到,会在该函数内部malloc一个空间,然后将arg的值(一个字符串的地址)放入*argname中;没找到是直接将arg的值赋予*argname。
4.void select_syscall_tables(void)
作用
syscalls_64bit 一个syscalltable数组,每一个元素是一个syscallentry,它是记了系统调用相关参数,flag,sanitise函数的结构体。
5.static struct syscalltable * copy_syscall_table(struct syscalltable *from, unsigned int nr)
作用
把from复制并作为返回。
6.static void decide_if_active(void)
作用
决定是否激活syscalls
7.void activate_syscall_in_table(unsigned int calln, unsigned int *nr_active, const struct syscalltable *table, int *active_syscall)
作用
设置一个syscallentry的各种属性,把syscalls激活。
8.int setup_syscall_group(unsigned int group)
作用
设定了组,激活该组(VFS)的系统调用
9.void enable_random_syscalls_biarch(void)
作用
随机一个syscall激活
10.void mark_all_syscalls_active(void)
作用
激活所有的syscall
11.void sanity_check_tables(void)
作用
检查syscalltable中的每一个syscall entry的参数名,以及数目。
12.void count_syscalls_enabled(void)
作用
输出syscalls的相关信息,如32位有多少个,64位有多少个,能调用的有多少个,不能调用的有多少个。
13.void display_enabled_syscalls(void)
作用
展示64位和32位哪些可以调用,哪些不行。
14.void dump_syscall_tables(void)
作用
显示syscall是ACTIVE的或AVOID的,ACTIVE是enable的,AVOID是disable的。
15.void show_unannotated_args(void)
作用
显示每个syscall未注释参数的数目。
16.void init_syscalls(void)
作用
如果syscall是激活的就初始化。
17.void do_uid0_check(void)
作用
权限check。
0x05 uid.c
1.void init_uids(void)
作用
orig_uid=nowuseruid;
orig_gid=nowusergid;
如果dropprivs==TRUE,会获取nobody用户信息,用来初始化nobody_uid,nobody_gid。
0x06 trinity.c
1.static void change_tmp_dir(void)
作用
切换工作目录到tmp/目录下
syscalls文件夹
内容
其中有关于所有系统调用的syscallentry结构,以及其传入参数的变异函数。
举例
static void sanitise_read(struct syscallrecord *rec)
{
rec->a2 = (unsigned long) get_non_null_address();
if (RAND_BOOL())
rec->a3 = rnd() % page_size;
else
rec->a3 = page_size;
}
struct syscallentry syscall_read = {
.name = "read",
.num_args = 3,
.sanitise = sanitise_read,
.arg1name = "fd",
.arg1type = ARG_FD,
.arg2name = "buf",
.arg2type = ARG_ADDRESS,
.arg3name = "count",
.arg3type = ARG_LEN,
.flags = NEED_ALARM,
};
// 在模糊测试中,sanitize(或sanitise)指的是处理测试输入以使其符合规范、合理或安全的过程。
如read系统调用,3个参数,参数类型和参数名以及参数的sanitise过程函数都被赋值。
其他
flags参数
- AVOID_SYSCALL:不应该测试的系统调用,因为它们可能会破坏系统或测试环境。
- NI_SYSCALL:代表非实现的系统调用。这些系统调用在当前系统中没有实现,但是在一些其他的系统中可能实现了。
- BORING:代表这个系统调用是相对“无趣”的,即它不太可能引发崩溃或错误。
- ACTIVE:表示这个系统调用已经激活,需要进行测试。
- TO_BE_DEACTIVATED:表示这个系统调用已经被激活,但是在将来的版本中可能会被禁用或删除。
- NEED_ALARM:代表这个系统调用需要一个 alarm(2) 或者 setitimer(2) 的超时时间。
- EXTRA_FORK:表示在执行这个系统调用之前,需要额外进行一个 fork() 调用。
- IGNORE_ENOSYS:表示这个系统调用不会返回 ENOSYS 错误,即系统调用已经实现并且可以被调用。
- EXPENSIVE:代表执行这个系统调用的代价比较大,会消耗较多的系统资源,所以需要谨慎测试。
0x07 taint.c
1.void init_taint_checking(void)
作用
检查内核是否被污染
0x08 map-initial.c
1.void setup_initial_mappings(void)
作用
为匿名内存映射对象分配并清0内存空间。
0x09 main.c
1.void main_loop(void)
作用
fuzz主循环
2.static void fork_children(void)
作用
创建一个新的进程。
3.static void handle_child(int childno, pid_t childpid, int childstatus)
作用
处理子进程退出情况。
4.static void handle_children(void)
作用
处理每一个子进程,如等待子进程的变化,并获取子进程的状态信息;设置一些对信号的屏蔽。
5.static void taint_check(void)
作用
检查内核是否被污染,被污染了记录被污染时候的信息。
6.static void reap_dead_kids(void)
作用
回收该次循环死亡的子进程
7.static bool is_child_making_progress(struct childdata *child)
作用
看看某一个子进程是否在做事,没做的话就把它杀了。
8.static void check_children_progressing(void)
作用
检查所有的子进程是否有进展,如果所有的运行的子进程都没进展,随机杀1/4的子进程。
0x0A lock.c
1.bool check_all_locks(void)
作用
检查锁
0x0B syscall.c
1.void do_syscall(struct syscallrecord *rec)
作用
执行系统调用
2.static void __do_syscall(struct syscallrecord *rec, enum syscallstate state)
作用
被上面的函数调用,做一些操作如设置系统调用是否需要alarm,如果需要则alarm(1)。然后进行syscall()函数。
0x0C child.c
1.static bool spawn_child(int childno)
设置种子,清除之前的childdata,设置pids。
2.static void init_child(struct childdata *child, int childno)
设置种子,初始化子进程的映射内存,设置子进程名,设置子进程屏蔽的一些信号。
文章评论