|
|
|
@ -88,7 +88,6 @@ static volatile u8
|
|
|
|
|
stop_soon, /* Ctrl-C pressed? */
|
|
|
|
|
child_timed_out; /* Child timed out? */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Classify tuple counts. This is a slow & naive version, but good enough here. */
|
|
|
|
|
|
|
|
|
|
static const u8 count_class_lookup[256] = {
|
|
|
|
@ -105,6 +104,8 @@ static const u8 count_class_lookup[256] = {
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* 根据分类查找表对位图中的计数值进行分类 */
|
|
|
|
|
|
|
|
|
|
static void classify_counts(u8* mem) {
|
|
|
|
|
|
|
|
|
|
u32 i = MAP_SIZE;
|
|
|
|
@ -127,8 +128,7 @@ static void classify_counts(u8* mem) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Apply mask to classified bitmap (if set). */
|
|
|
|
|
/* 如果设置了掩码,则对分类后的位图应用掩码 */
|
|
|
|
|
|
|
|
|
|
static void apply_mask(u32* mem, u32* mask) {
|
|
|
|
|
|
|
|
|
@ -146,8 +146,7 @@ static void apply_mask(u32* mem, u32* mask) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* See if any bytes are set in the bitmap. */
|
|
|
|
|
/* 检查位图中是否有任何字节被设置 */
|
|
|
|
|
|
|
|
|
|
static inline u8 anything_set(void) {
|
|
|
|
|
|
|
|
|
@ -160,9 +159,7 @@ static inline u8 anything_set(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Get rid of shared memory and temp files (atexit handler). */
|
|
|
|
|
/* 清理共享内存和临时文件(atexit处理程序) */
|
|
|
|
|
|
|
|
|
|
static void remove_shm(void) {
|
|
|
|
|
|
|
|
|
@ -171,8 +168,7 @@ static void remove_shm(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Configure shared memory. */
|
|
|
|
|
/* 配置共享内存 */
|
|
|
|
|
|
|
|
|
|
static void setup_shm(void) {
|
|
|
|
|
|
|
|
|
@ -196,8 +192,7 @@ static void setup_shm(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read initial file. */
|
|
|
|
|
/* 读取初始文件 */
|
|
|
|
|
|
|
|
|
|
static void read_initial_file(void) {
|
|
|
|
|
|
|
|
|
@ -223,8 +218,7 @@ static void read_initial_file(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Write output file. */
|
|
|
|
|
/* 将数据写入文件 */
|
|
|
|
|
|
|
|
|
|
static s32 write_to_file(u8* path, u8* mem, u32 len) {
|
|
|
|
|
|
|
|
|
@ -244,8 +238,7 @@ static s32 write_to_file(u8* path, u8* mem, u32 len) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle timeout signal. */
|
|
|
|
|
/* 处理超时信号 */
|
|
|
|
|
|
|
|
|
|
static void handle_timeout(int sig) {
|
|
|
|
|
|
|
|
|
@ -254,9 +247,7 @@ static void handle_timeout(int sig) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Execute target application. Returns 0 if the changes are a dud, or
|
|
|
|
|
1 if they should be kept. */
|
|
|
|
|
/* 执行目标应用程序。如果更改无效返回0,否则返回1 */
|
|
|
|
|
|
|
|
|
|
static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
@ -321,7 +312,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
|
close(prog_in_fd);
|
|
|
|
|
|
|
|
|
|
/* Configure timeout, wait for child, cancel timeout. */
|
|
|
|
|
/* 配置超时,等待子进程,取消超时 */
|
|
|
|
|
|
|
|
|
|
child_timed_out = 0;
|
|
|
|
|
it.it_value.tv_sec = (exec_tmout / 1000);
|
|
|
|
@ -339,7 +330,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
|
MEM_BARRIER();
|
|
|
|
|
|
|
|
|
|
/* Clean up bitmap, analyze exit condition, etc. */
|
|
|
|
|
/* 清理位图,分析退出条件等 */
|
|
|
|
|
|
|
|
|
|
if (*(u32*)trace_bits == EXEC_FAIL_SIG)
|
|
|
|
|
FATAL("Unable to execute '%s'", argv[0]);
|
|
|
|
@ -356,7 +347,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Always discard inputs that time out. */
|
|
|
|
|
/* 始终丢弃超时的输入 */
|
|
|
|
|
|
|
|
|
|
if (child_timed_out) {
|
|
|
|
|
|
|
|
|
@ -365,7 +356,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Handle crashing inputs depending on current mode. */
|
|
|
|
|
/* 根据当前模式处理崩溃的输入 */
|
|
|
|
|
|
|
|
|
|
if (WIFSIGNALED(status) ||
|
|
|
|
|
(WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
|
|
|
|
@ -386,7 +377,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
|
|
/* Handle non-crashing inputs appropriately. */
|
|
|
|
|
/* 根据当前模式处理非崩溃的输入 */
|
|
|
|
|
|
|
|
|
|
if (crash_mode) {
|
|
|
|
|
|
|
|
|
@ -406,8 +397,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find first power of two greater or equal to val. */
|
|
|
|
|
/* 找到大于或等于val的第一个2的幂 */
|
|
|
|
|
|
|
|
|
|
static u32 next_p2(u32 val) {
|
|
|
|
|
|
|
|
|
@ -417,8 +407,7 @@ static u32 next_p2(u32 val) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Actually minimize! */
|
|
|
|
|
/* 实际地进行最小化 */
|
|
|
|
|
|
|
|
|
|
static void minimize(char** argv) {
|
|
|
|
|
|
|
|
|
@ -507,10 +496,9 @@ next_del_blksize:
|
|
|
|
|
tail_len = in_len - del_pos - del_len;
|
|
|
|
|
if (tail_len < 0) tail_len = 0;
|
|
|
|
|
|
|
|
|
|
/* If we have processed at least one full block (initially, prev_del == 1),
|
|
|
|
|
and we did so without deleting the previous one, and we aren't at the
|
|
|
|
|
very end of the buffer (tail_len > 0), and the current block is the same
|
|
|
|
|
as the previous one... skip this step as a no-op. */
|
|
|
|
|
/* 如果我们已经处理了一个完整的块(最初,prev_del == 1),
|
|
|
|
|
并且没有删除前一个块,且我们不在缓冲区的末尾(tail_len > 0),
|
|
|
|
|
并且当前块与前一个块相同... 则跳过此步骤作为无操作 */
|
|
|
|
|
|
|
|
|
|
if (!prev_del && tail_len && !memcmp(in_data + del_pos - del_len,
|
|
|
|
|
in_data + del_pos, del_len)) {
|
|
|
|
@ -522,10 +510,10 @@ next_del_blksize:
|
|
|
|
|
|
|
|
|
|
prev_del = 0;
|
|
|
|
|
|
|
|
|
|
/* Head */
|
|
|
|
|
/* 头部 */
|
|
|
|
|
memcpy(tmp_buf, in_data, del_pos);
|
|
|
|
|
|
|
|
|
|
/* Tail */
|
|
|
|
|
/* 尾部 */
|
|
|
|
|
memcpy(tmp_buf + del_pos, in_data + del_pos + del_len, tail_len);
|
|
|
|
|
|
|
|
|
|
res = run_target(argv, tmp_buf, del_pos + tail_len, 0);
|
|
|
|
@ -658,9 +646,7 @@ finalize_all:
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle Ctrl-C and the like. */
|
|
|
|
|
/* 处理Ctrl-C等信号 */
|
|
|
|
|
|
|
|
|
|
static void handle_stop_sig(int sig) {
|
|
|
|
|
|
|
|
|
@ -670,8 +656,7 @@ static void handle_stop_sig(int sig) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Do basic preparations - persistent fds, filenames, etc. */
|
|
|
|
|
/* 进行基本的准备工作 - 持久性文件描述符,文件名等 */
|
|
|
|
|
|
|
|
|
|
static void set_up_environment(void) {
|
|
|
|
|
|
|
|
|
@ -695,7 +680,7 @@ static void set_up_environment(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set sane defaults... */
|
|
|
|
|
/* 设置合理的默认值... */
|
|
|
|
|
|
|
|
|
|
x = getenv("ASAN_OPTIONS");
|
|
|
|
|
|
|
|
|
@ -714,8 +699,7 @@ static void set_up_environment(void) {
|
|
|
|
|
if (x) {
|
|
|
|
|
|
|
|
|
|
if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR)))
|
|
|
|
|
FATAL("Custom MSAN_OPTIONS set without exit_code="
|
|
|
|
|
STRINGIFY(MSAN_ERROR) " - please fix!");
|
|
|
|
|
FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(MSAN_ERROR) " - please fix!");
|
|
|
|
|
|
|
|
|
|
if (!strstr(x, "symbolize=0"))
|
|
|
|
|
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
|
|
|
|
@ -740,8 +724,7 @@ static void set_up_environment(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Setup signal handlers, duh. */
|
|
|
|
|
/* 设置信号处理程序 */
|
|
|
|
|
|
|
|
|
|
static void setup_signal_handlers(void) {
|
|
|
|
|
|
|
|
|
@ -753,22 +736,21 @@ static void setup_signal_handlers(void) {
|
|
|
|
|
|
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
|
|
|
|
|
|
/* Various ways of saying "stop". */
|
|
|
|
|
/* 各种方式表示“停止”。 */
|
|
|
|
|
|
|
|
|
|
sa.sa_handler = handle_stop_sig;
|
|
|
|
|
sigaction(SIGHUP, &sa, NULL);
|
|
|
|
|
sigaction(SIGINT, &sa, NULL);
|
|
|
|
|
sigaction(SIGTERM, &sa, NULL);
|
|
|
|
|
|
|
|
|
|
/* Exec timeout notifications. */
|
|
|
|
|
/* 执行超时通知。 */
|
|
|
|
|
|
|
|
|
|
sa.sa_handler = handle_timeout;
|
|
|
|
|
sigaction(SIGALRM, &sa, NULL);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Detect @@ in args. */
|
|
|
|
|
/* 检测参数中的@@ */
|
|
|
|
|
|
|
|
|
|
static void detect_file_args(char** argv) {
|
|
|
|
|
|
|
|
|
@ -785,12 +767,12 @@ static void detect_file_args(char** argv) {
|
|
|
|
|
|
|
|
|
|
u8 *aa_subst, *n_arg;
|
|
|
|
|
|
|
|
|
|
/* Be sure that we're always using fully-qualified paths. */
|
|
|
|
|
/* 确保总是使用全路径。 */
|
|
|
|
|
|
|
|
|
|
if (prog_in[0] == '/') aa_subst = prog_in;
|
|
|
|
|
else aa_subst = alloc_printf("%s/%s", cwd, prog_in);
|
|
|
|
|
|
|
|
|
|
/* Construct a replacement argv value. */
|
|
|
|
|
/* 构造替换的argv值 */
|
|
|
|
|
|
|
|
|
|
*aa_loc = 0;
|
|
|
|
|
n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
|
|
|
|
@ -809,8 +791,7 @@ static void detect_file_args(char** argv) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Display usage hints. */
|
|
|
|
|
/* 显示使用提示 */
|
|
|
|
|
|
|
|
|
|
static void usage(u8* argv0) {
|
|
|
|
|
|
|
|
|
@ -845,8 +826,7 @@ static void usage(u8* argv0) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find binary. */
|
|
|
|
|
/* 查找二进制文件 */
|
|
|
|
|
|
|
|
|
|
static void find_binary(u8* fname) {
|
|
|
|
|
|
|
|
|
@ -898,21 +878,20 @@ static void find_binary(u8* fname) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fix up argv for QEMU. */
|
|
|
|
|
/* 为QEMU修复argv */
|
|
|
|
|
|
|
|
|
|
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
|
|
|
|
|
|
|
|
|
|
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
|
|
|
|
|
u8 *tmp, *cp, *rsl, *own_copy;
|
|
|
|
|
|
|
|
|
|
/* Workaround for a QEMU stability glitch. */
|
|
|
|
|
/* 为QEMU稳定性问题的解决提供了一个临时的解决方案。 */
|
|
|
|
|
|
|
|
|
|
setenv("QEMU_LOG", "nochain", 1);
|
|
|
|
|
|
|
|
|
|
memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
|
|
|
|
|
|
|
|
|
|
/* Now we need to actually find qemu for argv[0]. */
|
|
|
|
|
/* 现在我们需要实际地找到qemu来运行argv[0] */
|
|
|
|
|
|
|
|
|
|
new_argv[2] = target_path;
|
|
|
|
|
new_argv[1] = "--";
|
|
|
|
@ -961,8 +940,7 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read mask bitmap from file. This is for the -B option. */
|
|
|
|
|
/* 从文件读取掩码位图。这是为-B选项服务的 */
|
|
|
|
|
|
|
|
|
|
static void read_bitmap(u8* fname) {
|
|
|
|
|
|
|
|
|
@ -976,9 +954,7 @@ static void read_bitmap(u8* fname) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Main entry point */
|
|
|
|
|
/* 主入口点 */
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
@ -1084,18 +1060,14 @@ int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
case 'B': /* load bitmap */
|
|
|
|
|
|
|
|
|
|
/* This is a secret undocumented option! It is speculated to be useful
|
|
|
|
|
if you have a baseline "boring" input file and another "interesting"
|
|
|
|
|
file you want to minimize.
|
|
|
|
|
/* 这是一个秘密的未公开选项!如果有一个基线“无聊”的输入文件和另一个“有趣”的文件你想最小化,
|
|
|
|
|
这个选项可能是有用的。
|
|
|
|
|
|
|
|
|
|
You can dump a binary bitmap for the boring file using
|
|
|
|
|
afl-showmap -b, and then load it into afl-tmin via -B. The minimizer
|
|
|
|
|
will then minimize to preserve only the edges that are unique to
|
|
|
|
|
the interesting input file, but ignoring everything from the
|
|
|
|
|
original map.
|
|
|
|
|
你可以使用afl-showmap -b来为无聊的文件转储二进制位图,
|
|
|
|
|
然后通过-B加载到afl-tmin中。最小化器将只保留有趣输入文件中独特的边,
|
|
|
|
|
但忽略来自原始映射的所有内容。
|
|
|
|
|
|
|
|
|
|
The option may be extended and made more official if it proves
|
|
|
|
|
to be useful. */
|
|
|
|
|
如果这个选项被证明是有用的,可能会被扩展并正式记录。 */
|
|
|
|
|
|
|
|
|
|
if (mask_bitmap) FATAL("Multiple -B options not supported");
|
|
|
|
|
mask_bitmap = ck_alloc(MAP_SIZE);
|
|
|
|
@ -1104,7 +1076,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
case 'V': /* Show version number */
|
|
|
|
|
|
|
|
|
|
/* Version number has been printed already, just quit. */
|
|
|
|
|
/* 版本号已经打印过了,直接退出 */
|
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -1169,5 +1141,4 @@ int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|