git地址:
https://github.com/kernelslacker/trinity
linux下对syscall的模糊测试。
main函数位于trinity.c中。
int main(int argc, char* argv[])
{
int ret = EXIT_SUCCESS;
const char taskname[16]="test-main";
outputstd("Trinity " VERSION " Dave Jones <davej@codemonkey.org.uk>\n");
progname = argv[0];
mainpid = getpid();
getrlimit(RLIMIT_NOFILE, &max_files_rlimit); //获取或设定资源使用限制
// eg.RLIMIT_NOFILE进程能打开的最大文件数
page_size = getpagesize();
num_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
max_children = num_online_cpus * 4; /* possibly overridden in params. -C可配置*/
select_syscall_tables(); //根据系统架构选择系统调用表eg.syscalls-x86_64.h
create_shm();//创建共享内存
parse_args(argc, argv);//对传入的参数解析
init_uids();//当前进程的uid,gid以及nobody用户的信息
change_tmp_dir();
init_shm();//用于查看每个子进程的syscall records
init_taint_checking();//'/proc/sys/kernel/tainted'内核是否被污染
if (munge_tables() == FALSE) {
ret = EXIT_FAILURE;
goto out;
}
if (show_syscall_list == TRUE) {
dump_syscall_tables();
goto out;
}
if (show_ioctl_list == TRUE) {
dump_ioctls();
goto out;
}
if (show_unannotated == TRUE) {
show_unannotated_args();
goto out;
}
init_syscalls();
do_uid0_check();
if (do_specific_domain == TRUE)
find_specific_domain(specific_domain_optarg);
pids_init();
init_logging();
init_object_lists(OBJ_GLOBAL);
setup_initial_mappings();
parse_devices();
/* FIXME: Some better object construction method needed. */
create_futexes();
create_sysv_shms();
setup_main_signals();
no_bind_to_cpu = RAND_BOOL();
prctl(PR_SET_NAME, (unsigned long) &taskname);
if (open_fds() == FALSE) {
if (shm->exit_reason != STILL_RUNNING)
panic(EXIT_FD_INIT_FAILURE); // FIXME: Later, push this down to multiple EXIT's.
_exit(EXIT_FAILURE);
}
setup_ftrace();
main_loop();
destroy_global_objects();
if (is_tainted() == TRUE)
stop_ftrace();
output(0, "Ran %ld syscalls. Successes: %ld Failures: %ld\n",
shm->stats.op_count, shm->stats.successes, shm->stats.failures);
if (show_stats == TRUE)
dump_stats();
shutdown_logging();
ret = set_exit_code(shm->exit_reason);
out:
exit(ret);
}
trinity通过spawn_child产生子进程去执行系统调用。子进程内调用child_process,其中random_syscall即随机匹配系统调用去执行。
// spawn_child中代码段
pid = fork();
if (pid == 0) {
child_process(child, childno);
_exit(EXIT_SUCCESS);
} else {
if (pid == -1) {
debugf("Couldn't fork a new child in pidslot %d. errno:%s\n",
childno, strerror(errno));
return FALSE;
}
}
random_syscall函数中,set_syscall_nr随机系统调用号
syscallnr = rnd() % max_nr_syscalls;
bool random_syscall(struct childdata *child)
{
struct syscallrecord *rec;
int ret = FALSE;
rec = &child->syscall;
if (set_syscall_nr(rec) == FAIL)
return FAIL;
memset(rec->postbuffer, 0, POSTBUFFER_LEN);
/* Generate arguments, print them out */
generate_syscall_args(rec);
output_syscall_prefix(rec);
do_syscall(rec);
output_syscall_postfix(rec);
handle_syscall_ret(rec);
ret = TRUE;
return ret;
}
系统调用的参数随机生成
syscalltrinity/include/syscalls-x86_64.h该文件中存在struct syscalltable结构体数组,每一个元素都是一个系统调用。
struct syscalltable {
struct syscallentry *entry;
};
syscalltrinity/syscalls/文件夹下,对于每个系统调用,实现了对应的结构体。
eg. syscall_poll
struct syscallentry syscall_poll = {
.name = "poll",
.num_args = 3,
.arg1name = "ufds",
.arg2name = "nfds",
.arg3name = "timeout_msecs",
.arg3type = ARG_RANGE,
.low3range = 0,
.hi3range = 1,
.flags = NEED_ALARM,
.sanitise = sanitise_poll,
.post = post_poll,
};
//函数sanitise_poll即为poll对应的参数调整函数
static void sanitise_poll(struct syscallrecord *rec)
{
struct pollfd *pollfd;
unsigned int i;
unsigned int num_fds = rnd() % 10;
pollfd = zmalloc(num_fds * sizeof(struct pollfd));
for (i = 0; i < num_fds; i++) {
pollfd[i].fd = get_random_fd();
pollfd[i].events = set_rand_bitmask(ARRAY_SIZE(poll_events), poll_events);
}
rec->a1 = (unsigned long) pollfd;
rec->a2 = num_fds;
}