关于 fuzzing
该技能指导 Agent 使用 libFuzzer、AFL++ 等流程设置并运行覆盖率引导的模糊测试,涵盖目标编写、Sanitizer 构建、崩溃复现、语料管理和 CI,适合测试软件健壮性的开发者。
主要功能
- 01libFuzzer 与 AFL++ 配置
- 02编写与构建 fuzz target
- 03Sanitizer 集成
- 04崩溃复现与语料管理
- 05CI 与 OSS-Fuzz 指引
- 06结构感知与数据流追踪
适用场景
- 01为解析器或反序列化器创建模糊测试
- 02重现并调试 Fuzzer 发现的崩溃
- 03在 CI 中运行短时模糊测试
- 04合并或精简测试语料
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill fuzzing安装后在 Claude Code 中输入/fuzzing确认已加载。
附带文件references/targets.md
详细介绍
模糊测试
目的
指导 Agent 设置并运行覆盖率引导的模糊测试:libFuzzer(进程内)和 AFL++(基于 fork),以及集成 Sanitizer 和设置 CI 流水线。
触发条件
- “如何对我的解析器/反序列化器进行模糊测试?”
- “什么是模糊测试目标/如何编写一个?”
- “如何设置 libFuzzer?”
- “如何在我的程序上使用 AFL++?”
- “如何在 CI 中运行模糊测试?”
- “模糊测试器发现了崩溃——如何复现?”
工作流
1. 编写模糊测试目标(libFuzzer)
模糊测试目标是一个接受任意字节并执行被测代码的函数。
// fuzz_parser.c
#include <stdint.h>
#include <stddef.h>
#include "myparser.h"
// Entry point called by libFuzzer with random data
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Must not abort/exit on invalid input (that's expected)
// Must not read outside [data, data+size)
MyParser *p = parser_create();
if (p) {
parser_feed(p, (const char *)data, size);
parser_destroy(p);
}
return 0; // Always return 0 (non-zero means discard input)
}
关键规则:
- 切勿调用
abort()、exit(),或使用会在多次调用间保留状态的全局状态 - 妥善处理所有输入(崩溃 = 发现 Bug)
- 让目标保持快速:模糊测试器会调用它数百万次
2. 使用 libFuzzer 构建
# Clang (libFuzzer is built into Clang)
clang -fsanitize=fuzzer,address -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
# With UBSan too
clang -fsanitize=fuzzer,address,undefined -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
-fsanitize=fuzzer 会链接 libFuzzer 并提供 main()。不要在模糊测试目标中提供自己的 main()。
3. 运行 libFuzzer
# Create corpus directory
mkdir -p corpus
# Seed with known-good inputs (greatly accelerates coverage)
cp tests/inputs/* corpus/
# Run the fuzzer
./fuzz_parser corpus/ -max_len=65536 -timeout=10
# Run for a time limit
./fuzz_parser corpus/ -max_total_time=3600
# Run with specific number of jobs (parallel)
./fuzz_parser corpus/ -jobs=4 -workers=4
# Minimise a corpus (remove redundant inputs)
./fuzz_parser -merge=1 corpus_min/ corpus/
常用标志:
| 标志 | 默认值 | 效果 |
|---|---|---|
-max_len=N | 4096 | 输入的最大字节数 |
-timeout=N | 1200 | 如果单次运行耗时超过 N 秒,则终止 |
-max_total_time=N | 0(永久) | 模糊测试总时长 |
-runs=N | -1(无限) | 运行总次数 |
-dict=file | 无 | 有意义标记的字典 |
-jobs=N | 1 | 并行任务(每个任务写入自己的日志) |
-merge=1 | 关闭 | 合并模式:精简语料库 |
4. 复现崩溃
libFuzzer 会将崩溃输入写入文件,文件名为 crash-<hash>、oom-<hash>、timeout-<hash>。
# Reproduce
./fuzz_parser crash-abc123
# Debug with GDB
gdb ./fuzz_parser
(gdb) run crash-abc123
5. 设置 AFL++
AFL++ 是一种基于 fork 的模糊测试器,可用于任意程序(不限于带有模糊测试入口点的程序)。
# Install
apt install afl++ # or build from source
# Instrument the target
CC=afl-clang-fast CXX=afl-clang-fast++ \
cmake -S . -B build-afl -DCMAKE_BUILD_TYPE=Debug
cmake --build build-afl
# Or compile directly
afl-clang-fast -g -O1 -o prog_afl main.c myparser.c
# Create input corpus
mkdir -p afl-input afl-output
echo "hello" > afl-input/seed1
# Run
afl-fuzz -i afl-input -o afl-output -- ./prog_afl @@
# @@ is replaced with the input file path
# For stdin-based programs: remove @@
afl-fuzz -i afl-input -o afl-output -- ./prog_afl
6. 使用持久模式运行 AFL++(更快)
持久模式可避免每个输入都调用一次 fork(),对于库模糊测试来说快得多:
// In your harness:
#include "myparser.h"
int main(int argc, char **argv) {
while (__AFL_LOOP(1000)) {
// Read input
unsigned char *buf = NULL;
ssize_t len = read(0, &buf, MAX_SIZE); // or use afl_custom_mutator
parser_feed((char*)buf, len);
free(buf);
}
return 0;
}
7. 语料库管理
# AFL++ corpus minimisation
afl-cmin -i afl-output/default/queue -o corpus_min -- ./prog_afl @@
# Merge libFuzzer corpora from multiple runs
./fuzz_parser -merge=1 merged_corpus/ run1_corpus/ run2_corpus/
# Show coverage (libFuzzer)
./fuzz_parser corpus/ -runs=0 -print_coverage=1
8. 集成 CI
# GitHub Actions example
- name: Build fuzz targets
run: |
clang -fsanitize=fuzzer,address,undefined -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
- name: Short fuzz run (regression check)
run: |
./fuzz_parser corpus/ -max_total_time=60 -error_exitcode=1
# Also run known crash inputs if any:
ls known_crashes/ 2>/dev/null | xargs -I{} ./fuzz_parser known_crashes/{}
对于长时间运行的模糊测试,请使用 OSS-Fuzz 或 ClusterFuzz 基础设施。
9. 感知结构的模糊测试(libFuzzer)
// Custom mutator hook — preserve format invariants
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed) {
// Delegate to default mutator then fix up structure
Size = LLVMFuzzerMutate(Data, Size, MaxSize);
if (Size >= 4)
fix_checksum(Data, Size);
return Size;
}
// Register custom crossover for structured inputs
extern "C" size_t LLVMFuzzerCustomCrossOver(
const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize, unsigned int Seed);
当朴素的位翻转会破坏校验和/标头,导致无法到达深层代码路径时使用。
10. Atheris(Python 模糊测试)
import atheris
import sys
with atheris.instrument_imports():
import myparser
def TestOneInput(data: bytes) -> None:
fdp = atheris.FuzzedDataProvider(data)
try:
myparser.parse(fdp.ConsumeString(sys.maxsize))
except myparser.ParseError:
pass
if __name__ == "__main__":
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
pip install atheris
python fuzz_myparser.py corpus/ -max_total_time=300
11. 数据流跟踪
# Track tainted bytes through execution (LLVM dataflow sanitizer + libFuzzer)
clang -fsanitize=fuzzer,dataflow -g -O1 fuzz.c target.c -o fuzz
LIBFUZZER_DATAFLOW_TRACE=1 ./fuzz corpus/
生成跟踪记录,显示哪些输入字节影响了分支——以此指导字典和感知结构的变异器。
12. 集成 OSS-Fuzz
OSS-Fuzz workflow
├── Add project/ in google/oss-fuzz repo (Dockerfile + build.sh)
├── Fuzz targets linked with -fsanitize=fuzzer,address
├── ClusterFuzz runs continuously on GCE
└── Crash reproducers uploaded to issue tracker
# project/Dockerfile (minimal)
FROM gcr.io/oss-fuzz-base/base-builder
RUN git clone --depth 1 https://github.com/you/yourproject
WORKDIR yourproject
COPY build.sh $SRC/
# Local OSS-Fuzz repro
python infra/helper.py build_image yourproject
python infra/helper.py build_fuzzers yourproject
python infra/helper.py run_fuzzer yourproject fuzz_target
13. Zig 模糊测试
# Zig 0.11+ built-in fuzzing
zig build test --fuzz
# fuzz target in build.zig
# .root_module.fuzz_tests = &.{
# .{ .name = "parser", .path = "src/fuzz/parser.zig" },
# };
Zig fuzz 与 zig test 和原生目标的 Sanitizer 构建集成。
14. 字典文件
字典包含有意义的标记,用于引导变异:
# parser.dict
kw1="<"
kw2=">"
kw3="</"
kw4='="'
kw5="\x00"
kw6="\xff\xfe"
./fuzz_parser corpus/ -dict=parser.dict
参考资料
有关模糊测试目标模板、语料库种子示例和 OSS-Fuzz 集成指南,请参阅 references/targets.md。
相关技能
- 使用
skills/runtimes/sanitizers为模糊测试构建添加 ASan/UBSan - 使用
skills/compilers/clang了解 Clang 专用的 libFuzzer 标志 - 使用
skills/debuggers/gdb调试模糊测试器发现的崩溃输入 - 使用
skills/zig/zig-testing了解 Zigbuild test --fuzz工作流 - 使用
skills/security/kernel-security通过 syzkaller 进行内核模糊测试
评论
支持 Markdown