- 网络安全
- 开发工具
- 质量保障
【免费下载链接】syzkaller
syzkaller is an unsupervised coverage-guided kernel fuzzer
syz-aflow是 syzkaller 仓库中一个独立的命令行工具,用于在本地调试与测试由pkg/aflow框架定义的一整套“智能体工作流”(Agentic Flow)——包括自动生成内核补丁(patching)、复现崩溃(repro)、安全评估、基于文件行号生成 syzlang 种子程序(seed-gen-file-line)等。本文将以 tools/syz-aflow/README.md 为主体,结合源码完整讲解如何构建该工具、编写工作流输入 JSON、执行单任务与批量任务、配置 Gemini/Vertex 模型、可视化执行轨迹,以及其内部的执行与断点续跑机制,读完即可上手跑通一个真实工作流。
一、背景:从pkg/aflow框架到syz-aflow执行器
syz-aflow本身是一个极薄的 CLI 外壳,真正的工作流定义与执行引擎位于 pkg/aflow 包。按 pkg/aflow/GEMINI.md 的描述,aflow是一个“Agentic Flow”框架,用结构化的方式组合传统 Go 代码与LLM 智能体来完成高层的自动化内核任务,典型场景包括:
- Patching:自动生成并精修内核补丁;
- Moderation:评估 bug 报告的影响与可操作性;
- Reproduction:为已上报的崩溃寻找复现方式(syzkaller 与 C 复现器);
- Assessment:分析 KCSAN 报告与安全报告。
框架的核心概念包括:
| 概念 | 说明 |
|---|---|
| Flow | 一次高层工作流定义,声明输入、输出与动作序列,可用Flow.Consts注入常量 |
| Action | 工作流中的单个步骤;LLMAgent是驱动 Gemini 的智能体,FuncAction是包装成步骤的 Go 函数;Pipeline/DoWhile/If/ForEach提供编排 |
| Tool | 提供给 LLMAgent 的能力;FuncTool是暴露给 LLM 的 Go 函数,LLMTool是嵌套子智能体 |
| Context | 携带执行状态、管理持久化缓存、记录执行历史 |
| Trajectory | 由 span(Flow/Action/Agent/LLM/Tool)组成的分层执行日志,记录包括 LLM 思考与 token 消耗在内的完整执行路径 |
所有工作流通过aflow.Register注册到全局注册表 pkg/aflow/flow.go,并由 pkg/aflow/flow/flows.go 统一导入。当前仓库内可用的工作流类型(定义于 pkg/aflow/ai/ai.go)包括:patching、patch-iteration、moderation、assessment-kcsan、assessment-security、repro、repro-c、patch-triage、seed-gen、seed-gen-file-line、finding-triage。
syz-aflow的作用就是把这些注册好的工作流暴露给本地命令行:从 aflow.go 的main()可以看到,工具先解析命令行 flag,再在aflow.Flows注册表中按-workflow名字查找工作流,然后调用flow.Execute执行。不带参数运行时,它会打印全部可用工作流及其描述。
二、构建:一行命令产出可执行文件
在仓库根目录通过syz-env环境(syzkaller 官方提供的容器化开发环境入口脚本,见 tools/syz-env)执行:
./tools/syz-env go build ./tools/syz-aflow该命令会在仓库根目录生成syz-aflow二进制。后续所有运行命令都通过./tools/syz-env ./syz-aflow ...的方式调用,以保证依赖与编译环境一致。
三、基本执行与全部命令行参数
3.1 单任务运行
运行一个工作流需要三要素:工作流名称、输入 JSON 文件、工作目录:
./tools/syz-env ./syz-aflow -workflow <workflow_name> -input <input.json> -workdir <workdir>其中-workdir是工作流执行 checkout、内核构建等耗时操作的私有目录,建议在多次运行之间保留(pkg/aflow会在这里持久化 LLM 缓存,显著降低重复运行成本)。
3.2 全部 Flag 一览
README 列出了核心参数,结合 aflow.go 的 flag 定义,完整的参数表如下:
| Flag | 默认值 | 说明 |
|---|---|---|
-workflow | 空 | 要执行的工作流名称,必填 |
-input | 空 | 工作流输入 JSON 文件路径;若为目录则进入批量模式(目录下每个*.json是一个任务),必填 |
-parallel | 1 | 批量执行时的并发任务数(仅批量模式可用) |
-corpus | 空 | 批量模式下将所有执行过的程序保存到指定的corpus.db(仅批量模式可用) |
-workdir | 空 | 工作流执行 checkout、构建等的目录 |
-html | 空 | 将执行轨迹实时渲染到指定的本地 HTML 文件 |
-output | 空 | 将最终工作流输出保存到指定 JSON 文件 |
-model | 空 | 覆盖默认 LLM 模型(为空时使用各工作流的默认模型) |
-provider | gemini | LLM 提供商(gemini或vertex) |
-cache-size | 10GB | 最大缓存大小(支持100MB、5GB、1TB等格式) |
-token-limit | 0 | 整个工作流运行允许的最大 token 数(0 表示不限制) |
-debug | false | 开启 runner 调试日志 |
-download-bug | 空 | 按 bug 的 id 或 extid 从 dashboard 下载 bug 详情并写入-input文件 |
-auth | false | 下载 bug 时使用 gcloud auth token(需先执行gcloud auth application-default login) |
-no-safety-filters | false | 对 Gemini/Vertex 请求关闭安全过滤器(定义于 gemini.go) |
注意-cache-size的解析逻辑在 aflow.go:支持KB/MB/GB/TB后缀及裸数字,未知后缀会直接报错。缓存实际落在-workdir/cache目录下(见 runner.go),由pkg/aflow的 Cache 组件管理,用于避免重复的 LLM 调用。
四、工作流输入 JSON:无需 syz-manager 配置
与syz-manager需要标准 TOML 配置不同,syz-aflow只需要一个JSON 文件,其中放的是特定工作流自己的参数字段。如果工作流需要与 VM 交互(如复现崩溃、测试补丁),输入 JSON 中就需要包含描述环境的字段(如Image、VM 类型与配置、KernelSrc等),工作流代码会在运行时把这些零散参数程序化地拼装出 manager 配置,因此你不需要自己维护一份完整配置。
4.1 patching 工作流的示例输入
README 中给出的完整示例:
{ "Syzkaller": "/path/to/syzkaller", "Image": "/path/to/linux/image", "Type": "qemu", "VM": { "count": 1, "cpu": 2, "mem": 2048, "qemu_args": "-machine q35 -enable-kvm -smp 2,sockets=2,cores=1" }, "ReproSyz": "syz_open$dir(0x0, 0x1) ...", "KernelConfig": "@/path/to/linux.config" }对照 pkg/aflow/flow/patching/patching.go 中patching.Inputs结构体,该工作流实际支持的输入字段还包括AgentName、TargetOS、TargetArch、TargetVMArch、ReproOpts、ReproC、BaseRepository、BaseBranch、BaseCommit、StraceBin等。其中BaseCommit支持三种取值:精确 commit hash(本地测试)、"HEAD"(用当前分支 HEAD)、"RC"(用分支上最新的 release/release candidate tag),由baseCommitPicker动作处理。
patching工作流的完整流水线(同样见 patching.go)是:选择基准 commit → 生成简化 C 复现器 → 内核 checkout/构建 → 复现崩溃 → 建立代码搜索索引 →debugger智能体分析 bug →history-explorer智能体挖掘历史上下文 → 补丁生成循环 → 补丁精修循环 → 定位 Fixes 提交 → 获取维护者与近期提交 → 生成补丁描述。每一步都会产出结构化的中间值供后续步骤消费。
4.2 seed-gen-file-line 工作流的输入
批量模式专用的seed-gen-file-line工作流(定义于 pkg/aflow/flow/seedgen/seedgen_file_line.go)的输入字段为:FilePath(目标文件路径)、LineNumber(目标行号)、KernelRepo、KernelCommit、KernelConfig、Image、Type、VM、CorpusVMCount、Syzkaller、TargetOS、TargetArch、TargetVMArch、CorpusPath、Snapshot。其流水线先kernel.Checkout/kernel.Build构建内核,再由resolve-line-to-pc动作调用 coverage 后端把FilePath + LineNumber解析为一组候选 KCOV PC(ResolveLineToPC,见 seedgen_file_line.go),之后进入最多 5 轮(maxSeedGenAttempts = 5)的“生成器智能体 → 验证 PC → 反馈失败原因”循环,直到生成能命中目标 PC 的 syzlang 程序(通用 pipeline 见 pkg/aflow/flow/seedgen/seedgen.go)。
4.3@文件展开规则
输入 JSON 中任何字符串字段若以@开头(如"@/path/to/file"或"@./relative/path"),会被自动替换为对应文件的内容;相对路径基于-inputJSON 文件所在目录解析。字面量@可用@@转义(如"@@literal"会得到@literal)。
展开逻辑在 aflow.go 的expandFileInputs/expandValue中实现,且是递归的:不仅顶层字段,嵌套的 JSON 对象(如VM配置)和数组中的字符串同样会被展开。对应测试 aflow_test.go 覆盖了绝对路径、相对路径、@@转义、嵌套 map/数组以及“文件不存在时报错”等全部场景,可作为行为契约参考。利用该机制,KernelConfig可以直接写"@/path/to/linux.config",把整个内核配置内容注入工作流。
五、批量执行:目录输入 + 并发 + 断点续跑
当-input指向一个目录时,目录下每个*.json文件被视为一个独立任务,进入批量模式。README 中的示例:
./tools/syz-env ./syz-aflow -workflow seed-gen-file-line -input ./tasks -workdir ./workdir -parallel 45.1 结果目录与任务状态
每个任务的结果按状态分类保存到<workdir>/trajectories/<state>/下,状态共四类(定义于 batch.go):
success/:工作流成功(输出中Success == true);giveup/:工作流正常结束但放弃(未产出成功结果);error/:工作流或基础设施报错;in_progress/:运行中任务的临时.html轨迹与.log日志(进程被杀后会遗留于此,用于断点续跑识别)。
每个任务目录下保存同名<id>.json(含id、state、outputs、error、duration_ms字段的结果文件)、.html(轨迹)与.log(日志)。状态归类逻辑在classifyResultState(batch.go):有错误 →error;输出中Success为 true →success;否则 →giveup。
5.2 重启续跑与执行顺序
重启时,工具扫描trajectories/下各状态目录(batch.go):
- 已有
.json结果文件的任务视为已完成,直接跳过; - 只有
in_progress残留文件(.html/.log)的任务视为上次被中断,会优先重跑——因为这些任务还“热”在 LLM 缓存里,重跑成本最低; - 其余任务以随机顺序执行,使长时间批量运行的中间结果对整个任务集具有代表性,便于需要时提前终止。
5.3 批量模式的限制
批量执行当前仅支持seed-gen-file-line工作流,且不能与-html、-output组合使用(轨迹统一写入workdir/trajectories/),同时强制要求指定-workdir。这些约束由validateBatchMode强制校验(batch.go)。此外:单任务模式下使用-parallel或-corpus会直接报错,-parallel必须 ≥ 1。
5.4 多 API Key 分摊限流
为应对 Gemini 的速率限制,可将多个 API Key每行一个放入环境变量:
GOOGLE_API_KEY="$(cat keys.txt)" ./tools/syz-env ./syz-aflow -workflow seed-gen-file-line -input ./tasks -workdir ./workdir -parallel 4实现上,gemini.go 通过gemini.ParseAPIKeys解析GOOGLE_API_KEY(或GEMINI_API_KEY)中按行分隔的多个 key,每个任务固定使用其中一个 key。注意:只有 key 属于不同项目时才真正有助于规避速率限制;同一项目的多个 key 效果有限。
5.5 批量产出语料库:-corpus
配合-corpus <path>,批量运行期间执行的所有程序(不含 fault injection 等调用属性)会被实时保存到指定的corpus.db,可用于后续作为 fuzzing 种子。其实现见 corpus.go:每个结束的 span 若有 syzlang 程序 artifact,就按TargetOS/TargetArch解析目标、反序列化程序、清空调用属性(CallProps)与注释后,以哈希为 key 去重写入数据库。无法解析的程序会被跳过而不是拖垮整个批量任务,且程序在 span 结束时立即落盘,中断也不会丢失。
六、LLM Provider 配置:Gemini 与 Vertex
syz-aflow/gemini.go 通过RegisterProvider(注册机制见 registry.go)注册了两个 provider:
gemini(默认):需要设置环境变量GOOGLE_API_KEY或GEMINI_API_KEY,否则启动报错;vertex:需要设置GOOGLE_CLOUD_PROJECT(必填),GOOGLE_CLOUD_REGION可选、默认global,使用 Vertex AI 端点。
用-provider vertex切换,用-model覆盖默认模型。框架内部按任务复杂度分层使用模型(见 pkg/aflow/GEMINI.md):aflow.DeepReasoningModel(Pro 级)用于复杂因果推理、架构规划与安全影响分析;aflow.CoreModel(最新 Flash 级)是智能体执行、C 代码编写、评审循环的主力;aflow.LightweightModel(Flash)用于低开销的文本/标签抽取与上下文压缩。若不需要内容安全过滤,可加-no-safety-filters。
七、实时轨迹可视化:-html与-output
单任务运行时可实时观察工作流每一步的轨迹:
./tools/syz-env ./syz-aflow -workflow patching -input input.json -workdir ./workdir -html trajectory.html-html指定的 HTML 文件会在执行过程中被实时重写:每次产生或更新一个 span(Flow/Action/Agent/LLM/Tool 层级),runner.go 的回调就会用appendOrUpdateSpan按 span 序号增量更新内存列表,并调用aflowhtml.RenderReport渲染到该文件(runner.go)。用浏览器打开即可看到各步骤的图表与执行进度,便于调试。轨迹渲染模板位于 pkg/aflow/trajectory/html。
配合-output out.json,工作流结束时的最终输出(map[string]any形式)会以 JSON 写入指定文件,便于后续程序化消费。
八、从 syzbot dashboard 拉取真实 bug 作为输入
-download-bug <id|extid>可以从 dashboard 按 bug 的 id 或 extid 拉取真实崩溃详情,自动生成一份可直接作为-input使用的输入 JSON(aflow.go)。它会通过https://syzbot.org的/bug?extid=...&json=1接口(失败后回退id=)抓取数据,并组装出KernelRepo、KernelCommit、BugTitle、ReproSyz、ReproOpts、ReproC、KernelConfig、CrashReport等字段写入-input指定的文件。私有 bug 需要配合-auth(使用gcloud auth application-default login获取的凭据,见getAccessToken)。这正是把线上 syzbot 的 bug 直接喂给本地patching等工作流进行调试/复现的快捷通道。dashboard 侧的 JSON 导出接口在 pkg/aflow/docs/extract-workflows.md 有专门说明,tools/extract_workflows.sh脚本可批量导出历史工作流轨迹用于离线分析。
九、源码视角:执行机制与关键调用链
工作流的实际执行入口是 pkg/aflow/execute.go 的Flow.Execute:先校验输入类型(checkInputs)、合并Flow.Consts常量,初始化Context(携带工作目录、LLM provider、缓存、token 限制、事件回调),然后从Root动作开始顺序执行整个动作图,最终调用extractOutputs提取结构化输出。执行过程的关键机制包括:
- Trajectory span 事件:
startSpan/finishSpan会通过OnEvent回调把每个动作的开始/结束(含错误、结果与 token 消耗)推给 runner,这是-html可视化与批量模式结果分类的数据基础; - 持久化缓存:
Context.Cache/CacheObject基于 prompt、配置与历史做 LLM 响应级缓存,-cache-size限制其磁盘占用,workdir在重启间保留以复用缓存; - token 预算:
ConsumeTokens累计所有 LLM 调用消耗的 token,超过-token-limit时以FlowError中止; - VM 生命周期:
main()注册了osutil.HandleInterrupts(vm.Shutdown),收到 SIGINT/SIGTERM 时会优雅取消运行中的工作流并关闭其 VM;被中断的批量任务会保留in_progress文件以便下次优先恢复; - 错误语义:
FlowError表示工作流自身的预期失败(如内核构建失败),不应触发基础设施告警;模型超配额错误有专门的识别与重置时间计算逻辑(QuotaResetTime,按太平洋时区午夜 +5 分钟)。
十、常见问题与注意事项
- 找不到工作流:
-workflow名字必须在aflow.Flows注册表中存在,可用不带参数的运行方式列出全部可用工作流与描述;执行syz-aflow时若-workflow或-input为空也会打印 usage。 - provider 报错:
gemini缺GOOGLE_API_KEY/GEMINI_API_KEY,或vertex缺GOOGLE_CLOUD_PROJECT时,启动阶段即失败(见 gemini.go),请先配置环境变量。 - 批量模式限制:仅
seed-gen-file-line支持批量;批量中混用-html/-output、单任务中用-parallel/-corpus都会校验失败。 - 工作目录语义:
-workdir存放 checkout、构建产物、缓存与批量轨迹,应使用可写的独立目录并在重启间保留,以最大化缓存命中与断点续跑收益。 - 文件展开副作用:
@展开发生在输入加载阶段(loadTaskInputs),引用的文件必须存在,否则任务报错(批量模式下该任务标记为error)。
总的来说,syz-aflow让开发者无需搭建 syzbot 完整服务,即可在本地用一条命令驱动 syzkaller 最前沿的 LLM 智能体工作流,配合批量执行、断点续跑、轨迹可视化与语料导出,是调试内核崩溃复现、自动生成补丁与定向种子程序的实用入口。
- 网络安全
- 开发工具
- 质量保障
【免费下载链接】syzkaller
syzkaller is an unsupervised coverage-guided kernel fuzzer
相关推荐
丢一份硬件报告进去,还你一套黑苹果 OpenCore EFI:OpCore Simplify 上手指南
丢一份硬件报告进去,还你一套黑苹果 OpenCore EFI:OpCore Simplify 上手指南 在自组机器上跑 macOS(黑苹果),最耗时间的环节不是
开发工具CLIWoodpecker 本地流水线执行指南:用 woodpecker-cli exec 调试与回放工作流
Woodpecker 本地流水线执行指南:用 woodpecker cli exec 调试与回放工作流 woodpecker cli exec 是 Woodpe
CI/CDDevOpssyzkaller corpus.db 数据库操作指南:syz-db 工具全面解析
syzkaller corpus.db 数据库操作指南:syz db 工具全面解析 syz db 是 syzkaller 项目自带的 corpus.db 数据库
网络安全开发工具质量保障
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考