- 网络安全
- 开发工具
- 质量保障
【免费下载链接】syzkaller
syzkaller is an unsupervised coverage-guided kernel fuzzer
本文基于 docs/translations/zh_CN/syz_testbed.md(英文原版见 docs/syz_testbed.md)及
tools/syz-testbed/下的源码编写,介绍如何使用 syzkaller 官方自带的 syz-testbed 工具,自动化完成"检出多个 syzkaller 版本 → 分别构建 → 并行运行 syz-manager → 周期收集并汇总统计数据"的完整对比实验,同时也讲解如何用它验证不同版本对历史 bug 的复现能力。
syz-testbed 是 syzkaller 仓库自带的实验编排工具,它把"性能对比评估"从手工劳动变成一条命令。无论你是想量化某个开发分支对 fuzzing 效率的影响,还是想评估新版本对已知崩溃日志的复现成功率,都可以用它搭建并自动运行整个实验流程。读完本文,你将掌握 syz-testbed 的完整配置语法、实例调度原理、统计文件布局、Web 图表用法,以及 syz-repro 复现测试的配置方法。
一、syz-testbed 是什么
syz-testbed(源码位于 tools/syz-testbed/)是一个用于简化对不同 syzkaller 版本(或配置)进行性能对比评估流程的工具。它会自动完成以下工作:
- 检出(checkout)syzkaller 仓库的指定分支;
- 构建(build)每个检出版本;
- 并行运行多个
syz-manager实例; - 收集并汇总这些实例的统计结果,输出为 CSV 表格与 bench 文件。
从 testbed.go 的头部注释可以看到其设计初衷:"自动检出、构建并搭建多个 syzkaller 实例,这在评估新改动对 syzkaller 整体性能的影响时非常有帮助"。也就是说,它的典型场景是把master与某个开发分支放在同一套环境里跑同样的时间,最后对比谁发现的 bug 更多、覆盖率更高、执行速度更快。
二、配置 syz-testbed
syz-testbed 需要一个 JSON 配置文件,通过命令行参数-config传入。以下是一个完整的示例(来自官方文档):
{ "workdir": "/tmp/syz-testbed-workdir/", "corpus": "/tmp/corpus.db", "target": "syz-manager", "max_instances": 5, "run_time": "24h", "http": "0.0.0.0:50000", "checkouts": [ { "name": "first", "repo": "https://github.com/google/syzkaller.git", }, { "name": "second", "repo": "https://github.com/google/syzkaller.git", "branch": "some-dev-branch", } ], "manager_config": { "target": "linux/amd64", "kernel_obj": "/tmp/linux-stable", "image": "/tmp/kernel-image/trixie.img", "sshkey": "/tmp/kernel-image/trixie.id_rsa", "procs": 8, "type": "qemu", "vm": { "count": 2, "kernel": "/tmp/linux-stable/arch/x86/boot/bzImage", "cpu": 2, "mem": 2048 } } }顶层配置项详解
对照 testbed.go 中的TestbedConfig结构体,各字段含义如下:
| 配置项 | JSON 类型 | 说明 | 默认值 |
|---|---|---|---|
name | string | testbed 的名称,会作为 syz-manager 实例名称的前缀 | "testbed" |
target | string | 要测试的应用,当前支持syz-manager与syz-repro两种 | "syz-manager" |
max_instances | int | 同时运行的实例总数上限 | 无(校验要求 ≥ 1) |
run_time | string | 每个实例的运行时长(Go duration 字符串,如"24h"、"1h30m") | "24h" |
http | string | Web 界面绑定的 IP 与端口,例如"0.0.0.0:50000" | 空(不启用) |
benchcmp | string | syz-benchcmp可执行文件路径,用于 Web 图表 | 自动从PATH查找 |
corpus | string | 初始 corpus 数据库文件路径,会复制到每个实例的 workdir | 空(不使用初始 corpus) |
workdir | string | 所有检出与运行产物所在的根目录 | 无(必填) |
repro_config | object | syz-repro 测试的配置(见下文第五节) | 默认crashes_per_bug = 1 |
manager_config | object | 基础 syz-manager 配置(与 syz-manager 的 config 字段一致) | 无 |
manager_mode | string | 传递给 syz-manager 的-mode参数 | "fuzzing" |
checkouts | array | 要对比的版本列表,至少一个 | 无 |
checkout 配置项
checkouts数组中的每个元素(对应 CheckoutConfig):
| 配置项 | 说明 |
|---|---|
name | 该版本在 testbed 中的唯一名称,会用于目录命名(如run-first-0)与统计列名 |
repo | syzkaller 仓库地址,例如https://github.com/google/syzkaller.git |
branch | 要检出的分支;不填时默认为master |
manager_config | (可选)该 checkout 专属的 manager 配置片段,会与顶层manager_config合并 |
默认值与配置校验(源码视角)
syz-testbed 在读取配置前会先填充一组默认值,见 testbed.go:target默认"syz-manager"、run_time默认 24 小时、manager_mode默认"fuzzing"、repro_config.crashes_per_bug默认 1,并会尝试通过exec.LookPath("syz-benchcmp")在系统PATH中自动查找syz-benchcmp。
加载配置后执行checkConfig校验(testbed.go),主要规则包括:
name必须匹配正则^[0-9a-z\-]{1,20}$;workdir不能为空,且会被自动转换为绝对路径并创建;- 若指定了
corpus,该文件必须存在; max_instances不能小于 1;- 若指定了
benchcmp,该路径必须真实存在; target必须是已注册的构造器之一(syz-manager/syz-repro);- 每个 checkout 的
repo与branch会经vcs.CheckRepoAddress/vcs.CheckBranch校验,branch为空时自动设为master; - checkout 的
name不能重复。
manager_config 的合并与实例化
顶层manager_config作为"基础配置",每个 checkout 的manager_config作为"补丁"与之合并(config.MergeJSONs),随后 syz-testbed 会把HTTP强制改为:0(避免多个实例端口冲突),见 MakeMgrConfig。
在每个实例启动前,还会对合并后的配置进一步打补丁(instance.go):自动填入name(即槽位名称)、workdir(实例专属目录)、syzkaller(指向该 checkout 的构建产物路径),并将最终配置写入实例目录下的manager.cfg文件。
三、工作流程:从检出到轮转运行
给定第二节的配置,syz-testbed 会执行以下操作(官方文档明确描述):
- 将
https://github.com/google/syzkaller.git的master分支检出到/tmp/syz-testbed-workdir/checkouts/first/并构建; - 将同一仓库的
some-dev-branch分支检出到/tmp/syz-testbed-workdir/checkouts/second/并构建; - 启动 3 个
first实例和 2 个second实例(因为max_instances = 5,实例按轮询方式分配); - 24 小时后(
run_time为24h),停止这 5 个实例; - 再创建 2 个
first实例和 3 个second实例; - 不断重复上述步骤,直到收到停止信号。
底层实现:Slot 与 Loop
从源码看,这个"创建 → 运行 → 归档 → 重来"的循环由两个核心函数实现(testbed.go):
Loop:为每个槽位(0 到max_instances-1)启动一个 goroutine,每个槽位固定占用一个实例名额;Slot:在槽位内不断调用Target.NewJob领取新任务——syz-manager目标按**轮询(round-robin)**策略在 checkout 之间分配实例(见 targets.go),syz-repro目标则优先挑选对某个 checkout 执行次数最少的崩溃日志。
每个syz-manager实例实际以如下命令行启动(instance.go):
<workdir>/checkouts/<name>/bin/syz-manager \ -config <实例目录>/manager.cfg \ -mode fuzzing \ -bench <实例目录>/bench.txtsyz-manager实例达到run_time后会被优雅停止:先发送 SIGINT(os.Interrupt),若 1 分钟内没有自行退出则强制 Kill(instance.go)。正常结束的实例会被归档为RunResult并加入该 checkout 的已完成列表(checkout.go),而异常退出的实例会直接终止整个实验(见下文)。
停止条件
该工具在收到 SIGINT(例如按 Ctrl+C)或 SIGTERM 信号后停止,停止时会关闭所有槽位并等待全部实例退出(testbed.go)。此外,如果任意一个实例由于错误退出,也会导致整个实验停止——这是有意设计的保守策略:一旦某个实例异常,说明环境或配置可能有问题,继续跑下去的数据也没有意义。
目录结构
运行期间,workdir下的目录结构如下(来自官方文档):
/tmp/syz-testbed-workdir/ └── checkouts ├── first │ ├── run-first-0 │ │ ├── log.txt │ │ ├── manager.cfg │ │ └── workdir │ ├── run-first-1 │ │ ├── log.txt │ │ ├── manager.cfg │ │ └── workdir │ └── run-first-4 │ ├── log.txt │ ├── manager.cfg │ └── workdir └── second ├── run-second-2 │ ├── log.txt │ ├── manager.cfg │ └── workdir └── run-second-3 ├── log.txt ├── manager.cfg └── workdir每个run-<checkout>-<编号>目录对应一个实例:log.txt是实例日志,manager.cfg是该实例最终的 syz-manager 配置,workdir是它的数据目录(corpus、crashes 等)。若配置了corpus,初始 corpus 会被复制到每个实例的workdir/corpus.db(instance.go)。此外每个实例目录还包含bench.txt,记录 syz-manager 按固定周期导出的统计快照(JSON 序列)。
四、Web 界面与 syz-benchcmp 图表
syz-testbed 自带一个简单的 Web 界面(源码见 html.go 与模板 templates/testbed.html),用于实时展示实验状态:
- 当前活动实例与已完成实例的数量(按 checkout 分组);
- 距实例停止的剩余时间;
- 从各 syz-manager 收集到的最新统计数据;
- 按 bug 标题、统计指标展示的各类表格。
要启用该界面,把http参数设置为 syz-testbed 要绑定的 IP 地址与端口,例如"http": "0.0.0.0:50000"。启动后即可在浏览器中访问,页面提供completed与all两个统计视图的切换(对应第四节的两种统计"视图"),以及 Statistics、Bugs、Bug Counts 等表格页签。
如果配置中的benchcmp参数指向syz-benchcmp可执行文件,Web 界面还能生成随时间或执行次数变化的各项参数曲线图。此时页面上的/graph路由会先调用syz-benchcmp(html.go),将其-all -over <x轴变量> -out <临时文件>参数与各 checkout 的平均 bench 文件组合执行,再把生成的图表返回给浏览器。
tools/syz-benchcmp/(benchcmp.go)本身是独立的 syz-manager 基准对比可视化工具,支持以下参数:
| 参数 | 说明 |
|---|---|
-all | 对所有统计变量绘制图形;不指定时仅绘制coverage、corpus、exec total、crash types四项 |
-over <变量> | 作为 X 轴的统计变量,默认fuzzing(可理解为以执行次数为横轴) |
-out <文件> | 将图形保存到文件而不是打开浏览器 |
-skip <秒数> | 跳过启动后前 N 秒的数据(默认 -30,即跳过前 20%) |
五、统计输出:两种视图与文件布局
syz-testbed 提供两种统计"视图"(对应 testbed.go 中的GetStatViews):
complete—— 仅包含已完成实例的数据(即运行满run_time的实例);all—— 还包含当前正在运行的实例的数据;来自已完成实例的统计会被"回退(对齐)"到与活动实例当前运行时长一致的时间点(stats.go 中的AlignedStatsTable按某个基准字段把各实例样本对齐)。
两种视图的统计每90 秒更新一次(testbed.go 中的周期 goroutine 调用SaveStats)。统计文件的整体布局如下:
$ tree -L 2 /tmp/syz-testbed-workdir/ /tmp/syz-testbed-workdir/ ├── stats_all │ ├── benches │ │ ├── avg_first.txt │ │ ├── avg_second.txt │ ├── bugs.csv │ ├── checkout_stats.csv │ └── instance_stats.csv ├── stats_completed │ ├── benches │ │ ├── avg_first.txt │ │ ├── avg_second.txt │ ├── bugs.csv │ ├── checkout_stats.csv │ └── instance_stats.csv └── testbed.csv各文件的含义与生成逻辑如下:
bugs.csv:包含所有运行实例发现的所有 bug(stats.go)。若某个 checkout 启动了多个实例(即count> 1),syz-testbed 会对它们发现的 bug 取并集(按 bug 标题去重,summarizeBugs逻辑见 stats.go),其目的是尽可能收集该 syzkaller 版本能够发现的全部 bug。Web 界面上对应的还有一张Bug Counts表,展示每个 bug 被多少实例发现及百分比。instance_stats.csv:保存各个 syz-manager 独立生成的统计(每行一个实例,按时间对齐后的最新样本)。checkout_stats.csv:将属于同一 checkout 的实例统计取平均(中位数)后保存(stats.go 的AvgStatRecords,按时间点逐个对齐并计算每个指标的中位数)。benches/avg_<checkout>.txt:把属于同一 checkout 的所有 syz-manager 的 bench 文件(参见 tools/syz-benchcmp)进行平均,保存为 JSON 行格式,可直接喂给syz-benchcmp绘制对比曲线。为了控制图表体积,长时间运行时采样点会被逐步抽样缩减到约 128~256 个数据点(stats.go 的SaveAvgBenchFile)。testbed.csv:testbed 级摘要表,包含每个 checkout 的 Running(运行中数量)、Completed(已完成数量)、Last started(最近一次启动距今时间)三列(testbed.go)。
此外,当target = "syz-repro"时,stats_*目录下会额外生成repro_success.csv、crepros_success.csv、repro_attempts.csv、repro_duration.csv等复现统计文件(见 targets.go)。
六、运行 syz-testbed
首先,检出 syzkaller 的最新版本:
$ git clone https://github.com/google/syzkaller.git然后构建 syz-testbed:
$ cd syzkaller/tools/syz-testbed/ $ go build编写并保存配置文件(例如保存为config.json),随后运行:
$ ./syz-testbed -config config.json运行时会看到每个 checkout 的检出、构建、实例启动日志。停止 syz-testbed 进程会同时停止所有 syzkaller 实例,因此可以放心地在实验中途按下 Ctrl+C 结束整个实验。
几点实操提醒:
- 需要提前准备好被测内核的
bzImage、rootfs 镜像与 ssh 私钥(对应manager_config中的kernel_obj、image、sshkey、vm.kernel等字段),可参考 docs/linux/setup.md 与 docs/setup.md 准备 QEMU 虚拟机环境; - 若想复用现有语料,可用
corpus字段指向一个已有的corpus.db; workdir下已存在的 checkout 目录会导致启动失败(checkout.go 会检查路径是否已存在),换新实验前请清空 workdir 或换一个新目录。
七、测试 syz-repro:评估 bug 复现能力
syz-testbed 也可用于测试 syzkaller 的bug 复现能力。为此,在配置文件中将target属性设置为syz-repro。
此时可以指定崩溃日志文件的来源,二选一:
input_logs:指向一个包含崩溃日志的文件夹——syz-testbed 会遍历该目录并把每个文件都作为一个输入;input_workdir:指向一个syzkaller 的 workdir——syz-testbed 会遍历其中发现的所有 bug,按规则挑选崩溃日志作为输入。
对应的配置段示例(官方文档):
"repro_config": { "input_workdir": "/tmp/some-syzkaller-workdir", "crashes_per_bug": 2, "skip_bugs": ["SYZFAIL", "no output", "corrupted", "lost connection"] },repro_config各字段含义(对应 ReproTestConfig):
| 配置项 | 说明 |
|---|---|
input_logs | 崩溃日志所在文件夹路径(与input_workdir互斥) |
input_workdir | syzkaller workdir 路径,从中读取所有 bug 及其崩溃日志 |
crashes_per_bug | 每个 bug 随机选取多少份崩溃日志进行处理,不能小于 1,默认 1 |
skip_bugs | 需要跳过的 bug 标题正则表达式列表(skip_bugs是正则,不只是字面匹配) |
以上述配置为例,syz-testbed 的处理流程为(targets.go):
- 遍历该 syzkaller workdir 发现的所有 bug(通过
collectBugs读取 crash 存储); - 跳过标题匹配
SYZFAIL、no output、corrupted或lost connection这些正则的 bug; - 对每个剩余 bug 随机选取 2 份崩溃日志(
crashes_per_bug = 2),且同一 bug 的日志不会被重复选取; - 检出并编译配置中指定的各 syzkaller 实例;
- 在每个被选中的崩溃日志上持续运行其
syz-repro,直到工具被停止。
每个syz-repro实例以如下方式启动(instance.go):
<workdir>/checkouts/<name>/bin/syz-repro \ -config <实例目录>/manager.cfg \ -output <实例目录>/repro.txt \ -crepro <实例目录>/crepro.txt \ -title <实例目录>/title.txt \ <实例目录>/execution-log.txt复现结果判定有一个值得注意的细节(instance.go):实例结束时会比对title.txt中解析出的 bug 标题与原始崩溃日志的标题,如果复现出的 bug 标题与原 bug 不一致,则该次复现视为失败(ReproFound与CReproFound均置为 false),避免"复现出了另一个 bug 却算作成功"的误判。若input_logs目录中某份日志解析不出崩溃报告,该日志也会被标记跳过(targets.go)。
syz-repro 模式下 Web 界面提供四类表格:Repros(各 bug 的复现成功率)、C Repros(已复现 bug 中能进一步生成 C 程序的比例)、All Repros(逐条列出每次复现尝试及其时长)、Duration(复现耗时分布),对应的 CSV 也会写入stats_*目录。
八、数据可信度与统计方法补充
syz-testbed 的统计表格并非简单的"最后一刻快照"对比,而是在源码层面做了较多严谨处理:
- 样本聚合:同一时刻各实例的同一指标会聚合为一个样本集,表格单元格存的是样本对象而非单个数值(table.go 的
ValueCell),展示时取中位数(sample.Median()); - 对齐回退:
all视图把已完成实例的统计回退到与运行中实例一致的时长(AlignedStatsTable),保证可比性; - 相对变化与显著性:Web 界面的统计表可指定
base_column基准列,把其他 checkout 的数值表示为相对基准列的百分比变化(PercentChange),并尝试用 Mann–Whitney U 检验计算 p 值(sample.UTest),见 table.go 的SetRelativeValues及其单元测试 table_test.go。
九、总结
syz-testbed 把"多版本 syzkaller 对比实验"标准化为一个配置文件加一条命令:syz-manager目标负责自动化对比各版本的 fuzzing 产出(bug 集合、统计指标、bench 曲线),syz-repro目标负责自动化对比各版本的 bug 复现能力。配合其 Web 界面与syz-benchcmp图表,你可以在一个页面里同时看到实验进度、统计表格和性能曲线。
如果你的日常工作涉及 syzkaller 的性能回归检测、开发分支效果评估或复现能力验证,直接使用 tools/syz-testbed/ 即可——它省去的正是最容易出错且最耗时的部分:手工检出、构建、编排实例与汇总结果。
- 网络安全
- 开发工具
- 质量保障
【免费下载链接】syzkaller
syzkaller is an unsupervised coverage-guided kernel fuzzer
相关推荐
丢一份硬件报告进去,还你一套黑苹果 OpenCore EFI:OpCore Simplify 上手指南
丢一份硬件报告进去,还你一套黑苹果 OpenCore EFI:OpCore Simplify 上手指南 在自组机器上跑 macOS(黑苹果),最耗时间的环节不是
开发工具CLIFFmpeg-Builds终极指南:不同版本功能与性能对比平台
FFmpeg Builds终极指南:不同版本功能与性能对比平台 FFmpeg Builds是一个专业的FFmpeg静态构建工具,提供Windows和Linux平
构建工具CI/CDDevOps开发工具syzkaller 在 NetBSD 上的部署与模糊测试实战:从源码构建到 syz-manager 运行
syzkaller 在 NetBSD 上的部署与模糊测试实战:从源码构建到 syz manager 运行 本文以 docs/netbsd/README.md h
网络安全开发工具质量保障
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考