ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OSS-Fuzz 基础设施镜像全量构建指南:从 base-image 到 base-runner 的 Docker 构建体系解析

OSS-Fuzz 基础设施镜像全量构建指南:从 base-image 到 base-runner 的 Docker 构建体系解析 OSS-Fuzz 基础设施镜像全量构建指南从 base-image 到 base-runner 的 Docker 构建体系解析【免费下载链接】oss-fuzzOSS-Fuzz - continuous fuzzing for open source software.项目地址: https://gitcode.com/gh_mirrors/oss/oss-fuzz本文围绕 infra/base-images/README.md 中唯一但核心的构建入口展开在项目根目录执行infra/base-images/all.sh即可一键构建 OSS-Fuzz 的全部基础设施镜像infra images。阅读本文后你将掌握 OSS-Fuzz 从基础镜像、编译器镜像、各语言 builder 镜像到 runner 镜像的完整构建顺序与依赖关系理解每个镜像在持续模糊测试流水线中的职责并能针对性地单独构建、传参或排查问题。一、构建入口all.sh 一键构建全部镜像原文档给出的操作方式非常简洁但它是整个 OSS-Fuzz 基础设施构建体系的唯一总入口# 从项目根目录执行 infra/base-images/all.sh打开 infra/base-images/all.sh 可以看到这个脚本按严格的依赖顺序依次执行了 9 条docker build命令构建结果全部推送到gcr.io/oss-fuzz-base/命名空间下构建顺序镜像 Tag构建上下文目录说明1gcr.io/oss-fuzz-base/base-imageinfra/base-images/base-image所有其他镜像的基石带--pull拉取最新基础层2gcr.io/oss-fuzz-base/base-clanginfra/base-images/base-clang内置 Clang/LLVM 工具链的编译器镜像3gcr.io/oss-fuzz-base/base-builderinfra/base-images/base-builder通用项目构建镜像预装 libFuzzer、AFL 等引擎4gcr.io/oss-fuzz-base/base-builder-goinfra/base-images/base-builder-goGo 语言变体 builder5gcr.io/oss-fuzz-base/base-builder-jvminfra/base-images/base-builder-jvmJVMJava语言变体 builder6gcr.io/oss-fuzz-base/base-builder-pythoninfra/base-images/base-builder-pythonPython 语言变体 builder7gcr.io/oss-fuzz-base/base-builder-rustinfra/base-images/base-builder-rustRust 语言变体 builder8gcr.io/oss-fuzz-base/base-builder-swiftinfra/base-images/base-builder-swiftSwift 语言变体 builder9gcr.io/oss-fuzz-base/base-runnerinfra/base-images/base-runner运行/复现/覆盖率镜像10gcr.io/oss-fuzz-base/base-runner-debuginfra/base-images/base-runner-debug带 valgrind、GDB 的调试版 runner脚本开头的#!/bin/bash -eux表明遇到任何一步失败-e都会立即终止并打印-x每一步执行的命令方便你观察构建进度与定位错误。需要留意脚本中的两个细节第一条命令带--pulldocker build --pull -t gcr.io/oss-fuzz-base/base-image ...表示 base-image 总是拉取最新的上游基础镜像其 Dockerfile 中的parent_image参数以保证安全更新其余镜像则依赖本地已构建的 base-image / base-clang / base-builder。$透传脚本把命令行参数原样透传给每条docker build。因此你可以这样给所有镜像追加构建参数例如指定平台架构# 为所有镜像显式指定构建平台x86_64 / aarch64 等 infra/base-images/all.sh --platform linux/amd64二、镜像依赖链谁构建在谁之上要正确使用 all.sh首先需要理解 10 个镜像之间严格的FROM继承关系这决定了脚本的构建顺序。从各镜像的 Dockerfile 中可以梳理出如下依赖链base-image (ubuntu:20.04) └── base-clang (预编译安装 LLVM/Clang、cmake、fuzz-introspector) └── base-builder (通用构建器sanitizer 标志、libFuzzer/AFL/honggfuzz/centipede、Python、Bazel) ├── base-builder-go (Go 工具链) ├── base-builder-jvm (JVM 工具链) ├── base-builder-python (Python 工具链) ├── base-builder-rust (Rust 工具链) └── base-builder-swift (Swift 工具链) base-image (复用同一基础层) ├── base-runner (复现、覆盖率、符号化工具) └── base-runner-debug (base-runner valgrind GDB)证据分别位于base-image/Dockerfile以ubuntu:20.04为底parent_image构建参数只安装最少的libc6-dev binutils libgcc-9-dev tzdata并统一声明OUT/out、SRC/src、WORK/work三个关键环境变量与目录把$PATH加上/out。base-runner 中运行的 fuzzer 也依赖这些约定。base-clang/DockerfileFROM gcr.io/oss-fuzz-base/base-image通过 checkout_build_install_llvm.sh 现场编译安装 LLVM设置CCclang、CXXclang与默认CFLAGS含-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION并针对旧代码把implicit-function-declaration等错误降级为警告。base-builder/DockerfileFROM gcr.io/oss-fuzz-base/base-clang在此基础上安装 Python 3.8.3、Bazelisk、AFL、honggfuzz、FuzzTest/centipede并把 compile、compile_libfuzzer、compile_afl 等脚本拷贝到/usr/local/bin/。base-builder-go/DockerfileFROM gcr.io/oss-fuzz-base/base-builder追加GOPATH/root/go并执行install_go.sh。base-runner/Dockerfile没有简单继承 base-builder而是使用多阶段构建——先从 base-image 临时构建rustfilt避免在最终镜像中保留 1GB 的 Rust 工具链再从 base-clang 阶段拷贝llvm-cov、llvm-profdata、llvm-symbolizer三个二进制最终镜像基于 base-image保证运行时镜像足够轻量。base-runner-debug/DockerfileFROM gcr.io/oss-fuzz-base/base-runner额外安装 valgrind、zip 并从源码编译 GDB 12.1用于崩溃调试场景。从源码结构看这种分层设计的核心价值是复用与隔离编译期重量级工具链集中在 builder 镜像中而生产运行期只依赖轻量的 runner 镜像。三、base-builder构建器的命令、环境变量与目录约定每个项目的 OSS-Fuzz 构建镜像都基于 base-builder。子目录 base-builder/README.md 明确了项目镜像对外暴露的接口。3.1 支持的命令任何项目镜像构建完成后都可以通过 docker 调用其内置命令docker run --rm -ti gcr.io/oss-fuzz/项目名 command arguments...命令说明compile默认构建全部 fuzz target/bin/bash进入 shell手动执行compile脚本启动构建这与 base-builder/Dockerfile 中的CMD [compile]相印证镜像默认入口就是 compile。3.2 构建配置环境变量同一个构建镜像可以通过环境变量产出不同配置的 fuzz 二进制环境变量默认值说明$SANITIZERaddress预设 sanitizer 配置address/memory/undefined/hwaddress/thread等$SANITIZER_FLAGS—直接指定 sanitizer 编译标志优先级高于$SANITIZER$COVERAGE_FLAGS—指定 fuzzer 反馈覆盖率用的编译标志$BUILD_UID—构建 fuzzers 时使用的用户 id一个典型用法示例原文档示例构建 sqlite3 的 UBSan 版本docker run --rm -ti -e SANITIZERundefined gcr.io/oss-fuzz/sqlite3从 base-builder/Dockerfile 可以看到这些配置在镜像内的完整预设。例如 address sanitizer 对应-fsanitizeaddress -fsanitize-address-use-after-scopeundefined 对应一组精确的-fsanitizearray-bounds,bool,builtin,enum,...列表并使用-fno-sanitize-recover还针对 aarch64 提供了去掉function的变体因为该选项在 aarch64 上不受支持。覆盖率构建SANITIZER_FLAGS_coverage为空字符串表示不加任何 sanitizerCOVERAGE_FLAGS默认是-fsanitizefuzzer-no-link而专门的覆盖率构建则使用-fprofile-instr-generate -fcoverage-mapping组合。3.3 镜像内目录布局位置环境变量用途/out/$OUT存放构建产物fuzz target、字典、options 文件、种子语料压缩包/src/$SRC检出项目源码/work/$WORK存放中间文件/usr/lib/libFuzzingEngine.a$LIB_FUZZING_ENGINE预构建的 fuzzing 引擎库如 libFuzzer所有 fuzz target 必须链接它目录在容器内是固定的但通过环境变量提供是为了让脚本可重定位。这一约定源自 base-image/Dockerfile 中mkdir -p $OUT $SRC $WORK chmod arwx的初始化。3.4 编译器标志约定子镜像构建 fuzzers 时必须使用以下环境变量提供的编译器与标志环境变量说明$CCC 编译器二进制$CXX、$CCCC 编译器二进制$CFLAGSC 编译标志$CXXFLAGSC 编译标志这些变量在 base-clang/Dockerfile 中完成初始化CCclang、CXXclangCFLAGS默认-O1 -fno-omit-frame-pointer -gline-tables-only ...C 额外追加-stdliblibc。绝大多数正规构建脚本会自动识别这些变量若不识别则需要手动把它们传给构建工具。3.5 子镜像项目镜像必须提供的文件源码子镜像需要把编译 fuzz targets 所需的全部源码检出到$SRC。运行时也可以用挂载方式覆盖本地检出docker run -v $HOME/my_project:/src/my_project ...。$SRC/build.sh构建脚本负责编译项目与 fuzz targets。这就是每个项目目录如 projects/sqlite3中 build.sh 的接口约定来源。四、base-runner运行、复现与覆盖率构建完镜像后base-runner 提供生产环境的执行能力。其用法为docker run -ti gcr.io/oss-fuzz-base/base-runner command argsbase-runner/README.md 列出四条核心命令命令说明reproduce fuzzer_name fuzzer_options构建全部 fuzz targets并用/testcase与给定参数运行指定 fuzzerrun_fuzzer fuzzer_name fuzzer_options运行指定 fuzzer自动合并.options文件中的参数test_all.py把/out下每个二进制当作 fuzzer 各运行一段时间验证其可用性coverage fuzzer_name为指定 fuzzer 生成覆盖率报告4.1 复现崩溃的两个典型用法使用最新 OSS-Fuzz 构建产物复现docker run --rm -ti -v testcase_path:/testcase \ gcr.io/oss-fuzz/PROJECT_NAME reproduce fuzzer_name使用本地源码检出复现挂载源码目录覆盖镜像内检出docker run --rm -ti \ -v source_path:/src/PROJECT_NAME \ -v testcase_path:/testcase \ gcr.io/oss-fuzz/PROJECT_NAME reproduce fuzzer_name对应实现位于 base-runner/reproduce、base-runner/run_fuzzer 与 base-runner/test_all.py仓库中还带有对应的测试 test_all_test.py。4.2 runner 镜像内的运行时默认值base-runner/Dockerfile 中预设了与 ClusterFuzz 侧保持一致的关键运行时选项理解这些有助于排查复现结果不一致的问题FUZZER_ARGS-rss_limit_mb2560 -timeout25默认内存上限 2560MB、单次执行超时 25 秒ASAN_OPTIONS包含detect_leaks1、detect_stack_use_after_return1、symbolize1、strip_path_prefix/workspace/等一整套与 ClusterFuzz 对齐的配置MSAN_OPTIONS/UBSAN_OPTIONS同样带有symbolize1与dedup_token_length3AFL_FUZZER_ARGS-m noneAFL 模式下不限制内存。五、独立构建单个镜像的三种方式all.sh面向全量构建但日常开发更常见的需求是单独构建某一个镜像仓库给出了灵活的实现路径直接对子目录执行 docker build使用 all.sh 中对应的 tag 与目录docker build -t gcr.io/oss-fuzz-base/base-builder infra/base-images/base-builder利用 all.sh 的参数透传构建全部但附加平台等参数见上文。从单个子镜像的 Dockerfile 追溯其全部依赖由于 base-builder、base-runner 等都FROM上游镜像本地若缺少这些上游 tagdocker build 会失败——此时可先执行 all.sh 中的前几步或单独构建对应依赖镜像这正是 all.sh 按依赖顺序排列各条命令的原因。六、构建前的环境要求与注意事项本流程基于 Docker请确保本地 Docker 守护进程可用且有足够磁盘空间base-clang 需现场编译 LLVMbase-runner 亦需多阶段构建磁盘占用通常达数 GB。all.sh使用bash -eux模式任一步docker build失败即中止失败时可先确认对应子目录 Dockerfile 中的依赖镜像 tag 是否已在本机存在。各镜像的 tag 固定为gcr.io/oss-fuzz-base/*如果构建机无法访问gcr.io镜像仓库或目标 registry 不同需要自行替换 all.sh 中的 tag。除文档外仓库还在 infra/base-images/base-builder-fuzzbench/ 提供了面向 FuzzBench 的扩展 builder 变体其包含fuzzbench_build、fuzzbench_measure、fuzzbench_run_fuzzer等独立脚本可在理解基础体系后进一步探索。七、小结从一条命令读懂整套构建体系回到起点infra/base-images/all.sh虽然只有十行 docker build 命令但它背后是 OSS-Fuzz 精心设计的镜像分层体系base-image 提供统一目录与基础运行时base-clang 提供模糊测试专用的编译器工具链base-builder 及各语言变体承载构建 fuzzers的全部能力base-runner 系列则负责运行、复现、覆盖率与调试。掌握这一链条无论是要为本仓库新增语言支持、调试构建失败还是复用这套基础设施搭建自己的模糊测试流水线都有了清晰的着手点。【免费下载链接】oss-fuzzOSS-Fuzz - continuous fuzzing for open source software.项目地址: https://gitcode.com/gh_mirrors/oss/oss-fuzz创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表