标题: [AFL]目标程序执行超时机制 分类: Fuzzing 创建: 2022-10-25 22:46 修改: 链接: http://0x2531.tech/fuzzing/202210252246.txt -------------------------------------------------------------------------------- 运行 afl-fuzz 时,通过 -t 选项设置目标程序超时时间(ms)。 接着,在函数 setup_signal_handlers 中注册超时处理器 /* Exec timeout notifications. */ sa.sa_handler = handle_timeout; sigaction(SIGALRM, &sa, NULL); 当 afl-fuzz 收到 SIGALRM 信号时,回调超时处理函数 handle_timeout /* Handle timeout (SIGALRM). */ static void handle_timeout(int sig) { if (child_pid > 0) { child_timed_out = 1; kill(child_pid, SIGKILL); } else if (child_pid == -1 && forksrv_pid > 0) { child_timed_out = 1; kill(forksrv_pid, SIGKILL); } } 如果目标程序(子进程)还在运行则设置全局变量 child_timed_out=1 并 kill 掉目标程序,否则,如 果 forkserver 还在运行则设置全局变量 child_timed_out=1 并 kill 掉 forkserver。 接着,就是执行目标程序,也就是调用函数 run_target。函数使用 setitimer 实现了计时器功能。 static struct itimerval it; it.it_value.tv_sec = (timeout / 1000); it.it_value.tv_usec = (timeout % 1000) * 1000; /* 计算目标程序执行时间(elapsed time),一旦超时则发出 SIGALRM 信号 */ setitimer(ITIMER_REAL, &it, NULL); 接着,就是等待目标程序执行 waitpid(child_pid, &status, 0) <--- dumb mode read(fsrv_st_fd, &status, 4) <--- forkserver mode 别忘了 disable 计时器 it.it_value.tv_sec = 0; it.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &it, NULL); 一旦目标程序执行超时,计时器将向 afl-fuzz 发送 SIGALRM 信号,触发回调超时处理函数 handle_timeout,设置全局变量 child_timed_out=1 并 kill 掉目标程序。 if (WIFSIGNALED(status) && !stop_soon) { kill_signal = WTERMSIG(status); if (child_timed_out && kill_signal == SIGKILL) return FAULT_TMOUT; return FAULT_CRASH; } 最后结果是,向函数 run_target 调用者返回执行超时状态。 以上便是超时机制的主要过程。 顺便提一下,如果没有通过 -t 指定超时时间,afl-fuzz 将会分场景自动获取。如果是恢复之前会话,则 从之前会话的状态文件里获取,即文件 fuzzer_stats 里的 exec_timeout 字段值;否则,将根据算法 计算出超时时间。 if (!timeout_given) { /* Figure out the appropriate timeout. The basic idea is: 5x average or 1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second. If the program is slow, the multiplier is lowered to 2x or 3x, because random scheduler jitter is less likely to have any impact, and because our patience is wearing thin =) */ if (avg_us > 50000) exec_tmout = avg_us * 2 / 1000; else if (avg_us > 10000) exec_tmout = avg_us * 3 / 1000; else exec_tmout = avg_us * 5 / 1000; exec_tmout = MAX(exec_tmout, max_us / 1000); exec_tmout = (exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND; if (exec_tmout > EXEC_TIMEOUT) exec_tmout = EXEC_TIMEOUT; ACTF("No -t option specified, so I'll use exec timeout of %u ms.", exec_tmout); timeout_given = 1; }