【论文阅读】Locus: Agentic Predicate Synthesis for Directed Fuzzing
- 1【论文阅读】Dytan: A Generic Dynamic Taint Analysis Framework
- 2【论文阅读】All You Ever Wanted to Know About Dynamic Taint Analysis and Forward Symbolic Execution
- 3【论文阅读】Augur: Dynamic Taint Analysis for Asynchronous JavaScript
- 4【论文阅读】VIPER-MCP: Detecting and Exploiting Vulnerabilities in Model Context Protocol Servers
- 5【论文阅读】Exploring Static Taint Analysis in LLMs: A Dynamic Benchmarking Framework for Measurement and Enhancement
- 6【论文阅读】Locus: Agentic Predicate Synthesis for Directed Fuzzing本文
- 7【论文阅读】Make Agent Defeat Agent: Automatic Detection of Taint-Style Vulnerabilities in LLM-based Agents
- 8【论文阅读】Sleuth: A Switchable Dual-Mode Fuzzer to Investigate Bug Impacts Following a Single PoC
阅读《Locus: Agentic Predicate Synthesis for Directed Fuzzing》,中文译名为《LOCUS:面向定向模糊测试的自主谓词合成》。
论文发表于 ICSE 2026,提出了一个结合 LLM Agent 与符号执行的定向模糊测试(Directed Grey-box Fuzzing, DGF)框架 Locus。
论文的核心思想是利用 LLM Agent 在目标程序任意位置合成捕获执行进度的中间谓词(Progress-capturing Predicates),以此作为通往目标状态(Canary)的里程碑。
解决的核心痛点:传统定向 Fuzzing 依赖的控制流图(CFG)距离反馈过于稀疏,且人工规则难以通用;而现有 LLM 辅助 Fuzzing 多局限于在输入层(Harness)生成约束,面临超长上下文推理能力不足、容易产生幻觉且难以验证的问题。
- 技术创新路径:
- 任意位置谓词合成:将约束生成从输入端解放至程序任意中间节点。
- 模糊测试容许性(Fuzzing Admissibility):严格保证生成的中间谓词是目标 Canary 状态的弛豫条件(Relaxation),既能拦截无法到达目标状态的无效路径(早期终止),又不会产生误杀(False Rejections)。
- Agentic 迭代与双重验证:结合程序分析工具(调用图、数据流图)进行多轮谓词位置上提(靠近程序入口),并通过编译器检查语法、利用 KLEE 符号执行验证语义弛豫的严格性。
论文叙述结构分析:论文遵循标准的软件工程与系统安全顶会逻辑,整体采用”痛点对齐 → 动机示例 → 理论形式化 → 智能体方法论 → 实验验证”的递进式结构。
在 Magma 基准测试上评估 Locus,涵盖八个广泛使用的库和十种漏洞类型,覆盖了八种最先进的模糊器,包括定向和非定向的。Locus 在定向模糊器上平均实现了 70.3× 的加速,在集成到最先进的定向模糊器 SelectFuzz 时,最高可达 214.2× 的加速。对于覆盖率引导的模糊器,Locus 平均加速了 13×,包括像 AFL++ 这样经过广泛优化的模糊器的 15.3× 加速。迄今为止,Locus 发现了九个之前未修复的漏洞。
概述
Canary 金丝雀探针
Canary 是指在代码中显式插入的、用于检查是否触发了特定漏洞或到达了特定状态的谓词/断言语句(Assertion)。当相应的 canary 条件满足时,认为这些状态已被达到。
用于有向模糊测试的 canary 来源于各种途径,包括静态分析警报、手动识别的漏洞位置或运行时清理器。例如,地址清理器也可以近似地视为检查内存安全违规的 canary,例如插入 canary(index > maxbound) 来检测越界访问。
现有定向模糊测试的三种通用策略
现有定向模糊测试(Directed Grey-box Fuzzing, DGF)在指导测试用例到达金丝雀(Canary,即目标漏洞状态)时,主要采用以下三种通用策略:
1. 距离引导调度策略(Distance-guided scheduling)
- 原理:基于控制流图(Control Flow Graph, CFG),近似计算当前测试种子(Seeds)覆盖的代码区域到目标金丝雀(Canary)节点之间的”图距离”。
- 执行方式:
- 种子优先级调度:优先给那些能进一步缩短到 Canary 距离的种子分配更多变异资源和执行时间(如 AFLGo, Hawkeye)。
- 早期终止(Early Termination):对于分析后发现极不可能到达 Canary 的执行路径,直接截断或提前终止执行,避免浪费 CPU 时间(如 Beacon, SelectFuzz)。
2. 领域特化的进度/状态抽象表示(Specialized progress-capturing state representations)
- 原理:针对特定类型的软件漏洞,人工设计领域专用的状态 abstraction,来追踪程序是否正在沿着触发漏洞所需的前置状态链条推进。
- 例子:例如对于”释放后重用”(Use-After-Free, UAF)漏洞,专门设计状态机来监控从”内存分配(Allocate)→ 内存释放(Free)→ 重新指针解引用(Use)“的特定时序和数据流事件(如 CAFL)。
3. 基于 LLM 的测试驱动/输入生成器合成(LLM-assisted harness generation)
- 原理:利用大语言模型(LLM)理解代码和语法规范的能力,直接生成具备语法感知的输入生成器(Fuzzing Harness)。
- 执行方式:尝试将到达 Canary 所需的各种前置条件,直接转化为在输入层(Input Level)的语法约束(如 InputBlaster, HGFuzzer),从一开始就限定 Fuzzer 只生成符合特定结构的输入,从而缩小搜索空间。
论文在提出这三种通用策略的同时,也指出了它们各自的瓶颈,从而引出了 Locus 的核心思想:
| 通用策略 | 存在的主要缺陷/局限性 | Locus 的改进思路 |
|---|---|---|
| 距离引导调度 | 反馈过于稀疏或间接。当存在大量平行分支或长前置条件时,不同分支在 CFG 上到 Canary 的距离可能完全相同,导致 Fuzzer 盲目探索。 | 合成显式的中间谓词作为”语义里程碑”,为 Fuzzer 提供更细粒度的反馈。 |
| 特化状态表示 | 极度依赖安全专家的手工规则设计,仅能针对特定漏洞类型(如 UAF),无法通用到各种复杂的业务逻辑中。 | 利用 LLM Agent 自动分析全栈代码,自动推导并表达通用语义约束。 |
| LLM Harness 生成 | 很多到达 Canary 的关键中间状态在程序执行中途才涌现(例如 PNG 的解析循环),无法直接在入口处的输入层进行表示和校验;且让 LLM 一路从目标逆向推导回输入端上下文过长、极易产生幻觉。 | 将约束生成从”输入入口”解放至程序任意中间节点,并结合符号执行严格校验语义弛豫(避免误杀)。 |
动机示例 Motivating Example
论文使用 libpng(一个广泛用于解析 PNG 文件的 C 库)中的一个真实漏洞 CVE-2013-6954,来演示 Locus 如何补充现有方法。
案例背景:CVE-2013-6954 (libpng)
- 漏洞原理:
libpng是 C 语言中广泛使用的 PNG 图像解析库。该漏洞属于堆缓冲区溢出(Buffer Overflow),触发条件是 PNG 文件包含一个调色板数据块(PLTE块),且调色板的尺寸超过了预设的最大限制(即 Canary 条件:num > PNG_MAX_PALETTE_LENGTH)。 - 程序结构:PNG 文件由一系列结构化的数据块(Chunks)组成。
libpng的核心解析逻辑是在主函数png_read_info中运行一个循环,轮询处理各个数据块(如文件头IHDR、调色板PLTE、图像数据IDAT等)。
参见下图:

