From 03730ec4cc0eefbb07e16312bfb0b665093fd110 Mon Sep 17 00:00:00 2001 From: Satori5ama <1242330740@qq.com> Date: Mon, 16 Dec 2024 20:30:42 +0800 Subject: [PATCH 1/2] add afl-fuzz.c comment about function main --- src/afl-fuzz.c | 330 ++++++++++++++++++++++++++++--------------------- 1 file changed, 186 insertions(+), 144 deletions(-) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 338d251..e6a2b74 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -7775,6 +7775,7 @@ static void save_cmdline(u32 argc, char** argv) { /* Main entry point */ +// 主函数,程序的入口点 int main(int argc, char** argv) { s32 opt; @@ -7788,94 +7789,114 @@ int main(int argc, char** argv) { struct timeval tv; struct timezone tz; - SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by \n"); - - doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - - gettimeofday(&tv, &tz); - srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); - - // argv 处理 - while ((opt = getopt(argc, argv, "+i:o:f:m:b:t:T:dnCB:S:M:x:QV")) > 0) - - switch (opt) { - - case 'i': /* input dir */ - - // 初始 corpus 目录 - if (in_dir) FATAL("Multiple -i options not supported"); - in_dir = optarg; - - // 若使用 "-i -",则表示 in-place resume - if (!strcmp(in_dir, "-")) in_place_resume = 1; - - break; - - case 'o': /* output dir */ - - if (out_dir) FATAL("Multiple -o options not supported"); - out_dir = optarg; - break; - - case 'M': { /* master sync ID */ - - u8* c; - - if (sync_id) FATAL("Multiple -S or -M options not supported"); - sync_id = ck_strdup(optarg); - - if ((c = strchr(sync_id, ':'))) { - - *c = 0; - - if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 || - !master_id || !master_max || master_id > master_max || - master_max > 1000000) FATAL("Bogus master ID passed to -M"); + SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by \n"); +} + /*************************************************************** + * 函数/方法: 主程序的参数处理 + * 描述: 该段代码负责解析命令行参数,并对输入输出目录、文件、同步ID以及超时等选项进行处理和验证。 + ***************************************************************/ + + doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; + + gettimeofday(&tv, &tz); + srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); + + // argv 处理 + while ((opt = getopt(argc, argv, "+i:o:f:m:b:t:T:dnCB:S:M:x:QV")) > 0) + + switch (opt) { + + case 'i': /* input dir */ + + // 初始 corpus 目录 + if (in_dir) FATAL("Multiple -i options not supported"); + in_dir = optarg; + + // 若使用 "-i -",则表示 in-place resume + if (!strcmp(in_dir, "-")) in_place_resume = 1; + + break; + + /* 处理输出目录的命令行选项 */ + case 'o': /* output dir */ + + if (out_dir) FATAL("Multiple -o options not supported"); + out_dir = optarg; + break; + + case 'M': { /* master sync ID */ + // 处理选项 'M',用于设定主同步 ID + + u8* c; + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = ck_strdup(optarg); + + if ((c = strchr(sync_id, ':'))) { + // 解析同步ID中的主ID和最大ID + + *c = 0; + + if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 || + !master_id || !master_max || master_id > master_max || + master_max > 1000000) FATAL("Bogus master ID passed to -M"); + + } + + force_deterministic = 1; + // 强制使用确定性执行 + } - - force_deterministic = 1; - - } - - break; - - case 'S': - - if (sync_id) FATAL("Multiple -S or -M options not supported"); - sync_id = ck_strdup(optarg); - break; - - case 'f': /* target file */ - - if (out_file) FATAL("Multiple -f options not supported"); - out_file = optarg; - break; - - case 'x': /* dictionary */ - - if (extras_dir) FATAL("Multiple -x options not supported"); - extras_dir = optarg; - break; - - case 't': { /* timeout */ - - u8 suffix = 0; - - if (timeout_given) FATAL("Multiple -t options not supported"); - - if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 || - optarg[0] == '-') FATAL("Bad syntax used for -t"); - - if (exec_tmout < 5) FATAL("Dangerously low value of -t"); - - if (suffix == '+') timeout_given = 2; else timeout_given = 1; - + break; - - } + + // 处理-S选项的代码逻辑 + /************************************************************************************ + * 该代码处理不同命令行选项的解析,包括同步ID、目标文件和字典目录等。 * + * 当检测到重复的选项时,程序会调用FATAL函数报错。 * + ************************************************************************************/ + case 'S': + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = ck_strdup(optarg); + break; + + case 'f': /* target file */ + + if (out_file) FATAL("Multiple -f options not supported"); + out_file = optarg; + break; + + case 'x': /* dictionary */ + + if (extras_dir) FATAL("Multiple -x options not supported"); + extras_dir = optarg; + break; + + /************************************** + * 处理命令行选项中与超时相关的参数 + * 支持-t选项,用于设置执行超时时间 + **************************************/ + case 't': { /* timeout */ + + u8 suffix = 0; + + if (timeout_given) FATAL("Multiple -t options not supported"); + + if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 || + optarg[0] == '-') FATAL("Bad syntax used for -t"); + + if (exec_tmout < 5) FATAL("Dangerously low value of -t"); + + if (suffix == '+') timeout_given = 2; else timeout_given = 1; + + break; + + } case 'm': { /* mem limit */ + // 处理内存限制选项的相关逻辑 u8 suffix = 'M'; @@ -7883,15 +7904,16 @@ int main(int argc, char** argv) { mem_limit_given = 1; if (!strcmp(optarg, "none")) { - + // 如果选项参数为"none",则将内存限制设置为0 mem_limit = 0; break; - } + // 解析命令行参数,获取内存限制和单位后缀 if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || optarg[0] == '-') FATAL("Bad syntax used for -m"); + // 根据单位后缀调整内存限制的值 switch (suffix) { case 'T': mem_limit *= 1024 * 1024; break; @@ -7903,8 +7925,10 @@ int main(int argc, char** argv) { } + // 检查内存限制值是否低于安全阈值 if (mem_limit < 5) FATAL("Dangerously low value of -m"); + // 在32位系统上检查内存限制的范围 if (sizeof(rlim_t) == 4 && mem_limit > 2000) FATAL("Value of -m out of range on 32-bit systems"); @@ -7913,10 +7937,11 @@ int main(int argc, char** argv) { break; case 'b': { /* bind CPU core */ - + // 处理 CPU 绑定选项,确保只能使用一次 if (cpu_to_bind_given) FATAL("Multiple -b options not supported"); cpu_to_bind_given = 1; + // 解析用户输入的 CPU 核心编号,检查输入合法性 if (sscanf(optarg, "%u", &cpu_to_bind) < 1 || optarg[0] == '-') FATAL("Bad syntax used for -b"); @@ -7924,6 +7949,7 @@ int main(int argc, char** argv) { } + /* 处理命令行参数,选择跳过确定性测试的选项 */ case 'd': /* skip deterministic */ if (skip_deterministic) FATAL("Multiple -d options not supported"); @@ -7932,24 +7958,19 @@ int main(int argc, char** argv) { break; case 'B': /* load bitmap */ - - /* This is a secret undocumented option! It is useful if you find - an interesting test case during a normal fuzzing process, and want - to mutate it without rediscovering any of the test cases already - found during an earlier run. - - To use this mode, you need to point -B to the fuzz_bitmap produced - by an earlier run for the exact same binary... and that's it. - - I only used this once or twice to get variants of a particular - file, so I'm not making this an official setting. */ - + /* + 该代码段处理加载位图的选项。 + 位图功能是一个未文档化的选项,适用于在正常模糊测试过程中找到有趣的测试用例后,进行变异而不重新发现先前运行中已找到的测试用例。 + 使用此模式时,需要将 -B 指向之前运行相同二进制文件生成的 fuzz_bitmap。 + 该功能仅在少数几次中使用过,因此不做为官方设置。 + */ if (in_bitmap) FATAL("Multiple -B options not supported"); in_bitmap = optarg; read_bitmap(in_bitmap); break; + /* 处理命令行参数选项 'C',用于设置崩溃模式 */ case 'C': /* crash mode */ if (crash_mode) FATAL("Multiple -C options not supported"); @@ -7957,27 +7978,34 @@ int main(int argc, char** argv) { break; case 'n': /* dumb mode */ - + // 处理-dumb模式的选项,当程序收到'-n'时触发 + if (dumb_mode) FATAL("Multiple -n options not supported"); if (getenv("AFL_DUMB_FORKSRV")) dumb_mode = 2; else dumb_mode = 1; break; + /* 处理命令行选项 */ case 'T': /* banner */ + /* 检查是否支持多个 -T 选项 */ if (use_banner) FATAL("Multiple -T options not supported"); use_banner = optarg; break; + // 处理QEMU模式的代码段 + // 如果启用QEMU模式,检查是否已指定多个-Q选项 + // 如果未指定内存限制,则使用默认的QEMU内存限制 + // 在处理完成后退出switch语句 + case 'Q': /* QEMU mode */ + + if (qemu_mode) FATAL("Multiple -Q options not supported"); + qemu_mode = 1; + + if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; + + break; - case 'Q': /* QEMU mode */ - - if (qemu_mode) FATAL("Multiple -Q options not supported"); - qemu_mode = 1; - - if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; - - break; - + /* 处理选项 'V' 的情况,显示版本号 */ case 'V': /* Show version number */ /* Version number has been printed already, just quit. */ @@ -7989,44 +8017,57 @@ int main(int argc, char** argv) { } - if (optind == argc || !in_dir || !out_dir) usage(argv[0]); - - setup_signal_handlers(); - check_asan_opts(); - - if (sync_id) fix_up_sync(); - - if (!strcmp(in_dir, out_dir)) - FATAL("Input and output directories can't be the same"); - - if (dumb_mode) { - - if (crash_mode) FATAL("-C and -n are mutually exclusive"); - if (qemu_mode) FATAL("-Q and -n are mutually exclusive"); - - } - - if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; - if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; - if (getenv("AFL_NO_ARITH")) no_arith = 1; - if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; - if (getenv("AFL_FAST_CAL")) fast_cal = 1; - - if (getenv("AFL_HANG_TMOUT")) { - hang_tmout = atoi(getenv("AFL_HANG_TMOUT")); - if (!hang_tmout) FATAL("Invalid value of AFL_HANG_TMOUT"); - } - - if (dumb_mode == 2 && no_forkserver) - FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); + // 检查命令行参数以及输入输出目录是否有效,若无效则显示使用方法 + if (optind == argc || !in_dir || !out_dir) usage(argv[0]); + + // 设置信号处理函数 + setup_signal_handlers(); + // 检查地址卫生选项 + check_asan_opts(); + + // 处理同步ID和目录检查的逻辑 + // 该段代码主要用于验证输入输出目录及模式的有效性 + // 在不同的运行模式下进行相应的错误处理 + + if (sync_id) fix_up_sync(); + + if (!strcmp(in_dir, out_dir)) + FATAL("Input and output directories can't be the same"); + + if (dumb_mode) { + + if (crash_mode) FATAL("-C and -n are mutually exclusive"); + if (qemu_mode) FATAL("-Q and -n are mutually exclusive"); + + } - if (getenv("AFL_PRELOAD")) { - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); - } + // 该代码段用于读取环境变量并根据其值设置相应的标志和超时值 + // 主要功能是启动时配置这些参数以调整程序的行为 + if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; + if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; + if (getenv("AFL_NO_ARITH")) no_arith = 1; + if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; + if (getenv("AFL_FAST_CAL")) fast_cal = 1; + + if (getenv("AFL_HANG_TMOUT")) { + hang_tmout = atoi(getenv("AFL_HANG_TMOUT")); + if (!hang_tmout) FATAL("Invalid value of AFL_HANG_TMOUT"); + } - if (getenv("AFL_LD_PRELOAD")) - FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); + // 此函数用于检查环境变量和启动模式的合法性 + // 如果在不支持的模式下使用互斥选项,则会引发致命错误 + // 处理环境变量以确保正确的库加载 + + if (dumb_mode == 2 && no_forkserver) + FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); + + if (getenv("AFL_PRELOAD")) { + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); + } + + if (getenv("AFL_LD_PRELOAD")) + FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); save_cmdline(argc, argv); @@ -8037,6 +8078,7 @@ int main(int argc, char** argv) { get_core_count(); #ifdef HAVE_AFFINITY + // 将当前进程绑定到一个空闲的CPU上,以优化性能 bind_to_free_cpu(); #endif /* HAVE_AFFINITY */ From 97275cd000325926291bba552cc0cce9fb0eb0ac Mon Sep 17 00:00:00 2001 From: Satori5ama <1242330740@qq.com> Date: Mon, 16 Dec 2024 20:38:55 +0800 Subject: [PATCH 2/2] add afl-fuzz.c comment from lines 7000 to 8200 --- src/afl-fuzz.c | 204 ++++++++++++++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 79 deletions(-) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e6a2b74..04327d7 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -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) {