- 网络安全
- 开发工具
- CI/CD
【免费下载链接】oss-fuzz
OSS-Fuzz - continuous fuzzing for open source software.
本文以 OSS-Fuzz 仓库的 infra/README.md 为骨架,深入剖析其两大核心基础设施——用于构建 fuzz target 的 Docker 镜像体系(
base-images)与 CI 构建脚本(ci),并逐条拆解自动化运维工具 helper.py 的 7 个常用子命令。读完本文,你将掌握 OSS-Fuzz 镜像的分层结构、每个子命令的参数与调用链、以及如何用一条命令完成从项目骨架生成到崩溃复现的完整本地开发闭环。
一、infra 目录定位:OSS-Fuzz 的“引擎舱”
OSS-Fuzz 是面向开源软件的持续模糊测试(continuous fuzzing)服务,其仓库中的infra/目录承载了支撑整个服务运转的本地与 CI 基础设施。从 infra/README.md 的目录划分看,它包含两大部分:
- 核心基础设施(Core infrastructure):
base-images——用于构建 fuzz target 的 Docker 镜像,以及与之对应的 Jenkins 流水线。仓库根目录下的 build_fuzzers.Dockerfile 与 run_fuzzers.Dockerfile 即是这条流水线在 CI 中使用的两个入口镜像定义。 - 持续集成基础设施(Continuous Integration infrastructure):
ci——在 CI 环境中构建项目的脚本,其行为由 ci/build_test.py 等测试用例进行验证。
除此之外,infra/目录还集中存放了 helper.py(用户日常最常打交道的自动化脚本)、constants.py(全局常量定义)、templates.py(项目骨架模板)、build_specified_commit.py、bisector.py、repo_manager.py 等配套工具。
二、base-images:分层镜像体系
base-images是整套基础设施的地基。其 README 只给出一行核心用法:在项目根目录运行infra/base-images/all.sh即可一次性构建全部基础设施镜像。展开来看,该目录按“语言适配层 + 运行时层”组织:
2.1 镜像构成与依赖链
从 all.sh 的构建顺序可以还原出镜像的依赖关系链:
docker build --pull -t gcr.io/oss-fuzz-base/base-image "$@" infra/base-images/base-image docker build -t gcr.io/oss-fuzz-base/base-clang "$@" infra/base-images/base-clang docker build -t gcr.io/oss-fuzz-base/base-builder "$@" infra/base-images/base-builder docker build -t gcr.io/oss-fuzz-base/base-builder-go "$@" infra/base-images/base-builder-go docker build -t gcr.io/oss-fuzz-base/base-builder-jvm "$@" infra/base-images/base-builder-jvm docker build -t gcr.io/oss-fuzz-base/base-builder-python "$@" infra/base-images/base-builder-python docker build -t gcr.io/oss-fuzz-base/base-builder-rust "$@" infra/base-images/base-builder-rust docker build -t gcr.io/oss-fuzz-base/base-builder-swift "$@" infra/base-images/base-builder-swift docker build -t gcr.io/oss-fuzz-base/base-runner "$@" infra/base-images/base-runner docker build -t gcr.io/oss-fuzz-base/base-runner-debug "$@" infra/base-images/base-runner-debug对应的镜像目录如下(全部位于 infra/base-images/ 下):
| 镜像 | 目录 | 作用 |
|---|---|---|
base-image | base-image/ | 基础系统镜像,一切镜像的起点 |
base-clang | base-clang/ | 提供 clang 工具链(含各类 sanitizer 支持) |
base-builder | base-builder/ | 通用构建器:编译 fuzz target 的默认环境(C/C++) |
base-builder-go | base-builder-go/ | Go 语言构建器 |
base-builder-javascript | base-builder-javascript/ | JavaScript 构建器 |
base-builder-jvm | base-builder-jvm/ | JVM(Java/Kotlin 等)构建器 |
base-builder-python | base-builder-python/ | Python 构建器 |
base-builder-rust | base-builder-rust/ | Rust 构建器 |
base-builder-swift | base-builder-swift/ | Swift 构建器 |
base-runner | base-runner/ | 运行时环境:负责执行 fuzz target、复现崩溃、统计覆盖率 |
base-runner-debug | base-runner-debug/ | 带调试工具的运行时镜像 |
base-builder-fuzzbench | base-builder-fuzzbench/ | 对接 FuzzBench 基准测试的构建器 |
整体分层可概括为:base-image → base-clang → base-builder(及各类语言变体)构成“构建端”,base-runner(及 debug 变体)构成“运行端”。项目级 Dockerfile 通常以gcr.io/oss-fuzz-base/base-builder或其语言变体作为FROM,因此构建出的项目镜像天然具备编译 fuzz target 的能力。
2.2 helper.py 中的语言映射
helper.py 中的LANGUAGE_TO_BASE_BUILDER_IMAGE常量明确定义了语言与基础构建器镜像的对应关系,这解释了为什么不同语言的项目会被自动分配到不同的镜像:
LANGUAGE_TO_BASE_BUILDER_IMAGE = { 'c': 'base-builder', 'c++': 'base-builder', 'go': 'base-builder-go', 'javascript': 'base-builder-javascript', 'jvm': 'base-builder-jvm', 'python': 'base-builder-python', 'rust': 'base-builder-rust', 'swift': 'base-builder-swift' }语言列表与 sanitizer、架构、引擎的可选范围在 constants.py 中统一定义:8 种语言、8 种 sanitizer(address、none、memory、undefined、thread、coverage、introspector、hwaddress)、3 种架构(i386、x86_64、aarch64)、6 种引擎(libfuzzer、afl、honggfuzz、centipede、none、wycheproof),默认值分别为 C++、address、x86_64、libfuzzer。
三、ci:CI 环境下的项目构建
ci目录承担了“在持续集成环境中构建项目”的职责。其核心脚本由ci/build.py提供(build_test.py 通过from ci import build引入并测试它),测试覆盖了should_build()的关键决策逻辑,例如:
- 项目
project.yaml中fuzzing_engines声明为['none']时,不应触发 coverage 构建; - 未显式声明
fuzzing_engines的项目,coverage 构建应正常进行; - 声明
libfuzzer引擎的项目同样应触发 coverage 构建。
从 build_test.py 的用例可以看出,CI 的构建决策完全由项目目录下的project.yaml内容驱动:language、fuzzing_engines、sanitizers字段共同决定了该项目的构建矩阵。这与 helper.py 读取project.yaml中language:字段选择基础镜像的逻辑一脉相承。
四、helper.py:本地开发的“瑞士军刀”
infra/README.md 用一张表概括了 helper.py 的全部能力,本文在此基础上逐条展开并补充参数细节。
前提说明:以下命令均在仓库根目录下执行,且要求本机已安装 Docker。helper.py 在启动时会
os.chdir到仓库根目录(见 helper.py),并自动创建build/目录用于存放各项目的输出物。
4.1 命令总览
| 命令 | 说明 |
|---|---|
generate | 为新项目生成骨架文件 |
build_image | 为指定项目构建 Docker 镜像 |
build_fuzzers | 为指定项目构建 fuzz target |
run_fuzzer | 在 Docker 容器中运行某个 fuzz target |
coverage | 运行 fuzz target 并生成代码覆盖率报告 |
reproduce | 运行测试用例以复现崩溃 |
shell | 在项目 Docker 镜像内启动一个 shell |
4.2 generate:新项目快速起步
python3 infra/helper.py generate <project_name> --language <language>该命令基于 templates.py 生成项目骨架文件。--language的可选值即LANGUAGE_TO_BASE_BUILDER_IMAGE的键集合(c、c++、go、javascript、jvm、python、rust、swift),默认c++。从 helper.py 可知,项目名必须匹配^[a-zA-Z0-9_-]+$且长度不超过 26 个字符。
4.3 build_image:构建项目镜像
python3 infra/helper.py build_image <project_name> [--pull|--no-pull] [--cache] [--architecture <arch>]--pull:拉取最新基础镜像;--no-pull:使用本地缓存的基础镜像;两者均不指定时交互式询问。--cache:构建时使用 Docker 缓存(显式调用build_image时默认不使用缓存,见 helper.py)。--architecture:可选i386/x86_64/aarch64,默认x86_64。选择aarch64时会在 x86_64 主机上借助 Docker Buildx + QEMU 模拟构建(--platform linux/arm64)。
镜像命名遵循gcr.io/oss-fuzz/<project_name>;若项目名恰好是基础镜像名,则会构建gcr.io/oss-fuzz-base/<name>(见 helper.py)。
4.4 build_fuzzers:编译 fuzz target(核心命令)
python3 infra/helper.py build_fuzzers <project_name> [--engine <engine>] [--sanitizer <sanitizer>] [--architecture <arch>] [-e VAR=value] [--clean|--no-clean] [source_path] [--mount_path <path>]这是本地开发中使用频率最高的命令,其内部流程(对应build_fuzzers_impl,helper.py)为:
- 先调用
build_image_impl构建(或复用)项目镜像; - 若指定
--clean,先清空build/out/<project>与build/work/<project>中的旧产物; - 以环境变量形式注入构建参数:
FUZZING_ENGINE、SANITIZER、ARCHITECTURE、PROJECT_NAME、FUZZING_LANGUAGE、HELPER=True,用户自定义变量通过-e追加; - 将宿主机
build/out/<project>:/out、build/work/<project>:/work挂载进容器并执行项目 Dockerfile 中的编译脚本。
关键参数说明:
--engine:可选libfuzzer/afl/honggfuzz/centipede/none/wycheproof,默认libfuzzer。注意 Centipede 引擎的特殊逻辑:它会额外在子目录__centipede_<sanitizer>中构建一份带 sanitizer 的二进制(见 helper.py)。--sanitizer:默认address(JavaScript 项目自动回退为none,见 helper.py)。source_path:传入本地源码目录后,helper.py 会解析项目 Dockerfile 中的WORKDIR指令(workdir_from_lines,helper.py),把本地源码以-v卷挂载覆盖容器内源码,实现“改代码不重建镜像”的迭代开发;--mount_path可显式指定挂载目标路径。- 构建产物落在
build/out/<project>/下,供后续run_fuzzer、check_build等命令使用。
4.5 run_fuzzer:运行 fuzz target
python3 infra/helper.py run_fuzzer <project_name> <fuzzer_name> [fuzzer_args...] [--engine <engine>] [--sanitizer <sanitizer>] [--corpus-dir <dir>] [-e VAR=value]在模拟的 fuzzing 环境中运行目标。--corpus-dir可指定语料库目录;fuzzer_args透传给 fuzzer 本体(例如-runs=100)。底层通过docker run拉起base-runner镜像并挂载build/out/<project>:/out执行。
4.6 coverage:生成代码覆盖率报告
python3 infra/helper.py coverage <project_name> [--no-corpus-download] [--no-serve] [--port <port>] [--fuzz-target <name>] [--corpus-dir <dir>] [--public] [extra_args...]在容器内运行 fuzz target 并基于 clang 的源码级覆盖率生成报告。默认行为是:
- 自动从 OSS-Fuzz 的 GCS 备份下载最新语料库(
--no-corpus-download可跳过,改用本地build/corpus/<project>/<fuzz_target>/); - 生成报告后启动本地 HTTP 服务(默认端口
8008,--no-serve可关闭,--port自定义端口); --fuzz-target限定只对单个目标生成覆盖率;--public改用wget从公共 HTTP 端点下载语料。
4.7 reproduce:复现崩溃
python3 infra/helper.py reproduce <project_name> <fuzzer_name> <testcase_path> [fuzzer_args...] [--valgrind] [-e VAR=value]将本地测试用例挂载进容器并运行对应 fuzz target,是分析崩溃报告的标准姿势。testcase_path会自动转换为绝对路径(helper.py)。--valgrind可切换到 valgrind 下运行以辅助定位内存类问题。
4.8 shell:进入容器调试
python3 infra/helper.py shell <project_name> [source_path] [--engine <engine>] [--sanitizer <sanitizer>]在项目 builder 镜像内启动/bin/bash,用于手动复现构建或运行问题;同样支持传入source_path挂载本地源码。
4.9 配套辅助命令
除上述 7 个常用命令外,get_parser() 还注册了若干辅助子命令,README 未列出但实际可用:
check_build <project> [fuzzer_name]:调用base-runner中的test_one.py/test_all.py校验 fuzz target 能否正常执行;download_corpora <project> [--fuzz-target ...] [--public]:从 GCS 备份批量下载语料(需gsutil,--public时改用wget);pull_images:拉取全部基础镜像;introspector <project>:对项目执行一次完整的 Fuzz Introspector 端到端分析(ASAN 构建 → 运行 → 覆盖率构建 → 提取覆盖率 → introspector 构建);run_clusterfuzzlite:在本地仓库上运行 ClusterFuzzLite(依赖 infra/cifuzz/ 模块与 run_fuzzers.Dockerfile)。
五、本地工作流串联:一个完整的调试循环
综合以上命令,一个典型的 OSS-Fuzz 项目本地开发循环如下:
# 1. 生成新项目骨架 python3 infra/helper.py generate my_project --language c++ # 2. 编辑 projects/my_project/ 下的 Dockerfile 与 build.sh 后,构建镜像 python3 infra/helper.py build_image my_project # 3. 编译 fuzz target(使用本地源码目录可跳过重建镜像) python3 infra/helper.py build_fuzzers my_project --sanitizer address # 4. 快速运行验证 python3 infra/helper.py run_fuzzer my_project my_fuzzer -runs=100 # 5. 复现崩溃 python3 infra/helper.py reproduce my_project my_fuzzer /path/to/crash.testcase # 6. 生成覆盖率报告 python3 infra/helper.py coverage my_project --fuzz-target my_fuzzer六、小结
OSS-Fuzz 的infra/目录是连接“上游开源项目”与“持续模糊测试服务”的桥梁:base-images 用分层镜像把编译与运行环境标准化,helper.py 则把这些镜像能力封装成一条条面向开发者的人性化命令。理解build_fuzzers背后“注入环境变量 + 挂载/out、/work”的容器执行模型,是深入使用 OSS-Fuzz 进行本地复现、覆盖率分析与新项目接入的关键一步。
进一步阅读可参考:infra/README.md(本文原始依据)、infra/constants.py(全部常量与可选值)、infra/base-images/all.sh(镜像构建脚本)、infra/ci/build_test.py(CI 决策逻辑测试)、以及 infra/helper_test.py(helper 行为测试)。
- 网络安全
- 开发工具
- CI/CD
【免费下载链接】oss-fuzz
OSS-Fuzz - continuous fuzzing for open source software.
相关推荐
OSS-Fuzz 基础设施解析:从 base-images 到 helper.py 的完整工作流指南
OSS Fuzz 基础设施解析:从 base images 到 helper.py 的完整工作流指南 本文基于 OSS Fuzz 仓库的 infra 目录,系统
测试应用安全质量保障OSS-Fuzz 基础设施镜像全量构建指南:从 base-image 到 base-runner 的 Docker 构建体系解析
OSS Fuzz 基础设施镜像全量构建指南:从 base image 到 base runner 的 Docker 构建体系解析 本文围绕 infra/base
网络安全开发工具CI/CDOSS-Fuzz base-builder 基础镜像完全指南:构建环境、命令接口与编译配置
OSS Fuzz base builder 基础镜像完全指南:构建环境、命令接口与编译配置 导读: base builder 是 OSS Fuzz 项目中面向
测试应用安全质量保障
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考