news 2026/9/23 13:55:42

OSS-Fuzz 基于 Agent 的构建脚本自动生成:用一条命令完成 OSS-Fuzz 项目接入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OSS-Fuzz 基于 Agent 的构建脚本自动生成:用一条命令完成 OSS-Fuzz 项目接入
  • 测试
  • 应用安全
  • 质量保障

【免费下载链接】oss-fuzz

OSS-Fuzz - continuous fuzzing for open source software.

项目地址:https://gitcode.com/gh_mirrors/os/oss-fuzz
点击查看免费下载

本篇技术指南聚焦 OSS-Fuzz 生态中一项关键的自动化能力:借助 LLM(大语言模型)驱动的 Agent 自动生成 OSS-Fuzz 所需的构建脚本,并结合 CLI 工具实现"输入一个 Git 仓库、输出一个完整 OSS-Fuzz 项目"的端到端工作流。读完本文,你将掌握 Agent 化构建生成的核心算法与四个关键函数、oss-fuzz-generator generate-full命令的完整使用方式,以及如何解读三个真实项目(libcypher-parser、Yams、Moment)生成的构建脚本,并理解该方案在 225 个仓库实测中的能力边界与已知局限。

背景:自动化 OSS-Fuzz 接入的两个核心难题

将任意开源项目接入 OSS-Fuzz 并非易事。OSS-Fuzz 要求每个项目提供特定格式的构建脚本,该脚本必须运行在 OSS-Fuzz 提供的构建环境(即 base-builder 镜像)中。由此,自动化 OSS-Fuzz 接入的问题天然被拆分成两个部分:

  1. 创建构建脚本:为目标项目及其相关的 fuzzing harness(模糊测试驱动)编写可在 OSS-Fuzz 构建环境中运行的脚本;
  2. 创建 fuzzing harness:编写真正调用目标项目 API 的模糊测试入口函数。

任何试图自动化 OSS-Fuzz 接入的解决方案,都必须同时解决上述两个问题,且要能覆盖风格迥异的开源项目。

这项工作的关键目标是支撑一个完整的自动化工作流:输入一个尚未接入 OSS-Fuzz 的项目仓库(如 GitHub 仓库),输出一个可用的 OSS-Fuzz 项目——包含可工作的构建脚本和一个或多个 fuzzing harness。更进一步,这个工作流必须易于访问和部署,让开源维护者能快速利用其能力。

作为参考,一个标准的 OSS-Fuzz 项目在本仓库中的目录结构通常由三个核心文件组成,这也是自动化流程需要产出的目标产物:

  • project.yaml:项目元数据(主页、主仓库地址、语言、fuzzing 引擎列表等),例如 projects/example/project.yaml;
  • Dockerfile:基于gcr.io/oss-fuzz-base/base-builder构建环境,负责拉取源码并拷贝构建脚本,例如 projects/example/Dockerfile;
  • build.sh:在$SRC$OUT等环境变量约定下编译 fuzz target 并拷贝到$OUT,例如 projects/example/build.sh。

在此之前,OSS-Fuzz-Gen 的精力主要集中在为已有 OSS-Fuzz 项目生成 fuzzing harness。此前一篇博客文章虽然记录了一种端到端的 OSS-Fuzz 接入方法,但其构建脚本生成基于模板策略,在应对多样化项目时存在明显局限。为此,本文介绍两项改进:

  1. 一种Agent 化的 LLM 构建脚本生成方法
  2. 一个易于访问和运行的 CLI 工具

总览与示例运行

方案的核心目标,是仅通过输入一个或多个 Git 仓库,就自动化地完整生成 OSS-Fuzz 项目,并输出一个或多个 OSS-Fuzz 接入集成。这些能力被打包为一个 Python 包并以 CLI 形式暴露,安装和运行都很简单。

以下示例为https://github.com/zserge/jsmn生成包含 fuzzing harness 的完整 OSS-Fuzz 项目:

# Prepare virtual environment python3.11 -m virtualenv .venv . .venv/bin/activate # Clone OSS-Fuzz-gen git clone https://github.com/google/oss-fuzz-gen cd oss-fuzz-gen # Install OSS-Fuzz-gen python3 -m pip install . # Generate fuzzers for https://github.com/zserge/jsmn echo "https://github.com/zserge/jsmn" > input.txt # Run the generation # Setup Vertex AI access: 参见 OSS-Fuzz-Gen 仓库 USAGE.md 中的 LLM access 章节 oss-fuzz-generator generate-full -i input.txt -m vertex_ai_gemini-2-flash-chat --agent -w work-1 # List the files of generated project $ ls final-oss-fuzz-projects/jsmn-agent/ build.sh Dockerfile empty-fuzzer.0.c empty-fuzzer.1.c project.yaml

