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 */