作者分析了现有的定向模糊测试策略遇到此类漏洞时的局限性:
① 传统”距离引导调度”的困境(图 1a)
- 控制流图(CFG)等距盲区:在
png_read_info的解析循环中,处理不同数据块的分支(PLTE、color等)在语法结构上是并行的。 - 问题:如图 1a 所示,灰色高亮节点在 CFG 上到目标 Canary 节点(黄色)的距离完全相同。但事实上,只有经过
PLTE分支(绿色箭头路径)才能触发漏洞。传统 Fuzzer(如 AFLGo)无法识别哪个并行分支才是关键路径,只能做保守的粗粒度剪枝(虚线箭头),导致在无关路径(黑色实线)上浪费大量的测试时间。
② 基于”LLM 生成 Harness / 输入生成器”的困境(图 1b)
- 输入层约束表达力不足:PNG 文件的压缩数据(如
IDAT块)结构复杂,LLM 很难直接在入口层(Harness 层面)构造精准的输入语法约束。LLM 生成的代码往往只能做到通用校验(如png_sig_cmp仅检查是否为合法 PNG)。 - 容易误导与产生幻觉:LLM 生成的 Harness 可能强行将输入限定在无关类型上(如生成
png_write_frame_head约束,把测试限定在 APNG 动态图片格式),导致完全无法到达 Canary 目标。 - 代码冗余开销:为了在入口校验这些属性,生成器不得不重复编写解析逻辑(如计算 CRC 表),增加了每次执行的开销。
③ 专家手动设计状态抽象的困境
- 需要安全专家深刻理解
libpng的内部逻辑才能写出有效规则,人力成本极高,且无法泛化到其他程序和漏洞。
Locus 如何解决?(三步演进与精炼,图 1c)
Locus 的思想是:不局限于输入入口,允许在程序任意中间位置合成带有早期退出(EXIT())的进度谓词(Predicates)。
在处理该漏洞时,Locus 通过 Synthesizer-Validator Agent 循环 经历了 3 步迭代:
步骤 1:生成初始谓词(标记 ❶)
-
合成位置:Canary 函数的直接调用者
png_write_png中。 -
生成谓词:
if (png->color != PALETTE) EXIT();漏洞(CVE-2013-6954)发生在处理调色板数据的函数
png_set_PLTE中(调色板数据长度超出最大限制导致缓冲区溢出)。如果输入的 PNG 图片根本不是调色板模式(比如是一张普通的 RGB 真彩色图片),那它绝对不可能执行到目标 Canary 语句去触发漏洞。通过加上这句话,一旦 Fuzzer 喂进来一张非调色板图片,程序就会立马退出,不再继续往下执行后续昂贵的解压、渲染逻辑,从而帮 Fuzzer 节约时间。 -
评价:语义上是正确的(没有
PALETTE就无法触发目标 Canary),并且通过了符号执行的弛豫验证。但因为紧接着原代码中就有类似的检查(if (color_type & MASK_PALETTE)),所以插入在这里对 Fuzzer 的加速作用微乎其微。
步骤 2:第一次位置上提/精炼(标记 ❷)
原因:为了让程序更早地退出,Locus 的 Agent 启动了位置上提(Refinement,精炼)机制。
found_plte就是在往程序入口推进的过程中被 Agent 创造出来的。Agent 发现png_read_info里面有一个for (;;)循环,专门用来逐个读取 PNG 的数据块(Chunk,比如IHDR块、PLTE块、IDAT块等)。合成标记变量:Agent 意识到可以在循环前定义一个局部变量int found_plte = 0;——循环中如果读到了PLTE块(chunk_name == png_PLTE),就把标记设为found_plte = 1;。循环结束后检查:if (!found_plte) EXIT();(如果整个循环跑完都没遇到过 PLTE 块,说明这图没救了,直接退出)。
- 合成位置:通过遍历调用图向上追踪,推导至更靠近入口的函数
png_read_info中,放在解析循环刚好结束的地方。 - 生成谓词:插入辅助变量并在循环后检查
if (!found_plte) EXIT(); - 评价:使得没有解析到
PLTE块的输入在循环结束时就能直接提前终止(Early Exit),不必继续执行后续昂贵的渲染和写入逻辑。
步骤 3:第二次深度语义精炼(标记 ❸)
- 深度语义推理:Locus 的 Agent 进一步分析 PNG 协议规范发现:PNG 规范规定可选的
PLTE(调色板)块必须出现在IDAT(图像数据)块之前。 - 合成位置与谓词:Locus 直接将谓词推进至解析
IDAT块的分支内部:
if (chunk_name == png_IDAT) { if (!found_plte) EXIT(); // 到了 IDAT 还没发现 PLTE,说明后面不可能有了,直接退出!}- 效果:一旦解析流接触到
IDAT块而此前未标记过PLTE,程序立马提前终止。
最终效果与启示
- 极致加速:对于原本极其棘手的 CVE-2013-6954,仅仅凭借 Locus 在
png_read_info中插装的这 3 行精炼后的谓词代码,就为经典定向 Fuzzer(AFLGo)带来了 8 倍(8x)的漏洞触发加速。 - 启示与总结:
- 证实了在中间程序点插入语义谓词比单纯在输入入口做 Harness 约束更灵活、更有效。
- 证明了 Agent 多轮位置上提(Refinement) 机制的必要性——越靠近入口终止,节约的时间成本越高。
方法论

中文译图(AI 生成,部分术语翻译不准确,重点参考英文原图):

漏洞与 Canary(金丝雀)的定义:
- 触发漏洞 可以被视为让程序到达一组特定的程序状态 。
- Canary 谓词 :定义为一个布尔映射,当且仅当程序状态 时,。定向模糊测试的目标就是寻找能满足 的输入。
谓词放松(Relaxation)与 Fuzzing 容许性(Admissibility):
- 核心定理 1(Admissibility):如果我们给程序 插装一个新谓词 变成 (不满足时提早退出),只要 是 Canary 的放松条件(Relaxation)——即只要能到达漏洞状态,就必然满足 (数学表达式:)——那么 就是容许的(Admissibility)。
- 通俗理解:这意味着 Locus 插入的早期退出条件(Early Exit)绝不会”误杀”任何原本能触发漏洞的正确输入。它只会安全地拦截那些通往漏洞死路上的垃圾输入,从而让 Fuzzer 专心探索有效路径。
传统的软件修复或漏洞定位智能体(Agent)通常只配有简单的命令行或局部文本检索工具(如读文件、grep 搜索)。但由于 Locus 需要在程序的任意中间位置合成谓词,它必须具备跨函数、跨文件的全局代码推理能力。
为此,Locus 的 Agent 被赋予了一套专门的图分析工具集(Table 1):
- 基础检索工具:如
class、method、symbol、code搜索,用于寻找特定的结构体、函数或代码片段。 - 程序图遍历工具(占了总工具调用的 1/4 以上):
callers(f)/callees(f):获取函数的调用者和被调用者,用来推导跨函数调用链(控制流)。references(s):获取符号的所有引用,用来追踪变量、指针解引用和数据访问模式。
- 案例:静态图有时会因为动态分派或间接调用而漏掉部分关系,但论文提到,Locus 底层的 LLM 具备极强的代码推理能力,能够自己”脑补”并解决这些间接调用(例如成功把抽象的函数指针
tif->tif_decoderow识别并对齐到具体的PixarLogDecode实现)。
谓词合成与精炼(Synthesis)

Require: original program P, vulnerability canary ψEnsure: a target-conditional equivalent program P'
1: C ← CANARYREASONING(P, ψ) ▷ 获得推理列表 (list of reasonings)2: Φ ← ∅3: for all c ∈ C do4: l ← LOCALIZE(c, P) ▷ 寻找初始程序点 (find the initial program point)5: n ← 06: repeat7: ϕ_l ← GENERATE(l, c, P)8: while ¬VALIDATE(ϕ_l, ψ, P) do ▷ 语法与语义校验 (syntax and semantic)9: ϕ_l ← GENERATE(l, ϕ, P)10: end while11: l ← LOCALIZE(ϕ, l, c, P) ▷ 精炼上提,寻找更好的位置 (refine, find a better location)12: n ← n + 113: until l = None ∨ n > MAXITERATIONS14: Φ ← Φ ∪ {ϕ_l}15: end for16: P' ← INSTRUMENT(P, Φ) ▷ 自动化生成模糊测试容许程序 (fuzzing admissible program)- 输入 (Require):原始程序 及目标漏洞金丝雀 。
- 输出 (Ensure):插装谓词后、与原程序在目标条件上等价的程序 。
算法 1(Algorithm 1)展示了 Locus 谓词合成的具体流程。由于一次性让 LLM 直接写出完美且靠前的中间谓词非常困难,Locus 采用了一种 “迭代定位-生成-精炼” 的工作流:
- 初始 Canary 推理:Agent 先分析 Canary ,大致推测出可能与该漏洞相关的输入特征(如数据结构、类型、关键标志位)。
- 粗粒度定位:Agent 先不用精确到某一行,而是先挑出一个候选函数,并在该函数内生成初始谓词(即动机示例中的步骤 ❶,位置比较靠后)。
- 迭代精炼(Refinement):
- 只要初始谓词通过了后面的验证,Locus 就会启动精炼循环(Refinement)。
- Agent 会利用调用图工具,尝试把这个谓词”向上提炼(Propagate)“到调用链中更靠近程序入口的函数里,或者推到更前置的分支中(如精炼到步骤 ❷ 和 ❸)。
- 目的:越早的阶段把无效输入拦截(Early Termination),Fuzzer 就能省下越多宝贵的模糊测试时间。
双重验证(Validation)
为了防止 LLM 产生幻觉或写出错误的谓词导致程序崩溃、或者错误”误杀”了漏洞触发路径,Locus 设计了严格的双重验证流水线:
- 语法验证(Syntax Validation):
- 怎么做:直接把生成的谓词插到代码里,调用项目的构建系统(如 Makefile / CMake)尝试编译。
- 反馈修复:如果报错(如符号未声明、类型不匹配),编译器报错信息会被喂给 LLM 让其自我修正(Self-reflection)。
- 语义验证(Semantic Validation)—— 核心难点:
- 目标:通过数学方式证明生成的谓词 确实是 Canary 的”严格放松条件”(定理 2:如果存在某条路径使得 成立但 依然能触发,说明谓词有误杀,验证失败)。
- 工具:使用 KLEE 符号执行引擎来寻找这样的反例。
- 工程优化(解决路径爆炸):符号执行非常慢。Locus 借鉴了 Chopper 的思想,先用 SVF 静态分析框架对控制流图(CFG)进行可达性剪枝,只保留跟谓词和 Canary 相关的关键路径,把不相干的分支全部切掉,从而大幅降低符号执行的开销。
实验与评估
论文从第四节开始进入系统的实验评估与讨论部分。作者围绕四个核心研究问题(RQ1–RQ4),通过基准测试复现、部署成本分析、消融实验、0-day 漏洞挖掘及跨语言拓展,全面验证了 Locus 的有效性。
1. 实验设置 (Evaluation Setup)
- 数据集:选用业界权威的 Magma 漏洞基准测试平台,涵盖 8 个开源 C 语言项目(如 libpng, OpenSSL, PHP, SQLite3 等),包含 28 个注入了真实历史 CVE 探针(Canary)的漏洞样本。
- 对比 Baseline:涵盖 8 个顶尖 Fuzzer,分为两大类:
- 定向 Fuzzer:AFLGo、SelectFuzz、Beacon、Titan。
- 覆盖率驱动 Fuzzer:AFL++、AFL、MOPT、Fox。
- 评估指标:采用 TTE(Time-To-Exposure,触发暴露时间)。每个漏洞重复执行 10 次独立测试,设置 24 小时超时上限,并使用 Mann-Whitney U 检验确认统计显著性。
- 底座与工具:默认使用
o3-mini模型(Medium 思考模式),结合 SVF 进行可达性剪枝,使用 KLEE 作为符号执行引擎。
2. 四大核心实验 (Core Experiments)
RQ1:漏洞复现加速效果 (Effectiveness)
- 定向 Fuzzer 提速显著:集成 Locus 后,SelectFuzz 实现最高 214.2 倍的平均加速,AFLGo 获得 17.0 倍加速,Beacon 和 Titan 分别获得 22.1 倍和 28.0 倍加速。
- 覆盖率 Fuzzer 同样大幅收益:传统 Fuzzer 如 AFL++ 加速 15.3 倍,AFL 加速 20.4 倍。
- 攻克超时难题:帮助 Baseline 在 24 小时限定时间内多发现了多个原本无法触及的隐藏漏洞(例如帮助 AFLGo 多解出 5 个漏洞)。
RQ2:开销与部署成本 (Cost & Performance)
- 时间开销(预处理):传统定向 Fuzzer 的静态分析预处理时间随代码量指数级暴涨(如 PHP 项目)。而 Locus 的生成与验证预处理总耗时仅在 500~1350 秒之间,在大项目上比 SelectFuzz 预处理速度快 4.5 倍。
- Token 货币成本:生成单个漏洞样本的谓词平均消耗 457k Tokens,相当于单次部署仅需约 0.72 美元,经济可行性极高。
RQ3:消融实验与模型泛化 (Ablations & Generality)
- 消融分析:
- 仅使用 Base(初始谓词):提速不稳定,且效果有限。
- 仅 Refine 不做 Validation 验证:容易引入产生”误杀”(False Rejections)的错误谓词,导致程序直接超时。
- 完整流水线(Base + Refine + Valid):证明了双重验证在防止误杀中的决定性作用。
- 模型泛化:将底座更换为
DeepSeek R1和Gemini 2.0 Flash,同样在各漏洞上取得了显著的加速,证明架构不依赖特定单一模型。
RQ4:真实世界 0-day 漏洞挖掘 (Security Impact)
- 实战挖掘:将 Locus 应用于 VLC、libarchive、libming、tcpreplay 等真实开源软件。
- 战果:成功挖掘出 9 个全新的未修复零日漏洞(涵盖内存泄漏、UAF、空指针解引用及越界访问)。其中 3 个已得到官方修复确认。
- 对比:在相同时间内,原生 AFL++ 仅能发现其中 2 个,SelectFuzz 仅能发现 5 个,而结合 Locus 后成功挖出全部 9 个。
3. 案例研究与拓展测试 (Case Study & Extensions)
- 从 Patch 自动生成 Canary:在 SQLite3 的 CVE-908 案例中,Locus 直接从安全补丁反向推导 Canary,生成的条件比 Magma 官方人工标注的 Ground Truth 更加精准(更精准地捕捉了带引号字符串导致未初始化内存访问的本质原因)。
- 跨编程语言拓展:将框架拓展至其他语言生态(搭配 Claude Code/Sonnet 4.5),在 Go(Go-fuzz)和 Python(Atheris)上分别取得了 4.5 倍 和 2.6 倍 的 TTE 加速,在 Java(Jazzer)上也成功覆盖到了原本无法触及的漏洞函数。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!









京公网安备11011402057358号