整个流程的第一步是安装 Python 包。目前的做法是先克隆 OSS-Fuzz-Gen 仓库,再用python -m pip install .安装。安装后的包内置了一个oss-fuzz-generatorCLI 工具,对外暴露 OSS-Fuzz 项目生成能力。随后只需配置好 LLM 运行环境(如 Vertex AI),然后调用generate-full命令即可。该命令会一次性完成构建脚本生成、fuzzing harness 生成,并将所有成功的 fuzzing harness 合并进一个 OSS-Fuzz 项目。

具体来说,oss-fuzz-generator generate-full会针对input.txt中列出的每个仓库依次执行三个步骤:

  1. 生成一个能够编译该项目 fuzzers 的构建脚本
  2. 如果第 1 步成功,则为项目生成fuzzing harness
  3. 将成功的 fuzzing harness合并为一个完整的 OSS-Fuzz 项目。

本文后续将聚焦第 1 步——Agent 化的构建脚本生成。

从生成的产物可以看到,Agent 产出的项目结构与 OSS-Fuzz 仓库中真实项目的形态完全一致:build.shDockerfileproject.yaml加 fuzzing harness 源文件。你可以对照本仓库中的 projects/example 目录理解这些产物的标准形态,例如 projects/example/build.sh 展示了find批量拷贝 fuzzer 到$OUT的写法,而 projects/example/my-api-repo/do_stuff_fuzzer.cpp 展示了一个标准LLVMFuzzerTestOneInput入口的实现。

Agent 化构建脚本生成的算法原理

Agent 化构建脚本生成依赖三个核心组件:

  • 初始提示词(initial prompt):向 LLM 概述为任意仓库编写构建脚本的总体任务与约束;
  • Agent 执行器:负责与 LLM 通信,并在构建脚本将要运行的运行时环境中执行 LLM 提供的任意命令,使 LLM 能够探索运行时环境;
  • 构建与运行回灌流程:负责运行生成的构建脚本、执行生成的 fuzzer,用真实运行结果引导 LLM 的下一步输出。

Agent 化构建生成的总体算法如下:

