名称: ossfuzz 类型: 技术 描述: > OSS-Fuzz 为开源项目提供免费的持续模糊测试。 在设置持续模糊测试基础设施或注册项目时使用。
OSS-Fuzz
OSS-Fuzz 是由 Google 开发的一个开源项目,提供免费的分布式基础设施用于持续模糊测试。它简化了模糊测试流程并便于修改。虽然只有选定的项目被接受加入 OSS-Fuzz,但项目的核心是开源的,允许任何人托管自己的实例用于私有项目。
概述
OSS-Fuzz 提供一个简单的 CLI 框架,用于构建和启动测试工具或计算其覆盖率。此外,OSS-Fuzz 可作为服务使用,托管从模糊测试输出(如覆盖率信息)生成的静态网页。
关键概念
| 概念 | 描述 |
|---|---|
| helper.py | 用于本地构建镜像、构建模糊测试器和运行测试工具的 CLI 脚本 |
| 基础镜像 | 提供构建依赖和编译器的分层 Docker 镜像 |
| project.yaml | 定义项目元数据的配置文件,用于 OSS-Fuzz 注册 |
| Dockerfile | 包含项目特定构建依赖的镜像 |
| build.sh | 为项目构建模糊测试工具的脚本 |
| 关键性评分 | OSS-Fuzz 团队用于评估项目接受度的指标 |
适用场景
应用此技术当:
- 为开源项目设置持续模糊测试
- 需要分布式模糊测试基础设施而不管理服务器
- 想要与模糊测试集成的覆盖率报告和错误跟踪
- 本地测试现有 OSS-Fuzz 测试工具
- 从 OSS-Fuzz 错误报告中复现崩溃
跳过此技术当:
- 项目是闭源的(除非托管自己的 OSS-Fuzz 实例)
- 项目未达到 OSS-Fuzz 的关键性评分阈值
- 需要专有或专门的模糊测试基础设施
- 模糊测试简单脚本,不值得使用基础设施
快速参考
| 任务 | 命令 |
|---|---|
| 克隆 OSS-Fuzz | git clone https://github.com/google/oss-fuzz |
| 构建项目镜像 | python3 infra/helper.py build_image --pull <项目> |
| 使用 ASan 构建模糊测试器 | python3 infra/helper.py build_fuzzers --sanitizer=address <项目> |
| 运行特定测试工具 | python3 infra/helper.py run_fuzzer <项目> <测试工具> |
| 生成覆盖率报告 | python3 infra/helper.py coverage <项目> |
| 检查 helper.py 选项 | python3 infra/helper.py --help |
OSS-Fuzz 项目组件
OSS-Fuzz 提供多个公开可用的工具和 Web 界面:
错误跟踪器
错误跟踪器 允许您:
- 检查特定项目的错误(最初仅对维护者可见,后来公开)
- 创建新问题和评论现有问题
- 在所有项目中搜索类似错误以了解问题
构建状态系统
构建状态系统 帮助跟踪:
- 所有包含项目的构建状态
- 上次成功构建的日期
- 构建失败及其持续时间
模糊测试内省器
模糊测试内省器 显示:
- OSS-Fuzz 中注册项目的覆盖率数据
- 覆盖代码的命中频率
- 性能分析和阻塞器识别
阅读此案例研究 获取示例和解释。
步骤:运行单个测试工具
您不需要托管整个 OSS-Fuzz 平台来使用它。helper 脚本使在本地运行单个测试工具变得容易。
步骤 1:克隆 OSS-Fuzz
git clone https://github.com/google/oss-fuzz
cd oss-fuzz
python3 infra/helper.py --help
步骤 2:构建项目镜像
python3 infra/helper.py build_image --pull <项目名称>
这会下载并构建项目的基础 Docker 镜像。
步骤 3:使用 Sanitizers 构建模糊测试器
python3 infra/helper.py build_fuzzers --sanitizer=address <项目名称>
Sanitizer 选项:
--sanitizer=address用于 AddressSanitizer 与 LeakSanitizer- 其他 sanitizers 可用(语言支持不同)
注意: 模糊测试器构建到 /build/out/<项目名称>/ 目录,包含测试工具可执行文件、字典、语料库和崩溃文件。
步骤 4:运行模糊测试器
python3 infra/helper.py run_fuzzer <项目名称> <测试工具名称> [<模糊测试器参数>]
如果您跳过某些步骤,helper 脚本会自动运行任何遗漏的步骤。
步骤 5:覆盖率分析(可选)
首先,安装 gsutil(跳过 gcloud 初始化)。
python3 infra/helper.py build_fuzzers --sanitizer=coverage <项目名称>
python3 infra/helper.py coverage <项目名称>
使用 --no-corpus-download 仅使用本地语料库。该命令生成并在本地托管覆盖率报告。
见官方 OSS-Fuzz 文档 获取详情。
常见模式
模式:运行 irssi 示例
用例: 用简单注册项目测试 OSS-Fuzz 设置
# 克隆并导航到 OSS-Fuzz
git clone https://github.com/google/oss-fuzz
cd oss-fuzz
# 构建并运行 irssi 模糊测试器
python3 infra/helper.py build_image --pull irssi
python3 infra/helper.py build_fuzzers --sanitizer=address irssi
python3 infra/helper.py run_fuzzer irssi irssi-fuzz
预期输出:
INFO:__main__:Running: docker run --rm --privileged --shm-size=2g --platform linux/amd64 -i -e FUZZING_ENGINE=libfuzzer -e SANITIZER=address -e RUN_FUZZER_MODE=interactive -e HELPER=True -v /private/tmp/oss-fuzz/build/out/irssi:/out -t gcr.io/oss-fuzz-base/base-runner run_fuzzer irssi-fuzz.
Using seed corpus: irssi-fuzz_seed_corpus.zip
/out/irssi-fuzz -rss_limit_mb=2560 -timeout=25 /tmp/irssi-fuzz_corpus -max_len=2048 < /dev/null
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1531341664
INFO: Loaded 1 modules (95687 inline 8-bit counters): 95687 [0x1096c80, 0x10ae247),
INFO: Loaded 1 PC tables (95687 PCs): 95687 [0x10ae248,0x1223eb8),
INFO: 719 files found in /tmp/irssi-fuzz_corpus
INFO: seed corpus: files: 719 min: 1b max: 170106b total: 367969b rss: 48Mb
#720 INITED cov: 409 ft: 1738 corp: 640/163Kb exec/s: 0 rss: 62Mb
#762 REDUCE cov: 409 ft: 1738 corp: 640/163Kb lim: 2048 exec/s: 0 rss: 63Mb L: 236/2048 MS: 2 ShuffleBytes-EraseBytes-
模式:注册新项目
用例: 将您的项目添加到 OSS-Fuzz(或私有实例)
在 projects/<您的项目>/ 目录中创建三个文件:
1. project.yaml - 项目元数据:
homepage: "https://github.com/yourorg/yourproject"
language: c++
primary_contact: "your-email@example.com"
main_repo: "https://github.com/yourorg/yourproject"
fuzzing_engines:
- libfuzzer
sanitizers:
- address
- undefined
2. Dockerfile - 构建依赖:
FROM gcr.io/oss-fuzz-base/base-builder
RUN apt-get update && apt-get install -y \
autoconf \
automake \
libtool \
pkg-config
RUN git clone --depth 1 https://github.com/yourorg/yourproject
WORKDIR yourproject
COPY build.sh $SRC/
3. build.sh - 构建测试工具:
#!/bin/bash -eu
./autogen.sh
./configure --disable-shared
make -j$(nproc)
# 构建测试工具
$CXX $CXXFLAGS -std=c++11 -I. \
$SRC/yourproject/fuzz/harness.cc -o $OUT/harness \
$LIB_FUZZING_ENGINE ./libyourproject.a
# 复制语料库和字典(如可用)
cp $SRC/yourproject/fuzz/corpus.zip $OUT/harness_seed_corpus.zip
cp $SRC/yourproject/fuzz/dictionary.dict $OUT/harness.dict
OSS-Fuzz 中的 Docker 镜像
测试工具在 Docker 容器中构建和执行。所有项目共享一个运行器镜像,但每个项目有自己的构建镜像。
镜像层次结构
镜像按此顺序构建:
- base_image - 特定 Ubuntu 版本
- base_clang - Clang 编译器;基于
base_image - base_builder - 构建依赖;基于
base_clang- 语言特定变体:
base_builder_go, 等。 - 见 /oss-fuzz/infra/base-images/ 获取完整列表
- 语言特定变体:
- 您的项目 Docker 镜像 - 项目特定依赖;基于
base_builder或语言变体
运行器镜像(单独使用)
- base_runner - 执行测试工具;基于
base_clang - base_runner_debug - 带调试工具;基于
base_runner
高级用法
技巧
| 技巧 | 为何有帮助 |
|---|---|
| 不要手动复制源代码 | 项目 Dockerfile 可能已拉取最新版本 |
| 检查现有项目 | 浏览 oss-fuzz/projects 获取示例 |
| 将测试工具放在单独仓库 | 如 curl-fuzzer - 更清晰的组织 |
| 使用特定编译器版本 | 基础镜像提供一致的构建环境 |
| 在 Dockerfile 中安装依赖 | 可能需要 OSS-Fuzz 注册批准 |
关键性评分
OSS-Fuzz 使用 关键性评分 评估项目接受度。见此示例 了解评分方式。
评分较低的项目仍可添加到私有 OSS-Fuzz 实例。
托管自己的实例
由于 OSS-Fuzz 是开源的,您可以为以下目的托管自己的实例:
- 不符合公共 OSS-Fuzz 资格的私有项目
- 评分较低的项目
- 自定义模糊测试基础设施需求
反模式
| 反模式 | 问题 | 正确方法 |
|---|---|---|
| 在 build.sh 中手动拉取源代码 | 不使用最新版本 | 让 Dockerfile 处理 git clone |
| 将代码复制到 OSS-Fuzz 仓库 | 难以维护,违反分离原则 | 引用外部测试工具仓库 |
| 忽略基础镜像版本 | 构建不一致性 | 使用提供的基础镜像和编译器 |
| 跳过本地测试 | 浪费 CI 资源 | 在 PR 前本地使用 helper.py |
| 不检查构建状态 | 未注意的构建失败 | 定期监控构建状态页面 |
工具特定指南
libFuzzer
OSS-Fuzz 主要使用 libFuzzer 作为 C/C++ 项目的模糊测试引擎。
测试工具签名:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// 您的模糊测试逻辑
return 0;
}
在 build.sh 中构建:
$CXX $CXXFLAGS -std=c++11 -I. \
harness.cc -o $OUT/harness \
$LIB_FUZZING_ENGINE ./libproject.a
集成技巧:
- 使用 OSS-Fuzz 提供的
$LIB_FUZZING_ENGINE变量 -fsanitize=fuzzer自动处理- 尽可能链接静态库
AFL++
OSS-Fuzz 支持 AFL++ 作为替代模糊测试引擎。
在 project.yaml 中启用:
fuzzing_engines:
- afl
- libfuzzer
集成技巧:
- AFL++ 测试工具与 libFuzzer 测试工具一起工作
- 使用持久模式以获得更好性能
- OSS-Fuzz 处理引擎特定的编译标志
Atheris (Python)
适用于带 C 扩展的 Python 项目。
测试工具:
import atheris
import sys
import cbor2
@atheris.instrument_func
def TestOneInput(data):
fdp = atheris.FuzzedDataProvider(data)
try:
cbor2.loads(data)
except (cbor2.CBORDecodeError, ValueError):
pass
def main():
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
if __name__ == "__main__":
main()
在 build.sh 中构建:
pip3 install .
for fuzzer in $(find $SRC -name 'fuzz_*.py'); do
compile_python_fuzzer $fuzzer
done
集成技巧:
- 使用 OSS-Fuzz 提供的
compile_python_fuzzer帮助器 - 见持续模糊测试 Python C 扩展 博客文章
Rust 项目
在 project.yaml 中启用:
language: rust
fuzzing_engines:
- libfuzzer
sanitizers:
- address # Rust 仅支持 AddressSanitizer
在 build.sh 中构建:
cargo fuzz build -O --debug-assertions
cp fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_target_1 $OUT/
集成技巧:
- Rust 仅支持 libfuzzer 的 AddressSanitizer
- 本地开发使用 cargo-fuzz
- OSS-Fuzz 处理 Rust 特定的编译
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 构建失败,依赖缺失 | 依赖未在 Dockerfile 中 | 在 Dockerfile 中添加 apt-get install 或等效命令 |
| 测试工具立即崩溃 | 缺少输入验证 | 在测试工具中添加大小检查 |
| 覆盖率为 0% | 测试工具未达到目标代码 | 验证测试工具是否实际调用目标函数 |
| 构建超时 | 复杂构建过程 | 优化 build.sh,考虑并行构建 |
| 构建中的 Sanitizer 错误 | 不兼容的标志 | 使用 OSS-Fuzz 环境变量提供的标志 |
| 找不到源代码 | Dockerfile 中的工作目录错误 | 设置 WORKDIR 或使用绝对路径 |
相关技能
使用此技术的工具
| 技能 | 如何应用 |
|---|---|
| libfuzzer | OSS-Fuzz 使用的主要模糊测试引擎 |
| aflpp | OSS-Fuzz 支持的替代模糊测试引擎 |
| atheris | 用于在 OSS-Fuzz 中模糊测试 Python 项目 |
| cargo-fuzz | 用于在 OSS-Fuzz 中处理 Rust 项目 |
相关技术
| 技能 | 关系 |
|---|---|
| coverage-analysis | OSS-Fuzz 通过 helper.py 生成覆盖率报告 |
| address-sanitizer | OSS-Fuzz 项目的默认 sanitizer |
| fuzz-harness-writing | OSS-Fuzz 注册项目必需 |
| corpus-management | OSS-Fuzz 为注册项目维护语料库 |
资源
关键外部资源
OSS-Fuzz 官方文档 涵盖 OSS-Fuzz 平台注册、测试工具编写和故障排除的全面文档。
入门指南 将新项目注册到 OSS-Fuzz 的逐步过程,包括要求和批准流程。
cbor2 OSS-Fuzz 集成 PR 将带 C 扩展的 Python 项目注册到 OSS-Fuzz 的真实示例。显示:
- 初始提案和项目介绍
- 关键性评分评估
- 完整实现(project.yaml、Dockerfile、build.sh、测试工具)
模糊测试内省器案例研究 使用模糊测试内省器分析覆盖率和识别模糊测试阻塞器的示例和解释。
视频资源
查阅 OSS-Fuzz 文档,获取注册和测试工具开发的研讨会录音和教程。