Liberating Libraries through Automated Fuzz Driver Generation: Striking a Balance without Consumer Code

一.背景

  软件库的模糊测试依赖人工编写的fuzz driver,编写成本高、覆盖能力有限,易进入覆盖停滞状态。 现有自动驱动生成方法分为依赖用户程序与不依赖用户程序两类: 依赖用户程序的方法受限于已有调用模式,无法探索未知路径; 不依赖用户程序的方法依赖库源码,但普遍将驱动生成与输入模糊测试耦合执行,未对计算资源进行显式分配。 在固定计算预算下,驱动生成时间与测试时间分配直接影响最终覆盖与漏洞发现效果,而现有工具均采用固定策略,无法适配不同库的特性差异。 本文聚焦于不依赖用户程序的自动驱动生成方法,仅以库源码为输入,并支持驱动生成时间与测试时间的动态独立配置。

二. 现有方法不足

  第一,生成与测试耦合:现有方法将驱动生成与输入模糊测试混合执行,无法独立分配生成时间与测试时间,导致资源分配缺乏灵活性。

  第二,覆盖率导向偏见:现有方法多以覆盖率作为唯一反馈信号,长序列在初始化阶段通常不产生新覆盖,容易被误判为无效并提前丢弃,从而错失潜在有效的调用序列。

  第三,驱动测试较浅:现有方法持续生成新驱动,但每个驱动均未被深入测试,大量计算资源消耗于无效或冗余驱动,难以触发深层缺陷。

  第四,固定策略:现有方法对所有库采用相同的生成与测试流程,无法适配不同库在API复杂度和输入结构方面的特性差异。

image

三. 核心挑战

  要实现生成与测试时间的动态分配,必须克服以下三个具体挑战:

  • 挑战一:预测复杂 API 组合 API 序列的搜索空间为 N 的 L 次方,其中 N 是 API 函数数量,L 是序列长度。在缺乏先验信息的情况下,系统难以判断哪些序列值得探索,哪些序列可能无效。
  • 挑战二:避免覆盖墙偏见 需要长序列初始化的驱动,在前期往往不产生新覆盖。以覆盖率为导向的方法会将其误判为无效并提前丢弃,但完整的长序列恰恰可能触发深层代码。
  • 挑战三:深入测试 API 序列 持续生成新驱动会导致每个驱动都浅尝辄止。在固定算力下,如何在众多驱动中分配测试资源,避免冗余测试,是一个需要解决的问题。

四.  本文贡献

  • 贡献一:可配置时间分配的库测试模型 提出消费者无关的库测试模型,支持驱动生成时间与模糊测试时间的独立配置,可根据不同库的特性动态调整分配比例。
  • 贡献二:三项核心技术 API Flow Graph:
    • 通过静态分析构建API函数间的依赖关系,指导有潜力的序列生成,并配有具体的生成算法,从而预测复杂API组合序列(C1)。
    • 动态剪枝:记录无效API序列,后续生成时直接跳过,避免重复尝试,减少资源浪费,从而避免覆盖墙偏见(C2)。
    • 驱动聚类选择:基于API序列相似度进行聚类,从每类中选择代表驱动进行测试,避免冗余测试(C3)
  • 贡献三:开源原型工具LIBERATOR 实现端到端的驱动生成框架,仅依赖库源码,输出与libFuzzer、AFL++兼容的C语言驱动。代码已开源,可直接使用。
  • 贡献四:大规模实验验证 在15个开源库上评估,覆盖8K至518K行代码。对比Hopper、FuzzGen、OSS-Fuzz-Gen等工具,发现24个真实漏洞,21个已修复并上游,真阳性率达25%,为同类工作两倍。

五. libErator设计

image

 5.1 静态分析

  LIBERATOR 的输入仅为库的源码(.h/.c)

  过程:基于SVF框架对库源码进行指针分析和值流分析,提取每个API函数的参数类型、返回值、访问的结构体字段,识别变量生命周期(分配/释放函数)以及Var-len关系(缓冲区与长度参数的对应)。

  输出:API Flow Graph(AFG) : AFG为有向图,节点为API函数及其属性,边表示可能的调用顺序。

5.2 驱动生成

  输入:AFG(地图)+(生成时间预算)

  输出:一组高质量、多样化的 fuzz driver(正链)两个子任务: 生成足够多的候选驱动(§5.2) 筛选出具有代表性的驱动(§5.3)

image

  这是一个时间控制的主循环:只要已用时间 < t_gen 就不断做三件事: 调用 generate_api_chain 获得一个新 API 序列(候选驱动) 调用 probe 验证该驱动是否能正常运行(正链/负链) 将结果存入历史记录(供后续剪枝使用) 循环结束后,从历史记录中筛选出所有状态为 positive 的 driver。 返回这些正链驱动列表,供下一阶段(§5.3 驱动选择)使用。

image

image

  Algorithm2 总结:在 AFG 地图上,从源函数出发,不断扩展合法后继,并利用历史剪枝和字段偏置,生成一个从未在正链中出现过的新 API 序列。

