name: address-sanitizer type: technique description: > 地址消毒器在模糊测试期间检测内存错误。 在模糊测试C/C++代码时使用,以查找缓冲区溢出和使用后释放错误。
地址消毒器 (ASan)
地址消毒器 (ASan) 是一个广泛采用的内存错误检测工具,在软件测试中,特别是模糊测试中广泛使用。它有助于检测可能被忽视的内存损坏错误,如缓冲区溢出、使用后释放错误和其他内存安全违规。
概述
ASan 是模糊测试中的标准实践,因为它能有效识别内存漏洞。它在编译时对代码进行检测,以跟踪内存分配和访问,在运行时检测非法操作。
关键概念
| 概念 | 描述 |
|---|---|
| 检测 | ASan 在编译期间向内存操作添加运行时检查 |
| 影子内存 | 映射 20TB 虚拟内存以跟踪分配状态 |
| 性能成本 | 与非检测代码相比,大约有2-4倍的减速 |
| 检测范围 | 查找缓冲区溢出、使用后释放、双重释放和内存泄漏 |
何时应用
应用此技术当:
- 模糊测试C/C++代码以查找内存安全漏洞
- 测试带有不安全块的Rust代码
- 调试与内存损坏相关的崩溃
- 运行怀疑有内存错误的单元测试
跳过此技术当:
- 运行生产代码(ASan可能降低安全性)
- 平台是Windows或macOS(ASan支持有限)
- 性能开销对您的用例不可接受
- 模糊测试纯安全语言无FFI(例如纯Go、纯Java)
快速参考
| 任务 | 命令/模式 |
|---|---|
| 启用 ASan (Clang/GCC) | -fsanitize=address |
| 启用详细输出 | ASAN_OPTIONS=verbosity=1 |
| 禁用泄漏检测 | ASAN_OPTIONS=detect_leaks=0 |
| 错误时强制终止 | ASAN_OPTIONS=abort_on_error=1 |
| 多个选项 | ASAN_OPTIONS=verbosity=1:abort_on_error=1 |
分步指南
步骤 1: 使用 ASan 编译
使用 -fsanitize=address 标志编译和链接您的代码:
clang -fsanitize=address -g -o my_program my_program.c
建议使用 -g 标志,以便在 ASan 检测到错误时获得更好的堆栈跟踪。
步骤 2: 配置 ASan 选项
设置 ASAN_OPTIONS 环境变量以配置 ASan 行为:
export ASAN_OPTIONS=verbosity=1:abort_on_error=1:detect_leaks=0
步骤 3: 运行您的程序
执行 ASan 检测的二进制文件。当检测到内存错误时,ASan 将打印详细报告:
./my_program
步骤 4: 调整模糊测试器内存限制
ASan 需要大约 20TB 的虚拟内存。禁用模糊测试器的内存限制:
- libFuzzer:
-rss_limit_mb=0 - AFL++:
-m none
常见模式
模式: 基本 ASan 集成
用例: 标准模糊测试设置与 ASan
之前:
clang -o fuzz_target fuzz_target.c
./fuzz_target
之后:
clang -fsanitize=address -g -o fuzz_target fuzz_target.c
ASAN_OPTIONS=verbosity=1:abort_on_error=1 ./fuzz_target
模式: ASan 与单元测试
用例: 为单元测试套件启用 ASan
之前:
gcc -o test_suite test_suite.c -lcheck
./test_suite
之后:
gcc -fsanitize=address -g -o test_suite test_suite.c -lcheck
ASAN_OPTIONS=detect_leaks=1 ./test_suite
高级使用
提示与技巧
| 提示 | 为何有帮助 |
|---|---|
使用 -g 标志 |
为调试提供详细的堆栈跟踪 |
设置 verbosity=1 |
确认 ASan 在程序启动前已启用 |
| 在模糊测试期间禁用泄漏检测 | 泄漏检测不会导致立即崩溃,避免输出杂乱 |
启用 abort_on_error=1 |
某些模糊测试器需要 abort() 而不是 _exit() |
理解 ASan 报告
当 ASan 检测到内存错误时,它会打印详细报告,包括:
- 错误类型:缓冲区溢出、使用后释放等。
- 堆栈跟踪:错误发生的位置
- 分配/释放跟踪:内存分配/释放的位置
- 内存映射:错误周围的影子内存状态
示例 ASan 报告:
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000eff4 at pc 0x00000048e6a3
READ of size 4 at 0x60300000eff4 thread T0
#0 0x48e6a2 in main /path/to/file.c:42
组合消毒器
ASan 可以与其他消毒器组合以进行全面检测:
clang -fsanitize=address,undefined -g -o fuzz_target fuzz_target.c
平台特定考虑
Linux:完整的 ASan 支持,性能最佳 macOS:支持有限,某些功能可能无法工作 Windows:实验性支持,不建议用于生产模糊测试
反模式
| 反模式 | 问题 | 正确方法 |
|---|---|---|
| 在生产中使用 ASan | 可能使应用程序安全性降低 | 仅将 ASan 用于测试 |
| 未禁用内存限制 | 模糊测试器可能因 20TB 虚拟内存而终止进程 | 设置 -rss_limit_mb=0 或 -m none |
| 忽略泄漏报告 | 内存泄漏表示资源管理问题 | 在模糊测试活动结束时审查泄漏报告 |
工具特定指导
libFuzzer
同时使用模糊测试器和地址消毒器编译:
clang++ -fsanitize=fuzzer,address -g harness.cc -o fuzz
以无限 RSS 运行:
./fuzz -rss_limit_mb=0
集成提示:
- 总是结合
-fsanitize=fuzzer与-fsanitize=address - 使用
-g以获得崩溃报告中的详细堆栈跟踪 - 考虑
ASAN_OPTIONS=abort_on_error=1以更好地处理崩溃
参见: libFuzzer: AddressSanitizer
AFL++
使用 AFL_USE_ASAN 环境变量:
AFL_USE_ASAN=1 afl-clang-fast++ -g harness.cc -o fuzz
以无限内存运行:
afl-fuzz -m none -i input_dir -o output_dir ./fuzz
集成提示:
AFL_USE_ASAN=1自动添加正确的编译标志- 使用
-m none以禁用 AFL++ 的内存限制 - 考虑
AFL_MAP_SIZE用于具有大覆盖率图的程序
cargo-fuzz (Rust)
使用 --sanitizer=address 标志:
cargo fuzz run fuzz_target --sanitizer=address
或在 fuzz/Cargo.toml 中配置:
[profile.release]
opt-level = 3
debug = true
集成提示:
- ASan 对模糊测试不安全 Rust 代码或 FFI 边界有用
- 安全 Rust 代码可能受益不多(编译器已预防许多错误)
- 专注于不安全块、原始指针和 C 库绑定
参见: cargo-fuzz: AddressSanitizer
honggfuzz
使用 ASan 编译并与 honggfuzz 链接:
honggfuzz -i input_dir -o output_dir -- ./fuzz_target_asan
编译目标:
hfuzz-clang -fsanitize=address -g target.c -o fuzz_target_asan
集成提示:
- honggfuzz 开箱即用地与 ASan 配合良好
- 使用反馈驱动模式以获得更好的覆盖率与消毒器
- 监控内存使用,因为 ASan 增加内存占用
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 模糊测试器立即终止进程 | 内存限制过低,无法满足 ASan 的 20TB 虚拟内存 | 使用 -rss_limit_mb=0 (libFuzzer) 或 -m none (AFL++) |
| “ASan 运行时未初始化” | 链接顺序错误或缺少运行时 | 确保在编译和链接中都使用 -fsanitize=address |
| 泄漏报告使输出杂乱 | LeakSanitizer 默认启用 | 设置 ASAN_OPTIONS=detect_leaks=0 |
| 性能差 (>4倍减速) | 调试模式或未优化构建 | 同时使用 -O2 或 -O3 与 -fsanitize=address 编译 |
| ASan 未检测到明显错误 | 二进制未检测 | 使用 ASAN_OPTIONS=verbosity=1 检查 ASan 是否打印启动信息 |
| 误报 | 拦截器冲突 | 检查 ASan FAQ 以了解特定库的已知问题 |
相关技能
使用此技术的工具
| 技能 | 如何应用 |
|---|---|
| libfuzzer | 使用 -fsanitize=fuzzer,address 编译以集成模糊测试与内存错误检测 |
| aflpp | 在编译期间使用 AFL_USE_ASAN=1 环境变量 |
| cargo-fuzz | 使用 --sanitizer=address 标志以启用 Rust 模糊测试目标的 ASan |
| honggfuzz | 使用 -fsanitize=address 编译目标以进行 ASan 检测的模糊测试 |
相关技术
| 技能 | 关系 |
|---|---|
| undefined-behavior-sanitizer | 常与 ASan 结合使用以全面检测错误(未定义行为 + 内存错误) |
| fuzz-harness-writing | 必须设计测试框架以处理 ASan 检测的崩溃并避免误报 |
| coverage-analysis | 覆盖率引导的模糊测试有助于触发代码路径,使 ASan 能够检测内存错误 |
资源
关键外部资源
AddressSanitizer on Google Sanitizers Wiki
官方 ASan 文档涵盖:
- 算法和实现细节
- 检测到的错误类型的完整列表
- 性能特征和开销
- 平台特定行为
- 已知限制和兼容性问题
所有消毒器共享的常见配置标志:
verbosity:控制诊断输出级别log_path:将消毒器输出重定向到文件symbolize:在报告中启用/禁用符号解析external_symbolizer_path:使用自定义符号化器
ASan 特定配置选项:
detect_leaks:控制内存泄漏检测abort_on_error:错误时调用abort()对比_exit()detect_stack_use_after_return:检测栈使用后返回错误check_initialization_order:查找初始化顺序错误
常见陷阱和解决方案:
- 链接顺序问题
- 与其他工具的冲突
- 平台特定问题
- 性能调整提示
Clang AddressSanitizer Documentation
Clang 特定指导:
- 编译标志和选项
- 与其他 Clang 功能的交互
- 支持的平台和架构
GCC 特定 ASan 文档:
- GCC 特定标志和行为
- 与 Clang 实现的差异
- GCC 中的平台支持
AddressSanitizer: A Fast Address Sanity Checker (USENIX Paper)
具有技术细节的原始研究论文:
- 影子内存算法
- 虚拟内存要求(历史上 16TB,现在约 20TB)
- 性能基准测试
- 设计决策和权衡