initial_prompt = prepare_initial_prompt(target_repository) prompt = prepare_initial_prompt(target_repository) llm_client = llm_start_chat() while should_keep_going(): llm_response = llm_client.chat(prompt) res = parse_llm_response(llm_response) if res.is_commands() { output = execute_commands(res.get_commands()); } else if (res.has_build_script()) { output = build_and_run_fuzzer(res.get_build_script(), res.get_fuzz_harness()); if (output.has_successful_build_script()) { // Success in harness generation return output } } else { // Failure happened in parsing LLM output exit() } // Prepare a next prompt for the LLM to chat. prompt = prepare_next_prompt(output);

当算法执行到return output这一行时,即认为构建脚本生成成功。这一行只有在 LLM 创建的构建脚本附带一个 fuzz harness,并且该 harness 能够成功编译、链接到目标仓库代码时才会到达。

算法中有四个关键函数:

  • parse_llm_response:接收 LLM 返回的原始文本,将其转换为两类结果之一:(1) 需要在构建 fuzzer 的运行时环境中执行的一组命令;(2) 一个构建脚本及其携带的 fuzzing harness 源码。prepare_initial_prompt会事先指示 LLM 以某种标准格式输出(例如用 XML 标签包裹输出),以便可靠解析;
  • execute_commands:当parse_llm_response判定 LLM 返回的是命令列表时,此函数在构建脚本将要运行的运行时环境中执行这些命令。核心价值在于让 LLM 能够探索、理解并测试运行时环境;命令执行结果会返回给 LLM,由于 Agent 运行在循环中,LLM 可以持续下发命令、解读输出并据此行动;
  • build_and_run_fuzzer:当parse_llm_response判定 LLM 返回的是构建脚本(可能附带 fuzzing harness,也可能为空)时,此函数在运行时环境中构建这些产物。构建输出会被分析:若成功构建出 harness,则流程结束;若构建失败,则构建脚本的执行输出会被保存并最终回传给 LLM;
  • prepare_next_prompt:当本轮迭代未产生成功构建脚本时(可能是 LLM 返回了命令列表,也可能是构建脚本构建失败),该函数用execute_commandsbuild_and_run_fuzzer的输出构造下一轮提示词。提示词以轻量文本描述包裹运行输出,作为下一轮 Agent 迭代的输入传给llm_client.chat

算法成功时输出的构建脚本,将成为 OSS-Fuzz 项目的基础,随后即可复用 OSS-Fuzz-Gen 的核心能力为该项目生成 fuzzing harness。

从算法可以看出,Agent 的核心优势在于它拥有执行权限——可以在真实运行时环境中运行命令、安装依赖、修改源码,观察输出,然后不断迭代。这与纯模板化方案有本质区别:模板只能覆盖已知模式,而 Agent 可以针对每个项目的特殊情况"临场发挥"。

实测评估:225 个仓库、88 个有效集成

为验证该方案,研究团队在一批 C/C++ 编写的 GitHub 仓库上运行了这套流程,共分析225 个仓库,产出了88 个带有效构建脚本的 OSS-Fuzz 集成。随后,团队还使用 OSS-Fuzz-Gen 的 harness 生成能力在这些项目上运行,以确认构建脚本的有效性。

实测发现,该方案有许多长处:它克服了众多项目设置的障碍,能够创建模板化方案无法生成的构建脚本。下面通过三个真实样例来展示其能力边界。

案例一:libcypher-parser

目标仓库:https://github.com/cleishm/libcypher-parser

生成的构建脚本如下:

# Build script for libcypher-parser with fuzzing harness # Install necessary dependencies apt-get update && apt-get install -y make autoconf automake libtool curl # Install autoconf 2.71 cd /tmp curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.71.tar.gz tar -xzf autoconf-2.71.tar.gz cd autoconf-2.71 ./configure make make install # Install leg tool cd /tmp curl -L -O https://www.piumarta.com/software/peg/peg-0.1.18.tar.gz tar -xzf peg-0.1.18.tar.gz cd peg-0.1.18 make make install # Build libcypher-parser cd $SRC/libcypher-parser ./autogen.sh ./configure --enable-static --disable-shared make # Copy the static library to the output directory cp lib/src/.libs/libcypher-parser.a $OUT/ # Compile the fuzzing harness for fuzzer in $(find $SRC -maxdepth 1 -name 'empty-fuzzer.*'); do fuzzer_basename=$(basename $fuzzer .c) $CC $CFLAGS -I$SRC/libcypher-parser/lib/src $fuzzer -o $OUT/${fuzzer_basename} \ -L$OUT -lcypher-parser -Wl,--whole-archive $LIB_FUZZING_ENGINE -Wl,--no-whole-archive done

总体而言,这是一个相当复杂的构建:它安装了与运行时环境自带版本不同的 autoconf,还额外安装了一个名为 "peg" 的工具。为了识别出 "leg"/"peg" 工具的必要性,Agent 必须先尝试在缺少该工具的情况下构建项目,并解读构建输出——因为缺少 peg 时,配置 libcypher-parser 会报出如下错误:

... checking for leg... no configure: error: leg is required: please install http://piumarta.com/software/peg/ ERROR:__main__:Building fuzzers failed.

这正是execute_commands+ 循环迭代机制价值的直接体现:Agent 通过"构建 → 读报错 → 安装依赖 → 重新构建"的闭环,自行推断出了依赖关系。脚本还展示了两个值得注意的细节:

  • $CC$CFLAGS$LIB_FUZZING_ENGINE是 OSS-Fuzz 构建环境注入的关键变量,$LIB_FUZZING_ENGINE提供 fuzzing 引擎的链接库;
  • 脚本用for循环遍历$SRC下所有empty-fuzzer.*文件并逐一编译,从而支持任意数量的 fuzzing harness——这是后文将提到的设计约束之一。

案例二:Yams

目标仓库:https://github.com/jpsim/Yams

生成的构建脚本如下:

#!/bin/bash # Set up build environment cd $SRC/Yams/Sources/CYaml mkdir -p build cd build cmake .. -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX make # Compile the fuzzing harness $CC $CFLAGS -I$SRC/Yams/Sources/CYaml/include -I$SRC $SRC/empty-fuzzer.c -o $OUT/empty-fuzzer -L. -Wl,--whole-archive libCYaml.a -Wl,--no-whole-archive $LIB_FUZZING_ENGINE

这是一个简单的 cmake 构建脚本,但它在 cmake 命令中传入了-DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX,确保目标项目使用 OSS-Fuzz 运行时环境指定的编译器(即带 sanitizer 和覆盖率插桩的 clang)进行构建——这是 OSS-Fuzz 构建的关键要求,否则插桩不会生效。

有趣的是,这里 fuzz harness 的编译链接没有使用循环。这在原理上可行(项目能构建并链接一个 fuzzing harness),但存在局限:它无法构建和链接任意数量的 fuzzing harness。

案例三:Moment

目标仓库:https://github.com/kmussel/Moment

这是一个已停止维护约 10 年的库,构建这样一个老旧项目具有特殊挑战。生成的构建脚本如下:

#!/bin/bash # Install necessary tools apt-get update && apt-get install -y bison flex # Set source and output directories SRC_DIR="$SRC/Moment" OUT_DIR="$OUT" # Preprocess parseIt.ym to remove the Foundation import sed '/#import <Foundation\/Foundation.h>/d' $SRC_DIR/parseIt.ym > $SRC_DIR/parseIt_preprocessed.ym # Use bison to generate parseIt.c and y.tab.h bison -d -o $SRC_DIR/parseIt.c $SRC_DIR/parseIt_preprocessed.ym # Rename the generated header to y.tab.h mv $SRC_DIR/parseIt.h $SRC_DIR/y.tab.h # Use flex to generate tokeIt.c flex -o $SRC_DIR/tokeIt.c $SRC_DIR/tokeIt.l # Compile the source files into object files $CC $CFLAGS -c $SRC_DIR/TimeParser.c -o TimeParser.o $CC $CFLAGS -c $SRC_DIR/parseIt.c -o parseIt.o $CC $CFLAGS -I$SRC_DIR -c $SRC_DIR/tokeIt.c -o tokeIt.o # Archive the object files into a static library llvm-ar rcs libmoment.a TimeParser.o parseIt.o tokeIt.o # Compile the fuzzing harness and link with the static library $CC $CFLAGS -I$SRC_DIR $SRC/empty-fuzzer.c -o $OUT_DIR/empty-fuzzer -L. libmoment.a $LIB_FUZZING_ENGINE

与 libcypher-parser 类似,这个构建脚本令人印象深刻的地方在于其复杂性:下载并安装自定义软件包(bison、flex),并将这些工具作为构建过程的一部分使用。脚本还用sed修改了目标项目中的源文件(移除不适用于当前环境的#import <Foundation/Foundation.h>),并运行 bison 和 flex 生成编译所需的代码。此外,该项目自身没有任何构建系统文件(如Makefile),因此 Agent 退而求其次,直接逐个编译源文件并用llvm-ar打包静态库——这种"无构建系统也能接"的能力是模板方案很难覆盖的。

值得一提的是,OSS-Fuzz 运行环境中的$SRC$OUT$CC$CFLAGS$LIB_FUZZING_ENGINE等环境变量是整个构建脚本契约的核心,本仓库的 projects/example/build.sh 和 projects/example/Dockerfile 中可以看到这些约定的标准用法。新项目接入的完整流程与规范,可参考仓库根目录的 new_project_guide.md。

局限性与未来工作

在实测评估过程中,研究团队观察到若干局限和可改进之处。

构建脚本"成功"却绕过了目标源码

团队观察到若干案例:Agent 生成的构建脚本完全绕过了目标源码的编译,最终只是构建了一个空 fuzzing harness。问题在于,当前方案不会对生成的 harness 做后处理分析,以验证目标源码是否真正进入了最终二进制文件。这意味着当流程推进到 harness 生成阶段时,由于构建脚本没有涉及任何目标源码的编译,无法支撑后续工作流。虽然这种情况比较少见,但必须的解决方案是:对生成的构建脚本做更严格的后处理完整性校验,或者在端到端工作流中提供后续修正能力。

只能构建单个 fuzzing harness 的脚本

方案会指示 LLM 生成能够构建任意数量fuzzing harness 的构建脚本,以便复用该脚本编译 OSS-Fuzz-Gen 在 harness 生成阶段产出的所有 harness(很可能不止一个)。但实测发现,这一约束并不总是被遵守,部分构建脚本最终只能构建单个 fuzzing harness(例如构建指令中缺少循环)。此时用户需要手动修改构建脚本,使其能够构建任意数量的 harness,才能支撑最终需要两个及以上 harness 的 OSS-Fuzz 接入。

融入目标代码库的构建系统

当前方案产出的构建脚本,通常显式使用CC/CXX环境变量将 fuzzing harness 链接到脚本前面阶段构建的静态库上,即由"一组命令 + 一份 harness 源码"组成。另一种思路是把 fuzzer 的构建融入目标仓库自身的构建系统(如扩展其 Makefile),这样虽然没有实质性的功能差异,但对开发者更友好、更易维护。

失败生成的诊断与结论

当构建脚本生成失败时,目前没有任何关于失败原因的解释。一个自然的扩展方向是引入另一个 Agent 或类似机制,专门分析构建失败的原因。例如,区分失败原因是硬性原因(如目标代码在相关构建运行时中根本无法编译),还是 LLM 能力不足没能找到合适的方案。如果是硬性原因,反而是一个有价值的结论——可以明确告知用户目标项目不兼容 OSS-Fuzz(例如 Windows-only 项目)。

结论

本文介绍了 OSS-Fuzz-Gen 的一项新能力:通过Agent 化构建脚本生成,从零开始产出 OSS-Fuzz 项目集成。该能力以 CLI 工具形式提供,只需一条命令即可生成一个 OSS-Fuzz 项目。研究团队在 225 个 C/C++ 项目上进行了实测,得到 88 个有效的 OSS-Fuzz 构建脚本,并通过若干案例展示了能力亮点,同时识别了局限与未来方向。

整体来看,这套 Agent 化方案把"接入 OSS-Fuzz"从一件依赖人工经验的手工活,变成了可规模化、可复现的自动化流程。它与 OSS-Fuzz 仓库中的其他自动化探索一脉相承——例如引入 Agent 能力的博客文章展示了 CLI Agent 如何在 OSS-Fuzz 仓库中直接完成新项目接入、覆盖率改进、构建修复等任务;LLM 合成 harness 的博客文章则记录了更早期的端到端接入方案。构建脚本生成与 harness 生成这两条技术线互相配合,正逐步逼近"任何项目都能一键接入 OSS-Fuzz"的目标。

如果你希望在自己的项目上尝试这套工具,只需按文中示例安装 OSS-Fuzz-Gen、配置 LLM 访问,然后运行oss-fuzz-generator generate-full。如果遇到构建生成不工作的情况,建议将该信息反馈给 OSS-Fuzz-Gen 项目维护者,帮助持续改进这一自动化能力。

  • 测试
  • 应用安全
  • 质量保障

【免费下载链接】oss-fuzz

OSS-Fuzz - continuous fuzzing for open source software.

项目地址:https://gitcode.com/gh_mirrors/os/oss-fuzz
点击查看免费下载
上一篇:DeepChat Tape Trace Inspector:会话级只读执行检查器的完整实现方案
下一篇:CANN/HCOMM带通知非阻塞写操作

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 13:53:28

Visual C++物理模拟入门:水瓶晃动与动量守恒实战

简介&#xff1a;本资源是一个基于物理原理的轻量级水瓶动力学模拟程序&#xff0c;面向高校物理竞赛&#xff08;如CUPT中国大学物理学术竞赛&#xff09;备赛学生、C初学者及游戏开发入门者&#xff0c;旨在通过可视化编程实践深化对动量守恒、牛顿运动定律与流体行为建模的理…

作者头像 李华
网站建设 2026/9/23 13:52:13

隐式扩散重新模糊增强:低质图像鲁棒性提升实战

简介&#xff1a;本资源面向计算机相关专业的毕业设计、期末大作业与课程实训场景&#xff0c;提供一套基于隐式扩散的重新模糊增强方法完整Python实现&#xff0c;帮助学习者理解并复现图像去模糊与质量增强的深度学习流程。压缩包共96个文件、约60.2MB&#xff0c;以59个Pyth…

作者头像 李华
网站建设 2026/9/23 13:51:58

服务大面积超时!排查了3天,根因竟是一个“常见”的DNS配置

“服务怎么又超时了&#xff1f;用户全在投诉&#xff01;”某天上午&#xff0c;我们的核心数据推送服务&#xff08;负责处理来自立达标讯的实时政策数据流&#xff09;突然出现大面积请求超时&#xff0c;P99延迟从50ms飙升至5s以上&#xff0c;且持续了数小时没有恢复。更诡…

作者头像 李华
网站建设 2026/9/23 13:50:17

Pelican 草稿页面实战:用 Markdown 与 status 元数据掌控发布流程

【免费下载链接】pelican Static site generator that supports Markdown and reST syntax. Powered by Python. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/pe/pelican 点击查看 免费下载 本篇技术指南以 Pelican 测试套件中的 draft_page_markdown.md 为切入点&a…

作者头像 李华