|
|
|
@ -8082,101 +8082,138 @@ int main(int argc, char** argv) {
|
|
|
|
|
bind_to_free_cpu();
|
|
|
|
|
#endif /* HAVE_AFFINITY */
|
|
|
|
|
|
|
|
|
|
/* 检查崩溃处理机制 */
|
|
|
|
|
check_crash_handling();
|
|
|
|
|
/* 检查CPU调节器设置 */
|
|
|
|
|
check_cpu_governor();
|
|
|
|
|
|
|
|
|
|
/* 设置后处理操作 */
|
|
|
|
|
setup_post();
|
|
|
|
|
/* 设置共享内存 */
|
|
|
|
|
setup_shm();
|
|
|
|
|
/* 初始化计数类16 */
|
|
|
|
|
init_count_class16();
|
|
|
|
|
|
|
|
|
|
/* 设置目录和文件描述符 */
|
|
|
|
|
setup_dirs_fds();
|
|
|
|
|
/* 读取测试用例 */
|
|
|
|
|
read_testcases();
|
|
|
|
|
/* 加载自动化设置 */
|
|
|
|
|
load_auto();
|
|
|
|
|
|
|
|
|
|
/* 处理输入的转换 */
|
|
|
|
|
pivot_inputs();
|
|
|
|
|
// 此代码段为 afl-fuzz.c 文件中的初始化和参数处理部分
|
|
|
|
|
// 主要功能是配置执行环境并检查传入的文件参数
|
|
|
|
|
// 包括加载额外目录、查找超时、检测文件参数、设置输出文件、检查二进制文件及获取当前时间
|
|
|
|
|
|
|
|
|
|
if (extras_dir) load_extras(extras_dir);
|
|
|
|
|
|
|
|
|
|
if (!timeout_given) find_timeout();
|
|
|
|
|
|
|
|
|
|
detect_file_args(argv + optind + 1);
|
|
|
|
|
|
|
|
|
|
if (!out_file) setup_stdio_file();
|
|
|
|
|
|
|
|
|
|
check_binary(argv[optind]);
|
|
|
|
|
|
|
|
|
|
start_time = get_cur_time();
|
|
|
|
|
|
|
|
|
|
if (qemu_mode)
|
|
|
|
|
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
|
|
|
|
|
else
|
|
|
|
|
use_argv = argv + optind;
|
|
|
|
|
|
|
|
|
|
if (extras_dir) load_extras(extras_dir);
|
|
|
|
|
|
|
|
|
|
if (!timeout_given) find_timeout();
|
|
|
|
|
|
|
|
|
|
detect_file_args(argv + optind + 1);
|
|
|
|
|
|
|
|
|
|
if (!out_file) setup_stdio_file();
|
|
|
|
|
|
|
|
|
|
check_binary(argv[optind]);
|
|
|
|
|
|
|
|
|
|
start_time = get_cur_time();
|
|
|
|
|
|
|
|
|
|
if (qemu_mode)
|
|
|
|
|
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
|
|
|
|
|
else
|
|
|
|
|
use_argv = argv + optind;
|
|
|
|
|
|
|
|
|
|
perform_dry_run(use_argv);
|
|
|
|
|
|
|
|
|
|
cull_queue();
|
|
|
|
|
|
|
|
|
|
show_init_stats();
|
|
|
|
|
|
|
|
|
|
seek_to = find_start_position();
|
|
|
|
|
|
|
|
|
|
write_stats_file(0, 0, 0);
|
|
|
|
|
save_auto();
|
|
|
|
|
|
|
|
|
|
if (stop_soon) goto stop_fuzzing;
|
|
|
|
|
|
|
|
|
|
/* Woop woop woop */
|
|
|
|
|
|
|
|
|
|
if (!not_on_tty) {
|
|
|
|
|
sleep(4);
|
|
|
|
|
start_time += 4000;
|
|
|
|
|
/*
|
|
|
|
|
* 此函数实现了模糊测试的初始步骤,包括执行干运行、清理队列、
|
|
|
|
|
* 显示初始化统计信息、寻找起始位置并写入统计文件。
|
|
|
|
|
*/
|
|
|
|
|
perform_dry_run(use_argv);
|
|
|
|
|
|
|
|
|
|
cull_queue();
|
|
|
|
|
|
|
|
|
|
show_init_stats();
|
|
|
|
|
|
|
|
|
|
seek_to = find_start_position();
|
|
|
|
|
|
|
|
|
|
write_stats_file(0, 0, 0);
|
|
|
|
|
save_auto();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 如果状态指示测试需要停止,则跳转到停止模糊测试的标签。
|
|
|
|
|
*/
|
|
|
|
|
if (stop_soon) goto stop_fuzzing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Woop woop woop */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 如果不是在终端上运行,则暂停4秒,增加开始时间。
|
|
|
|
|
*/
|
|
|
|
|
if (!not_on_tty) {
|
|
|
|
|
sleep(4);
|
|
|
|
|
start_time += 4000;
|
|
|
|
|
/*
|
|
|
|
|
* 再次检查是否需要停止模糊测试。
|
|
|
|
|
*/
|
|
|
|
|
if (stop_soon) goto stop_fuzzing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 该段代码实现了一个持续循环,处理模糊测试队列中的条目。
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
|
|
u8 skipped_fuzz;
|
|
|
|
|
|
|
|
|
|
cull_queue();
|
|
|
|
|
|
|
|
|
|
if (!queue_cur) {
|
|
|
|
|
|
|
|
|
|
queue_cycle++;
|
|
|
|
|
current_entry = 0;
|
|
|
|
|
cur_skipped_paths = 0;
|
|
|
|
|
queue_cur = queue;
|
|
|
|
|
|
|
|
|
|
while (seek_to) {
|
|
|
|
|
current_entry++;
|
|
|
|
|
seek_to--;
|
|
|
|
|
queue_cur = queue_cur->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
show_stats();
|
|
|
|
|
|
|
|
|
|
if (not_on_tty) {
|
|
|
|
|
ACTF("Entering queue cycle %llu.", queue_cycle);
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u8 skipped_fuzz;
|
|
|
|
|
|
|
|
|
|
// 清理当前模糊测试队列
|
|
|
|
|
cull_queue();
|
|
|
|
|
|
|
|
|
|
if (!queue_cur) {
|
|
|
|
|
|
|
|
|
|
// 如果当前队列为空,增加队列周期计数
|
|
|
|
|
queue_cycle++;
|
|
|
|
|
current_entry = 0;
|
|
|
|
|
cur_skipped_paths = 0;
|
|
|
|
|
queue_cur = queue;
|
|
|
|
|
|
|
|
|
|
// 根据指定的跳过路径数量,定位到队列中的特定条目
|
|
|
|
|
while (seek_to) {
|
|
|
|
|
current_entry++;
|
|
|
|
|
seek_to--;
|
|
|
|
|
queue_cur = queue_cur->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示当前状态统计
|
|
|
|
|
show_stats();
|
|
|
|
|
|
|
|
|
|
if (not_on_tty) {
|
|
|
|
|
// 在非终端模式下,输出当前队列周期信息
|
|
|
|
|
ACTF("Entering queue cycle %llu.", queue_cycle);
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we had a full queue cycle with no new finds, try
|
|
|
|
|
recombination strategies next. */
|
|
|
|
|
|
|
|
|
|
// 检查当前队列路径是否与前一个队列路径相同
|
|
|
|
|
if (queued_paths == prev_queued) {
|
|
|
|
|
|
|
|
|
|
// 根据是否使用拼接,决定增加无发现循环次数或启用拼接
|
|
|
|
|
if (use_splicing) cycles_wo_finds++; else use_splicing = 1;
|
|
|
|
|
|
|
|
|
|
} else cycles_wo_finds = 0;
|
|
|
|
|
|
|
|
|
|
// 更新前一个队列路径值
|
|
|
|
|
prev_queued = queued_paths;
|
|
|
|
|
|
|
|
|
|
// 检查同步ID,队列循环和环境变量以同步模糊测试器
|
|
|
|
|
if (sync_id && queue_cycle == 1 && getenv("AFL_IMPORT_FIRST"))
|
|
|
|
|
sync_fuzzers(use_argv);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 执行模糊测试
|
|
|
|
|
skipped_fuzz = fuzz_one(use_argv);
|
|
|
|
|
|
|
|
|
|
// 如果没有停止标志且没有跳过模糊测试,根据同步间隔决定是否同步
|
|
|
|
|
if (!stop_soon && sync_id && !skipped_fuzz) {
|
|
|
|
|
|
|
|
|
|
if (!(sync_interval_cnt++ % SYNC_INTERVAL))
|
|
|
|
@ -8184,38 +8221,47 @@ int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果没有停止标志且 exit_1 为真,则设置停止标志
|
|
|
|
|
if (!stop_soon && exit_1) stop_soon = 2;
|
|
|
|
|
|
|
|
|
|
// 如果设置了停止标志,则跳出循环
|
|
|
|
|
if (stop_soon) break;
|
|
|
|
|
|
|
|
|
|
queue_cur = queue_cur->next;
|
|
|
|
|
current_entry++;
|
|
|
|
|
// 更新当前队列指针和当前条目计数
|
|
|
|
|
queue_cur = queue_cur->next;
|
|
|
|
|
current_entry++;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (queue_cur) show_stats();
|
|
|
|
|
|
|
|
|
|
/* If we stopped programmatically, we kill the forkserver and the current runner.
|
|
|
|
|
If we stopped manually, this is done by the signal handler. */
|
|
|
|
|
if (stop_soon == 2) {
|
|
|
|
|
if (child_pid > 0) kill(child_pid, SIGKILL);
|
|
|
|
|
if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);
|
|
|
|
|
}
|
|
|
|
|
/* Now that we've killed the forkserver, we wait for it to be able to get rusage stats. */
|
|
|
|
|
if (waitpid(forksrv_pid, NULL, 0) <= 0) {
|
|
|
|
|
WARNF("error waitpid\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_bitmap();
|
|
|
|
|
write_stats_file(0, 0, 0);
|
|
|
|
|
save_auto();
|
|
|
|
|
/*
|
|
|
|
|
* 该段代码用于处理程序终止的情况,包括被程序控制的终止和手动终止。
|
|
|
|
|
* 在终止时会杀死子进程和forkserver,并等待forkserver获取资源使用统计信息。
|
|
|
|
|
* 此外,还会写入位图和统计文件以保存当前状态。
|
|
|
|
|
*/
|
|
|
|
|
if (queue_cur) show_stats();
|
|
|
|
|
|
|
|
|
|
/* If we stopped programmatically, we kill the forkserver and the current runner.
|
|
|
|
|
If we stopped manually, this is done by the signal handler. */
|
|
|
|
|
if (stop_soon == 2) {
|
|
|
|
|
if (child_pid > 0) kill(child_pid, SIGKILL);
|
|
|
|
|
if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);
|
|
|
|
|
}
|
|
|
|
|
/* Now that we've killed the forkserver, we wait for it to be able to get rusage stats. */
|
|
|
|
|
if (waitpid(forksrv_pid, NULL, 0) <= 0) {
|
|
|
|
|
WARNF("error waitpid\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_bitmap();
|
|
|
|
|
write_stats_file(0, 0, 0);
|
|
|
|
|
save_auto();
|
|
|
|
|
|
|
|
|
|
/* 停止模糊测试的函数 */
|
|
|
|
|
stop_fuzzing:
|
|
|
|
|
|
|
|
|
|
SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST,
|
|
|
|
|
stop_soon == 2 ? "programmatically" : "by user");
|
|
|
|
|
|
|
|
|
|
/* Running for more than 30 minutes but still doing first cycle? */
|
|
|
|
|
/* 运行超过30分钟但仍在进行第一次周期? */
|
|
|
|
|
|
|
|
|
|
if (queue_cycle == 1 && get_cur_time() - start_time > 30 * 60 * 1000) {
|
|
|
|
|
|
|
|
|
|