标题: [翻译]AFL + ASAN 分类: Fuzzing 创建: 2023-09-11 21:15 修改: 链接: http://0x2531.tech/fuzzing/202309112115.txt -------------------------------------------------------------------------------- ================================== Notes for using ASAN with afl-fuzz 在 afl-fuzz 中使用 ASAN 的说明 ================================== This file discusses some of the caveats for fuzzing under ASAN, and suggests a handful of alternatives. See README for the general instruction manual. 本文讨论了 ASAN 下模糊测试的一些注意事项,并提出了几个替代方案。查看 README 文档了解一般说明。 1) Short version 简短说明 ---------------- ASAN on 64-bit systems requests a lot of memory in a way that can't be easily distinguished from a misbehaving program bent on crashing your system. 64 位系统上的 ASAN 会请求大量内存,并且很难将其与导致程序崩溃的异常行为区分开来。 Because of this, fuzzing with ASAN is recommended only in four scenarios: 鉴于此,仅建议在如下4种场景下使用 ASAN 进行模糊测试: - On 32-bit systems, where we can always enforce a reasonable memory limit (-m 800 or so is a good starting point), 在 32 位系统上,可以通过 -m 选项限制内存使用(因为 ASAN 需要大约 600-800 MB内存, -m 800 是一个好的开始) - On 64-bit systems only if you can do one of the following: 满足以下条件之一时,才在 64 位系统上使用: - Compile the binary in 32-bit mode (gcc -m32), 使用 32 位模式编译目标程序(如:gcc -m32) - Precisely gauge memory needs using http://jwilk.net/software/recidivm . 使用类似 recidivm 工具准确监控内存的使用情况 - Limit the memory available to process using cgroups on Linux (see experimental/asan_cgroups). 在 Linux 上使用 cgroups 限制进程可使用的内存 To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags. Note that ASAN is incompatible with -static, so be mindful of that. 为了结合 ASAN 编译目标程序,在执行 'make clean all' 命令前设置 AFL_USE_ASAN=1。 afl-gcc / afl-clang 包装器将识别它并添加适当的标志。记住,ASAN 和 -static 不兼容。 (You can also use AFL_USE_MSAN=1 to enable MSAN instead.) (MSAN 的话,使用 AFL_USE_MSAN=1 代替) There is also the option of generating a corpus using a non-ASAN binary, and then feeding it to an ASAN-instrumented one to check for bugs. This is faster, and can give you somewhat comparable results. You can also try using libdislocator (see libdislocator/README.dislocator in the parent directory) as a lightweight and hassle-free (but less thorough) alternative. 还可以选择先使用非 ASAN 目标程序生成导致程序崩溃的测试用例,然后使用这些测试用例执行带 ASAN 的 目标程序,以确认导致程序崩溃的缺陷类型。这种方式效率更高。也可以尝试使用 libdislocator 作为轻量级 的替代方案。 2) Long version 详细说明 --------------- ASAN allocates a huge region of virtual address space for bookkeeping purposes. Most of this is never actually accessed, so the OS never has to allocate any real pages of memory for the process, and the VM grabbed by ASAN is essentially "free" - but the mapping counts against the standard OS-enforced limit (RLIMIT_AS, aka ulimit -v). ASAN 分配巨大的虚拟地址空间用于 bookkeeping 目的。其中,大部分从未被实际访问过, 因此操作系统永远不必为进程分配任何实际的内存页面,并且 ASAN 获取的虚拟内存本质是免费的。 但内存映射会违背标准的操作系统强制限制(RLIMIT_AS, 也就是 ulimit -v)。 On our end, afl-fuzz tries to protect you from processes that go off-rails and start consuming all the available memory in a vain attempt to parse a malformed input file. This happens surprisingly often, so enforcing such a limit is important for almost any fuzzer: the alternative is for the kernel OOM handler to step in and start killing random processes to free up resources. Needless to say, that's not a very nice prospect to live with. 就我们而言,afl-fuzz 试图规避在处理不受控制的一开始耗尽所有可用内存去徒劳的解析格式错误 的输入文件的影响。这种情况经常发生,因此这种强制限制对几乎所有模糊器都很重要。另一种选择 是让内核 OOM 处理程序介入并随机杀死进程以释放资源。不用说,这不是一个好方法。 Unfortunately, un*x systems offer no portable way to limit the amount of pages actually given to a process in a way that distinguishes between that and the harmless "land grab" done by ASAN. In principle, there are three standard ways to limit the size of the heap: 不幸的是,Unix 家族系统没有提供可移植的方法来限制实际提供给进程的页面数量,故无法区分出 ASAN 分配 巨大虚拟地址空间的无害行为。原则上,限制堆大小的标准方法有以下3种: - The RLIMIT_AS mechanism (ulimit -v) caps the size of the virtual space - but as noted, this pays no attention to the number of pages actually in use by the process, and doesn't help us here. RLIMIT_AS 机制 (ulimit -v) 限制了虚拟空间的大小 - 但如上所述,它不考虑进程实际使用的页面数 量,因此对我们没有帮助。 - The RLIMIT_DATA mechanism (ulimit -d) seems like a good fit, but it applies only to the traditional sbrk() / brk() methods of requesting heap space; modern allocators, including the one in glibc, routinely rely on mmap() instead, and circumvent this limit completely. RLIMIT_DATA 机制(ulimit -d)似乎很合适,但它仅应用于传统的 sbrk() 和 brk() 方法; 现代分配器,包括 glibc 中的分配器,通常依赖于 mmap(),并完全规避这一限制。 - Finally, the RLIMIT_RSS limit (ulimit -m) sounds like what we need, but doesn't work on Linux - mostly because nobody felt like implementing it. 最后,RLIMIT_RSS 限制 (ulimit -m) 听起来像我们需要的,但在 Linux 上不起作用 - 主要是因为没有人愿意实现它。 There are also cgroups, but they are Linux-specific, not universally available even on Linux systems, and they require root permissions to set up; I'm a bit hesitant to make afl-fuzz require root permissions just for that. That said, if you are on Linux and want to use cgroups, check out the contributed script that ships in experimental/asan_cgroups/. 还有 cgroups,但他是特定于 Linux 的,即使在 Linux 系统上也不是普遍可用,同时设置还需要 具有 root 权限。我有点犹豫是否要让 afl-fuzz 为此需要 root 权限。如果 你工作在 Linux 上并且想要使用 cgroups,请查看 Experimental/asan_cgroups/ 中附带的脚本。 In settings where cgroups aren't available, we have no nice, portable way to avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for binaries compiled in 32-bit mode (-m32), this is not a big deal: ASAN needs around 600-800 MB or so, depending on the compiler - so all you need to do is to specify -m that is a bit higher than that. 在 cgroups 不可用的情况下,我们没有好的、可移植的方法来避免将 ASAN 分配计入限制。 在 32 位系统上,或者对于以 32 位模式 (-m32) 编译的二进制目标程序,这并不是什么大问题: ASAN 需要大约 600-800 MB 内存,具体取决于编译器 - 所以需要指定比该值稍高的 -m。 On 64-bit systems, the situation is more murky, because the ASAN allocation is completely outlandish - around 17.5 TB in older versions, and closer to 20 TB with newest ones. The actual amount of memory on your system is (probably!) just a tiny fraction of that - so unless you dial the limit with surgical precision, you will get no protection from OOM bugs. 在 64 位系统上,因为 ASAN 内存分配非常诡异,所以情况更加模糊 - 旧版本中约为 17.5 TB,最新版本 接近 20 TB。系统上的实际内存量只是其中的一小部分 - 因此,除非精确的监控内存使用,否则将无法避免 OOM 错误。 On my system, the amount of memory grabbed by ASAN with a slightly older version of gcc is around 17,825,850 MB; for newest clang, it's 20,971,600. But there is no guarantee that these numbers are stable, and if you get them wrong by "just" a couple gigs or so, you will be at risk. 在我的系统上,使用稍旧版本的 gcc 的 ASAN 占用的内存量约为 17,825,850 MB; 对于最新的 clang,它是 20,971,600。但并不能保证这些数字是稳定的。 To get the precise number, you can use the recidivm tool developed by Jakub Wilk (http://jwilk.net/software/recidivm). In absence of this, ASAN is *not* recommended when fuzzing 64-bit binaries, unless you are confident that they are robust and enforce reasonable memory limits (in which case, you can specify '-m none' when calling afl-fuzz). 要获得精确的数字,可以使用 Jakub Wilk 开发的 recidivm 工具 (http://jwilk.net/software/recidivm)。 否则,在模糊测试 64 位二进制目标程序时不推荐使用 ASAN,除非你确信目标程序是健壮的并且强制执行合理的 内存限制(在这种情况下,在调用 afl-fuzz 时指定 '-m none') 。 Using recidivm or running with no limits aside, there are two other decent alternatives: build a corpus of test cases using a non-ASAN binary, and then examine them with ASAN, Valgrind, or other heavy-duty tools in a more controlled setting; or compile the target program with -m32 (32-bit mode) if your system supports that. 除了使用 recidivm 或无限制运行之外,还有两种不错的选择:先使用非 ASAN 目标程序生成导致程序崩溃的测 试用例,然后在更受控的设置中使用 ASAN、Valgrind 等工具检查它们;或者使用 -m32 (32 位模式)编译目 标程序。 3) Interactions with the QEMU mode QEMU 模式 ---------------------------------- ASAN, MSAN, and other sanitizers appear to be incompatible with QEMU user emulation, so please do not try to use them with the -Q option; QEMU doesn't seem to appreciate the shadow VM trick used by these tools, and will likely just allocate all your physical memory, then crash. ASAN、MSAN 和其它一些消毒剂看上去和 QEMU 用户模拟模式并不兼容,所以请不要尝试在 -Q 选项下使用它 们。QEMU 模式并不支持这些消毒剂使用的影子内存技巧。 4) ASAN and OOM crashes ASAN 和 OOM 崩溃 ----------------------- By default, ASAN treats memory allocation failures as fatal errors, immediately causing the program to crash. Since this is a departure from normal POSIX semantics (and creates the appearance of security issues in otherwise properly-behaving programs), we try to disable this by specifying allocator_may_return_null=1 in ASAN_OPTIONS. 默认情况下,ASAN 将内存分配失败视为致命错误,将导致程序立即崩溃。 由于这偏离了正常的 POSIX 规范,因此我们尝试通过在 ASAN_OPTIONS 中指定 allocator_may_return_null=1 来禁用此功能。 Unfortunately, it's been reported that this setting still causes ASAN to trigger phantom crashes in situations where the standard allocator would simply return NULL. If this is interfering with your fuzzing jobs, you may want to cc: yourself on this bug: 不幸的是,据报道在标准分配器仅返回 NULL 的情况下,此设置仍然会导致 ASAN 触发幻影崩溃。 如果这影响到了你的模糊测试工作,可自行查看如下 bug: https://bugs.llvm.org/show_bug.cgi?id=22026 5) What about UBSAN? UBSAN 如何? -------------------- Some folks expressed interest in fuzzing with UBSAN. This isn't officially supported, because many installations of UBSAN don't offer a consistent way to abort() on fault conditions or to terminate with a distinctive exit code. 有些人表示有兴趣使用 UBSAN 进行模糊测试。这不受官方支持,因为 UBSAN 的许多安装不提供在故障情况下 abort() 或以独特的退出代码终止的一致性方法。 That said, some versions of the library can be binary-patched to address this issue, while newer releases support explicit compile-time flags - see this mailing list thread for tips: 也就是说,该库的某些版本可以通过二进制修补来解决此问题,而新版本支持显式的编译时标志 - 请查看如下讨论以获取提示: https://groups.google.com/forum/#!topic/afl-users/GyeSBJt4M38