做 Linux 内核 Bug 排查时,最让人头疼的往往不是“没有信息”,而是信息太散。
syzbot 每天都在发现和分类大量 Linux 内核崩溃、死锁和内存安全问题。它给出的材料其实很丰富:崩溃报告、控制台日志、内核配置、C/syz 重现代码、相关讨论链接。但这些材料大多还是原始数据。真正困难的部分,比如根因分析、本地复现、验证补丁、整理邮件、提交修复,仍然需要人一点点把线索串起来。
SyzForge 想解决的,就是这段从“看到一个 syzbot 报告”到“完成一次可追溯工程调查”之间的损耗。
它不是想替代内核开发者的判断,也不是简单把几个脚本包在一起,而是希望把 syzbot/syzkaller 相关的分析链路重新整理成一条清晰、可重复、可审计的流水线:让原始报告变成结构化证据,让复现环境变成确定性工作区,让补丁讨论和发送准备变成可追踪的工程步骤。
换句话说,SyzForge 是一个用于 Linux 内核 Bug 排查的开源多 MCP(Model Context Protocol)系统。它的目标很直接:把无尽的 syzbot 报活,变成可以被 Agent 和工程师共同推进的实际工作。
为什么需要 SyzForge
在真实的内核 Bug 调查里,一个 crash 从 syzbot 上出现,到我们真正理解它,通常要经过很多零散动作:
打开 syzbot 报告,确认目标内核和崩溃类型
下载 crash report、console log、kernel config 和 reproducer
准备本地源码和构建环境
在指定 commit 上编译内核
编译 C reproducer
启动 QEMU 并运行复现程序
对比 before/after 结果
阅读调用栈和相关源码
查找社区里是否已有讨论或补丁
编写、验证、整理并提交修复
这些事情单独看都不陌生,但连在一起,就很容易变成一场注意力消耗战。尤其是当多个 Bug 并行推进,或者一个问题隔了几天再回来继续看时,前后文很容易丢失。
SyzForge 的设计背景就是这个痛点:工具已经不少,但工作流仍然断裂。我们需要的不是更多孤立命令,而是一个能承接完整调查过程的系统。

架构:三个 MCP 服务器,一个目标

SyzForge 由三个独立的 MCP 服务器组成:
SyzLens:负责证据采集
KernelLab:负责内核构建与复现
KernelMail:负责社区讨论和补丁邮件工作流
它们共享一个本地数据工作空间,但职责边界非常清楚。每个服务器只做自己确定性的工程动作,不越界做主观判断。
这也是 SyzForge 里最重要的一条设计原则:
MCP 工具执行确定性的工程动作并返回可追溯的数据。Agent 负责主观推理。
也就是说,SyzLens 不判断根因,KernelLab 不决定该测试什么,KernelMail 不决定该发什么补丁。真正需要推理的部分,比如阅读崩溃栈、理解源码、评估补丁正确性、决定下一步调查方向,都由上层 Agent 完成。
这个边界让系统更稳,也更容易审计。你可以清楚看到每一步输入是什么、输出是什么、文件从哪里来、日志怎么产生、补丁为什么被提出。
SyzLens:系统的眼睛

SyzLens 是 SyzForge 的证据采集层。它负责连接 syzbot 仪表盘,获取 Bug 详情、崩溃报告、控制台日志、内核配置、重现代码以及社区讨论页面。
它不做根因推断,也不做优先级判断。它的职责很纯粹:把事实收集完整,并把这些事实缓存下来。
这件事看起来简单,但非常关键。因为一旦证据被稳定保存到本地,后续调查就不再依赖重复访问 syzbot,也不容易受到限流、页面变化或临时网络问题影响。同一个 Bug 可以被离线审查,也可以被打包带到另一台机器上继续分析。
SyzLens 的关键能力包括:
按目标、群组和关键词搜索 syzbot Bug,例如 upstream、android-5-15、linux-6.6,或者 open、fixed、invalid 等状态
下载指定 Bug 的崩溃报告、控制台日志、内核配置和 C/syz 重现代码
将工件存入稳定的 per-bug 目录
获取 Google Groups 和 lore.kernel.org 相关讨论页面
保存完整 HTML,方便后续追溯
生成工件清单,记录来源、时间戳和 SHA256 校验和
将 Bug 证据打包为 ZIP,方便离线传输
当用户要求 SyzForge 调查一个 syzbot Bug 时,SyzLens 通常是第一个被调用的组件。
KernelLab:把复现变成工程工作区

