[论文笔记] KNighter: Transforming Static Analysis with LLM-Synthesized Checkers
Introduction
传统静态分析依赖专家手工定义的分析规则,无法应对新的 bug 模式。LLM 在代码理解上有不俗的能力。但直接使用 LLM 去分析 Linux 内核又面临有限上下文和幻觉的问题。本文提出用 LLM 从以往的报告中合成静态检查器,并通过在已有报告上运行来验证检查器的正确性以减少幻觉。KNighter 生成的检查器在 Linux 内核中发现了 92 个新的漏洞。
Background
Clang Static Analyzer
KNighter 基于 Clang Static Analyzer(CSA) 实现。对于一个 bug 类型,应该首先设计对应的抽象状态,规定相关的程序点,在对应程序点上通过回调函数实现静态检查逻辑。程序会被建模成程序点和抽象状态组成的一个爆炸超图(exploded graph)。
Motivating Example
一个原始漏洞是 devm_kzalloc 调用后缺少空指针检查,解引用的时候会崩溃。因为缺乏 devm_kzallloc 可能在失败时返回 NULL 的领域知识,以往的内核分析工具未能识别这些漏洞。KNighter 从原始漏洞及其修复方案中提取出这个问题,合成的检查器跟踪执行路径中的空检查状态,在 Linux 内核中发现了 3 个新的漏洞。
Design

整个 workflow 可以划分为合成(synthesis)和精化(refinement)两个部分。
Checker synthesis
合成又可以划分为四个阶段:1. 分析 bug 模式;2. 制订计划;3. 合成代码;4. 验证,这四个阶段由四个 agent 完成。整体的思路很像 claude code,gemini cli 等一些 code agents。
分析 bug 模式:bug 模式从 patch 上下文中提取,希望更具针对性而不是特别高程度的泛化(这可以提高 LLM 生成的成功率)
制定计划:计划确实能给生成过程带来性能提升。此外,作者还手动维护了一个实用函数的集合,LLM 可以在规划过程中考虑并在后续生成中直接使用它们
合成代码:作者还提供了一个预定义的检查器模板以提高 LLM 生成成功率。为了处理这些可能的编译错误,还采用了一个专门的调试 agent。
验证:对相关代码的错误版本和补丁版本进行评估,验证检查器是否正确识别了原始代码中的目标错误,并在补丁后不存在报告。



Checker refinement
检查器的精化同样用一种 agentic way 的方式实现。一个分类 agent 判定检查器给出的报告是真阳性还是假阳性,另一个精化 agent 根据分类和原始的 bug 模式调整检查器的逻辑。这一过程会迭代的进行,直到消除掉所有的假阳性报告(并且保持真阳性报告不变)。
Evaluation
RQ1. Can KNighter generate high-quality checkers?
RQ2. Can the checkers generated by KNighter find realworld kernel bugs?
RQ3. Are the capabilities of KNighter orthogonal to the human-written checkers?
RQ4. Are all the key components in KNighter effective?
我更关注 RQ1 和 RQ4.
RQ1
在 61 个 commit 上做验证,正确生成了 39 个 commit 对应的检查器,代码平均行数为 125.7。花费了 15.9 小时,8.2M 的输入 token 和 1.2M 的输出 token,平均每个 commit 花费 $0.24。平均每个 commit 需要生成 2.4 次。
39 个检查器中的 26 个是无需精化的,剩余的 13 个被成功精化了 11 个。
RQ4

多阶段和 RAG 能够显著提高 LLM 生成的成功率和效率。Gemini-2-flash 的性能显著较弱,表现在 CSA 实现方面,频繁使用不存在的 CSA API,生成了更多语法错误。

浙公网安备 33010602011771号