5.3 驱动选择

  经过前面的生成,我们会得到大量正链驱动,由于很多驱动非常相似而导致算力被稀释。

  为此,如果两个驱动的 API 调用序列相似,它们测试的库代码区域也相似。所以可以用 API 序列的相似度 来代表驱动行为的相似度,然后聚类,每类只选一个代表。 具体步骤为:

  • 序列化:将每个驱动表示为其调用的 API 函数名称序列。
  • 计算相似度:使用 Levenshtein 距离(编辑距离)衡量序列之间的相似度。
  • 聚类分组:采用亲和传播算法自动对驱动进行聚类,无需预先指定类别数量。
  • 选择代表:从每个聚类中选取一个代表驱动,用于后续模糊测试。 通过这一方法,可以在几乎不增加计算开销的前提下,大幅减少冗余驱动,将有限的测试算力集中在多样化的驱动上。

六. libErator原型实现

  LIBERATOR 的原型实现分为两部分:

  静态分析部分基于 SVF 框架:codeQL 用约 4K 行 C++ 代码构建 API Flow Graph,并针对 SVF 无法解析全局函数指针间接调用的局限做了额外补全;

  驱动生成、聚类选择和时间调度模块: 用约 5K 行 Python 代码实现。生成的驱动采用 C 语言编写,输入遵循 TLV(Type-Length-Value)结构,并内嵌自定义变异器,确保与 libFuzzer 或 AFL++ 等引擎兼容。

七. 评估

  实验环境:Docker Ubuntu 20.04,Xeon Gold 5218,64GB RAM,每组实验 5 次重复取平均

  测试集:15 个 C 库,8K–518K LoC Fuzzing

  配置:ASan + SanCov,测试引擎 libFuzzer 和 AFL++

  对比工具:Hopper(agnostic)+ UTOPIA、FuzzGen、OSS-Fuzz-Gen(dependent)+ OSS-Fuzz 手动驱动 后续我们通过解答几个比较核心的问题来进行评估。

7. 1 生成时间与测试时间的权衡在实践中如何体现?

  我们并不能自动化计算每个库的生成时间和测试时间的比例。 所以在对每个库进行正式测试之前,都需要预先通过一系列短实验来确定该库的最优时间配置。

  具体做法是: 固定总时间(如 24 小时),分别测试多组不同的生成时间与测试时间比例(如 6h/18h、12h/12h、18h/6h、24h/0h),比较每组达到的代码覆盖率,从中选出对该库最有利的分配比例。 每个库都要先“试”出适合自己的时间分配,才能进入正式的模糊测试流程。

image

7. 2 LIBERATOR 对库的探索程度如何?

image

  x轴是在24小时模糊会话期间生成的驱动程序的数量。 y轴是达到的累计边缘覆盖。

  说明:仅靠生成驱动(不做任何 fuzzing),覆盖率会随着驱动数量增加而上升,但最终会停下来(平台期) 再通过 libFuzzer + SanCov 对每个驱动进行输入变异和覆盖率统计,从而实现库代码的深度探索。

7. 3 与现有工具相比如何?

image

image

image

 

7. 4 LIBERATOR 能否在真实库中发现漏洞?

imageimage

  上图为漏洞列举。发现 24 个真实 bug,21 个已修复,真阳性率 25%(两倍于同类工作) 其中包含 CVE-2024-8006(libpcap)。

  下图为出现假阳性情况。相比而言,OSS-Fuzz 手动驱动等在此期间无法发现新的漏洞,Hopper 的 894 个崩溃中仅 6 个为真。

7. 5 消融实验

imageimage

  聚类选择能将驱动数量减少很多,且耗时不足总实验时间的 0.02%,证明该方法能以极低开销有效筛选驱动、集中测试算力。

八. 未来工作

  不支持循环:LIBERATOR 无法生成包含 for、while 等循环结构的驱动。未来可通过静态分析识别适合循环调用的 API(如连续读写操作)。

  仅支持 C 语言:我们的设计是语言无关的,但依赖框架只支持 C。未来可扩展至 C++、Python 等(需处理类、模板、垃圾回收等语言特性)。

  框架限制:依赖的 SVF 框架在处理间接跳转、全局函数指针时存在精度损失,导致部分 Var-len 关系遗漏或假阳性,部分库因SVF而信息爆炸。未来 SVF 改进可间接提升 LIBERATOR。

  自动找最优时间分配:如何根据库的静态特征(API 数量、输入复杂度等)自动去预测(生成时间和测试时间)最优比例,仍然是一个开放问题。

  未使用LLM辅助:未来可以尝试靠拢。

九. 总结

  LIBERATOR 是一个仅依赖库源码的 fuzz driver 自动生成框架,通过解耦生成与测试、可配置时间分配,以及 AFG、动态剪枝、聚类选择三项技术,在 15 个库上发现 24 个真实漏洞,真阳性率达 25%,显著优于现有自动工具。

 

 

 

 

 

 

 

 

posted @ 2026-05-20 17:53  智慧人士橘猫  阅读(9)  评论(0)    收藏  举报