证据收集完之后,真正费力的部分才开始:准备内核、构建镜像、编译 reproducer、启动 QEMU、运行复现并保存日志。
KernelLab 负责这部分工作。
它会为每个 syzbot Bug 准备一个确定性的、自包含的内核复现工作区。这个工作区不是随手跑出来的一堆临时文件,而是一个可重复、可检查、可比较的 case。
KernelLab 做的事情包括:
在指定 commit 上检出 Linux 内核源码
应用 syzbot 提供的内核配置
构建 bzImage
编译 C 重现程序
生成 QEMU 启动脚本
启动 guest 环境并运行 reproducer
捕获串口控制台日志、QEMU 输出和 guest dmesg
支持 before/after 复现结果对比
每一项调查都会形成独立 case,默认放在类似下面的路径中:
data/workspaces/<target>/<case-id>/
case 中会包含源码树、构建输出、证据目录和复现结果。这样做的好处是,调查过程不会散落在机器的各个角落。过一段时间回来继续看,或者交给同事接手,都能找到完整上下文。
KernelLab 同样保持克制:它不会判断修复方案是否正确,也不会决定下一步该测什么。它只负责把复现和验证这部分工程动作做扎实。
KernelMail:把社区协作流程管起来

内核 Bug 的修复并不止于本地验证。真正要进入 Linux 内核社区,还需要处理邮件线程、补丁格式、收件人、主题、回复关系和发送计划。
KernelMail 负责这一段流程中可以确定化的部分。
它不会替 Agent 决定发什么补丁,也不会擅自发送邮件。它做的是记录线程元数据、管理本地草稿、生成 git send-email 计划,并确保这些动作都是可追踪、可检查的。
KernelMail 的关键能力包括:
在 case 工作区下记录社区讨论线程
将线程消息保存为可追溯的 RFC822 对象
创建带有正确 header、收件人、主题和正文的本地回复草稿
验证补丁文件后生成确定性的
git send-email计划将发送计划写入脚本,供本地执行和记录输出
读取 SyzLens 导入的讨论 HTML 或文本工件,并返回相关片段和链接
默认情况下,KernelMail 处在安全状态。所有真实邮件发送动作都需要明确确认。
这点很重要。因为在自动化和 Agent 参与越来越多的工作流里,边界必须清楚:工具可以准备,Agent 可以推理,人可以确认,系统不能越权。
Agent:负责把线索连起来
三个 MCP 服务器是执行层,真正理解“为什么这个 Bug 重要”“下一步该怎么做”的,是上层 Agent。
SyzForge 的工作流大致是这样:
证据分诊
从一个 syzbot Bug URL 开始,Agent 调用 SyzLens 获取所有证据,验证工件清单,然后导入 KernelLab。复现实验室
KernelLab 构建内核、编译 reproducer、启动 QEMU 并运行复现。Agent 读取 before/after 结果,决定是否继续。补丁分析与编写
Agent 阅读崩溃栈、控制台日志和相关源码,通过 KernelMail 检查社区是否已有补丁。如果已有方案,就评估它;如果没有,就尝试写一个最小修复。社区邮件准备
本地验证通过后,KernelMail 生成git send-email计划。Agent 撰写邮件正文,补齐Fixes:、Reported-by:、Closes:等标准标签,再由用户确认发送。
这里的分工是 SyzForge 的核心:MCP 工具处理确定性的工程动作,Agent 处理主观推理和代码理解。
我觉得这是一个很自然也很重要的边界。内核 Bug 调查不是简单的自动化任务,它需要经验、判断和取舍。SyzForge 不应该把这些判断藏进工具里,而应该把证据和过程摆清楚,让 Agent 和工程师能更好地判断。
为什么采用多 MCP
从实现角度看,SyzLens、KernelLab 和 KernelMail 完全可以被塞进一个大工具里。但 SyzForge 选择拆成三个 MCP 服务器,是有意为之。
首先是职责单一。SyzLens 专注证据采集,KernelLab 专注构建和复现,KernelMail 专注邮件工作流。每个组件都知道自己该做什么,也知道自己不该做什么。
其次是独立演进。SyzLens 可以继续增加新的证据源,而不用影响 KernelLab 的构建管线。KernelLab 可以支持新的 QEMU 配置或更多目标架构,而不用理解 syzbot 页面解析。KernelMail 可以改进邮件线程管理,而不碰复现逻辑。
第三是选择性部署。最小化使用时,你可以只运行 SyzLens,在本地工作站做离线 Bug 分诊。完整调查时,再接入 KernelLab 和 KernelMail。不同场景不需要背负同样的复杂度。
最后是安全性。MCP 边界天然限制了每个服务器的能力。KernelMail 不会因为 Agent 想发邮件就直接发出去;KernelLab 不会因为日志里有线索就推断根因;SyzLens 也不会把原始证据包装成未经验证的结论。
这种设计让系统更像一组可靠的工程模块,而不是一个什么都想管的大型黑盒。
一个具体例子
假设我们收到一个 syzbot Bug:
syzbot: null ptr deref in vmxnet3_dev_xmit
在 SyzForge 中,一次调查可能会这样展开:
Agent 指示 SyzLens 获取该 Bug,并下载全部相关工件。
SyzLens 拉取 Bug 详情、崩溃报告、控制台日志、内核配置、C reproducer 和社区讨论页面,缓存到本地
data/artifacts/,同时生成工件清单。Agent 将 SyzLens 清单导入 KernelLab,在 upstream 目标下创建一个 case。
KernelLab 从 Linux 仓库检出 syzbot 指定 commit,应用内核配置,构建 bzImage,编译 C reproducer,搭建 QEMU 环境,并运行复现程序。
Agent 读取复现日志,确认 crash 可以稳定触发。
Agent 继续阅读崩溃栈和相关源码,定位到
vmxnet3_dev_xmit中可能的空指针解引用路径。KernelMail 展示已有社区讨论,比如有人提出过修复方案,也有人指出了另一个可能方向。
Agent 对比这些讨论,决定写一个更小、更直接的补丁。
KernelLab 重新构建并运行 after 复现,确认问题不再触发。
KernelMail 生成
git send-email计划,Agent 准备带有Fixes:、Reported-by:、Closes:标签的邮件正文。用户确认后,再执行邮件发送流程。
这一整套过程里,每一步都有记录,每个工件都能追溯,每个判断也能回到原始证据中重新检查。
这就是 SyzForge 想带来的改变:不是让 Bug 分析变得“神奇”,而是让它变得更稳、更顺、更能复盘。
实例验证
目前此系统已经成功验证一笔patch,并推送patch被linux-usb的维护人员同意,下面是邮件回复:
On Fri, Aug 21, 2026 at 05:04:16PM +0800, Liu Qi wrote:
> ene_ub6250_probe() calls usb_stor_probe2(), which starts the usb-storage
> infrastructure and schedules the delayed scan work. The driver then
> calls ene_get_card_type(), which sends an ENE command through
> ene_send_scsi_cmd() and the usb-storage bulk transfer helpers.
>
> Both the delayed scan work, through usb_stor_Bulk_max_lun(), and
> ene_get_card_type() use us->current_urb. The scan work serializes this
> access with us->dev_mutex, but the ENE card-type probe does not. If the
> scan work runs while ene_get_card_type() is still using us->current_urb,
> usb_submit_urb() warns that the URB is already active.
>
> Serialize ene_get_card_type() with us->dev_mutex, matching the locking
> used by the scan path.
>
> Reported-by: syzbot+22ea20ef3afb6785b122@syzkaller.appspotmail.com
> Closes: [https://syzkaller.appspot.com/bug?extid=22ea20ef3afb6785b122](https://syzkaller.appspot.com/bug?extid=22ea20ef3afb6785b122)
> Assisted-by: Qwen:Qwen3.6
> Signed-off-by: Liu Qi <liuqi@longcheer.com>
> ---
Acked-by: Alan Stern <stern@rowland.harvard.edu>
> drivers/usb/storage/ene_ub6250.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
> index 2cffc559a..13b332d1d 100644
> --- a/drivers/usb/storage/ene_ub6250.c
> +++ b/drivers/usb/storage/ene_ub6250.c
> @@ -2358,7 +2358,9 @@ static int ene_ub6250_probe(struct usb_interface *intf,
> return result;
>
> /* probe card type */
> + mutex_lock(&us->dev_mutex);
> result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
> + mutex_unlock(&us->dev_mutex);
> if (result != USB_STOR_XFER_GOOD) {
> usb_stor_disconnect(intf);
> return USB_STOR_TRANSPORT_ERROR;
> --
> 2.43.0
整个流程没有我个人的参与,完全靠这套系统进行探索以及与社区交流 - -!
设计理念:清晰、可控、可生长
如果要用三个词概括 SyzForge 的设计理念,我会选:清晰、可控、可生长。
清晰,是因为内核问题本身已经足够复杂,工具不应该再增加理解成本。一个功能为什么存在,当前处在哪一步,下一步可以做什么,系统都应该尽量直接地呈现出来。
可控,是因为自动化不是为了替人做所有决定。SyzForge 更像是把重复、繁琐、容易出错的部分托住,让人的判断力用在真正重要的位置上。复现是否可靠,日志说明了什么,补丁是否合理,这些仍然需要 Agent 和工程师一起判断。
可生长,是因为这个项目不会停在第一版。真实的漏洞分析流程会不断变化,新的目标、新的架构、新的证据源、新的协作方式都会出现。SyzForge 的模块化设计,就是为了让它能随着真实使用继续扩展,而不是被早期形态锁死。
我希望未来的 SyzForge 不是一个“看起来很全”的平台,而是一个大家愿意一直用的工作台。它不抢人的判断力,也不制造额外复杂度,而是把任务从模糊推向清楚,把线索从零散推向成形。
结语
SyzForge 这个名字里的 Forge 有锻造的意思,我觉得它很贴合这个项目的气质。
它要锻造的不是某一个单点工具,而是一条从 syzbot 原始报告到本地复现、补丁验证、社区提交的工程链路。崩溃报告、日志、配置、源码、讨论、补丁,这些原本散落在不同地方的东西,会在 SyzForge 里被重新组织起来,成为一次可以继续推进、可以交接、可以复盘的调查。
对我们来说,SyzForge 不只是一个多 MCP 项目,也是一种工作方式上的尝试:把内核 Bug 排查中重复的部分沉淀下来,把经验留下来,把复杂流程摆放得更有秩序。
如果你也经常面对 syzbot/syzkaller 带来的 Linux 内核 Bug,或者对 Agent 参与真实工程调查的方式感兴趣,SyzForge 会是一个值得一看的项目。