关键词:GPU-Fuzz、深度学习框架 、 内存错误 、模糊测试 、 约束求解
GPU 内存错误是威胁深度学习框架可靠性与安全性的关键隐患,越界访问、静默数据损坏等问题会引发系统崩溃与安全风险,而 现有深度学习模糊测试工具以网络结构生成为核心,聚焦编译器算术错误检测, 未系统性探索算子参数空间,难以挖掘底层 CUDA 内核的内存漏洞。
GPU-Fuzz: Finding Memory Errors in Deep Learning Frameworks https://arxiv.org/pdf/2602.10478 针对该技术盲区,本文提出 GPU-Fuzz 模糊测试工具, 将深度学习算子的语义规则与内存约束建模为形式化约束公式,依托 Z3 SMT 求解器生成测试用例 ,并采用迭代约束引导搜索策略高效探查参数边界条件,通过跨框架执行与 NVIDIA Compute Sanitizer 工具实现内存错误精准检测。
实验结果显示:
GPU-Fuzz 在 PyTorch、TensorFlow、PaddlePaddle 三大主流框架中发现 13 个此前未知漏洞 ,包含 7 项内存访问违规、5 个静默内存损坏问题;
与主流工具 NNSmith 对比,4 小时内测试用例生成量提升近 3 倍,成功挖掘 26±5 个高危内存错误 ,而 NNSmith 未发现任何内存安全问题。 GPU-Fuzz 发现漏洞汇总。该表统计了 GPU-Fuzz 在三大框架中发现的 13 个未知漏洞,包含 7 个内存访问违规、5 个静默内存损坏漏洞。转置卷积算子漏洞高发,根因多为网格维度计算错误与边界检查缺陷。漏洞覆盖静默损坏、GPU 异常、CPU 断言三类模式。GPU-Fuzz 可有效发现主流深度学习框架的底层 CUDA 内核内存安全漏洞,验证了工具的检测能力。 GPU-Fuzz 实现了从网络模型测试到算子参数空间测试的范式转变,填补了深度学习框架 GPU 内存安全测试的空白,为提升 AI 系统底层可靠性与安全性提供了全新技术方案。
unset
unset 本文目录 unset unset 一、引言 二、背景与动机 2.1 GPU 架构 2.2 深度学习算子 2.3 动机 三、系统设计 3.1 算子建模 3.2 基于约束的测试用例生成 3.3 跨框架执行 四、实现 五、评估 5.1 实验设置 5.2 漏洞发现效果 5.3 对比研究 5.4 案例研究 六、讨论 七、相关工作 八、负责任的披露 九、结论 交流加群请在 NeuralTalk 公众号后台回复:加群 unset
unset 一、引言 unset unset 如今,GPU 已成为 PyTorch[22]、TensorFlow[1]等深度学习(DL)框架中不可或缺的组成部分。然而, GPU 计算的正确性却常受到内存损坏问题的威胁,这类隐蔽的漏洞源于底层的 CUDA 内核 [18]。越界访问(内存访问时超出程序分配的内存地址范围)、内存地址未对齐(访问内存的地址不符合硬件要求的字节对齐规则)等内存错误,不仅会导致系统崩溃,还会引发静默数据损坏[7](内存数据被错误修改但无任何崩溃或报错提示,隐蔽性极强),对人工智能应用的可靠性和安全性构成重大威胁。
但定位这类与内存相关的漏洞仍是一项极具挑战性的工作 。 现有的深度学习系统模糊测试工具主要通过生成不同结构的多样化神经网络,来检测深度学习编译器中的算术计算错误 [15]。这种方法虽对编译器测试有效,却因未对算子参数空间进行探查,无法有效发现内存错误。
本文的核心见解是:要发现 GPU 内存错误,需将测试重点从网络结构转移到算子参数和内存布局上 。张量形状、数据类型、步长及其他参数的特定组合,决定了 CUDA 内核中的内存访问模式。因此, 一款有效的模糊测试工具必须能对这些复杂的访问模式进行推理,并生成可系统性探查参数空间的输入用例。
为此,我们设计并实现了 GPU-Fuzz 这一新型模糊测试工具,其专门用于定位这类与内存相关的漏洞 。与 NNSmith[15]等现有深度学习模糊测试工具不同, GPU-Fuzz 聚焦于算子层级的测试 。它 将深度学习算子复杂的语义规则和内存相关规则转化为形式化约束,再通过求解这些约束生成多样化输入用例,探查与内存相关的边界条件 。这种基于约束引导的测试方法[8],能让 GPU-Fuzz 对底层 CUDA 内核进行有效的内存安全性压力测试。
本文的主要贡献如下:
提出一种全新的模糊测试方法,通过系统性探查算子参数空间来针对 GPU 内存错误开展测试,该研究维度与现有深度学习模糊测试工具[15]形成互补;
设计并实现 GPU-Fuzz 系统,该系统利用约束求解技术自动生成测试用例,探查底层 CUDA 内核中与内存相关的边界条件; 在 PyTorch、TensorFlow、飞桨等主流深度学习框架中,通过 GPU-Fuzz 发现了 13 个此前未被发现的漏洞,验证了该工具的有效性。 unset unset 二、背景与动机 unset unset
2.1 GPU 架构 现代 GPU 是基于流多处理器(SMs)构建的大规模并行计算设备,每个流多处理器可同时执行数百个线程[18]。这种并行计算能力由复杂的内存层级结构支撑[13], 但要利用该硬件实现高性能计算,开发人员需手动管理数据的存储位置和传输过程 [9]。这一手动操作的复杂性,使得 CUDA 内核极易出现越界访问、竞态条件等内存错误[12]。
如图 1 所示,这类内存错误可被利用,从而破坏内核的完整性并篡改程序的控制流 。与这类攻击密切相关的内存空间主要包括:
全局内存 :供所有线程共享的大容量内存空间,通常用于存储内核的可执行指令和全局变量。 已有研究表明,GPU 不支持写执行分离(W⊕X)权限机制[10],因此越界写入漏洞会让攻击者能够修改存储在该共享空间中的内核指令 ,从根本上改变程序的预期执行逻辑。
本地内存 :每个线程独有的私有内存空间,用于存储函数参数、局部变量以及返回地址等控制流数据。 栈缓冲区溢出是一种常见的内存错误,该错误会覆盖保存的返回地址,而这一漏洞正是面向返回的编程(ROP,一种利用程序中现有代码片段实施的内存攻击手段,通过拼接现有返回指令实现恶意逻辑)攻击的基础 [10],攻击者可借此劫持线程的控制流,将执行逻辑转向恶意有效载荷。 这些漏洞的存在,凸显了建立可靠机制以检测和缓解 CUDA 内核中内存损坏问题的必要性。
2.2 深度学习算子 PyTorch[22]、TensorFlow[1]等深度学习框架,均基于一套丰富的基础计算单元构建,这类计算单元被称为 算子 。卷积、池化、矩阵乘法、激活函数[3]等算子,是构建神经网络的基本模块。
用户可通过简洁的高层 Python 接口调用这些算子,但其底层实现却极为复杂:每个算子都由一个或多个高度优化的底层程序(即内核[3])支撑,这些内核将在 GPU 上执行。
如图 2 所示,高层的 Python 算子调用会被转化为底层的 CUDA 内核执行,而实现过程中的细微漏洞,都可能引发各类内存错误。
算子的参数空间极为庞大,这是其底层实现复杂的核心原因 。以卷积算子[6]为例,除输入张量本身外,该算子还受内核尺寸、步长、填充、膨胀率、通道分组等众多参数约束。这些参数并非相互独立,而是受一套复杂的语义和数学约束规则限制,这些规则决定了参数的有效组合方式,并定义了输出张量的属性。为实现最优性能,框架开发人员会使用 CUDA C++手动实现这些内核,同时采用共享内存分块、复杂的指针运算等高级技术最大化数据吞吐量[9]。 这种以性能为导向的手动优化,往往会舍弃更安全的高层抽象方法,使得内核代码成为隐蔽内存错误的高发区——这类错误仅会在特定且通常较为罕见的参数配置下被触发[12]。
2.3 动机 GPU 内存漏洞是人工智能系统可靠性和安全性面临的严重且隐蔽的威胁[20]。在医学影像[24]、自动驾驶[14]等关键任务型应用中,这类漏洞可能引发灾难性故障;同时,它也可能被利用实施安全攻击[21,23]。
当前主流的深度学习模糊测试工具聚焦于编译器栈,通过生成有效的神经网络来发现漏洞[15,16]。 但这种方法并不适合检测 GPU 内核中的底层内存错误 ——这类错误通常并非由网络架构引发,而是由算子参数的特定组合(尤其是边界值组合,如张量形状、步长)触发。
这就导致了一个根本性的测试盲区:NNSmith[15]等现有工具并未对单个算子复杂的参数空间进行系统性探查,而这正是 GPU 内存漏洞的隐藏位置。
这一发现表明,深度学习模糊测试需要向 算子层级模糊测试 转型。为此,我们提出 GPU-Fuzz 系统,该系统通过探查算子参数空间,发现底层 CUDA 内核中的内存漏洞。
unset unset 三、系统设计 unset
unset 本节详细介绍 GPU-Fuzz 的架构。如图 3 所示,该系统包含三个核心阶段:算子建模、基于约束的测试用例生成、跨框架执行。
3.1 算子建模 GPU-Fuzz 通过一个抽象层对 GPU 算子进行建模,捕获算子的参数空间和形状关联关系。每个算子类别(如卷积、池化)都由一个统一模型表示,该模型定义了输入/输出形状的接口以及参数约束规则。
如图 4 所示,GPU-Fuzz 将算子语义编码为一组含符号变量的约束公式。
以图中的卷积算子为例,其核心约束公式[6]为:
其中, 和 分别表示输入和输出尺寸, 为填充值,
为膨胀率, 为内核尺寸, 为步长。只有当输入满足该约束公式时,算子才能被正确实例化并执行。除该核心约束外,还存在各类附加约束(如 )以保证算子的语义正确性。这种约束建模方法,能让我们为深度学习算子有效生成合法的测试用例。
为保证建模的正确性,我们从每个算子的官方文档中手动提取约束公式。两位作者独立完成各算子约束公式的提取工作,再交叉验证结果,整个过程耗时约一个月。这两位作者均为深度学习领域的专家,对各算子的语义有深入理解,这在很大程度上保证了 GPU-Fuzz 的正确性。本研究共为 13 类算子提取了 45 条约束规则。
3.2 基于约束的测试用例生成 约束求解 当算子完成约束建模后,GPU-Fuzz 会利用 Z3 的 SMT 求解器[5]为所有符号变量寻找满足约束的赋值。
如图 5 所示,要为卷积算子生成测试用例,求解器需为 、
、 、 、 和 找到满足图中约束集的具体数值。以图 5 为例,一组可行的解为 、
、 、 、
、 。
尽管 Z3[5]等 SMT 求解器能有效为给定约束找到一组解,但其设计初衷并非系统性探查整个参数空间。 具体而言,Z3[5]这类求解器往往会为符号变量返回单一的边界解(如对于约束 ,返回 ),这对于全面的模糊测试而言是远远不够的。 为解决这一问题,NNSmith[15]等现有研究通过为原始约束添加周期性扰动(如
),迫使 Z3[5]返回多组解 。而 GPU-Fuzz 则采用一种全新的 约束引导搜索策略 ,实现对参数空间的系统性探查。
参数空间探查 为实现对参数空间的系统性探查,GPU-Fuzz 采用迭代式的约束引导搜索策略,如图 6 所示。
该过程从求解器找到的初始解 (如
、
)开始,在每次迭代中,系统随机选择一个参数维度添加约束。
例如,系统可能先选择步长( ),添加排除其当前值的约束,引导求解器找到新解 ;在下一步中,系统可随机选择内核尺寸(
), 在现有约束基础上累加新约束 (如
且
), 迫使求解器向未探查的区域搜索,进而得到另一组解 。
值得注意的是,为同时提升求解器的效率和解的多样性,我们提出在约束中不仅加入 直接值排除 (如
),还融入 基于哈希的约束 (如 )。该哈希函数通过一系列位混合操作对输入值进行转换,使其具备离散性;
具体而言,该函数通过交替执行右移、异或和乘法操作,确保输入值的微小变化都会产生不同的哈希值,有效避免恒等映射和分布不均的问题。 基于哈希的约束与直接值排除形成互补,能防止求解器探查相似的参数区域,大幅提升解的多样性。
这种增量式搜索策略,确保 GPU-Fuzz 能持续、高效地生成多样化的测试用例。
3.3 跨框架执行 当生成一组有效的算子参数后,GPU-Fuzz 会将其作为测试用例,在 PyTorch[22]、飞桨[17]、TensorFlow[1]等多个深度学习框架中执行,以检测 GPU 内存错误。
如图 7 所示,该过程会将求解器生成的、与框架无关的抽象参数,转化为带特定 API 调用的具体参数。
例如,通用参数 outch 会在 PyTorch 中映射为 out_channels ,在 TensorFlow 中映射为
filters 。为检测内存错误和内核执行故障,每次执行都会由 NVIDIA 的 compute-sanitizer 工具[19]封装监控,这一方法能大幅提升内存错误的检测效率。
unset unset 四、实现 unset unset 本节详细介绍第 3 节所述系统设计的具体实现。GPU-Fuzz 基于 Python 开发,代码总量为 2628 行。
为实现第 3 节提出的算子建模和基于约束的测试用例生成功能,我们开发了一个专用库,该库中将每个算子表示为独立的类。本研究为 13 类算子应用了该建模方法(如表 1 所示),这些算子均为深度学习模型中的常用算子,且其内存访问模式复杂、易出现错误。
我们实现了第 3.3 节所述的参数转换过程, 将生成的参数值转化为各框架专属的 API 调用 。当 compute-sanitizer[19]在执行过程中检测到错误时,系统会自动归档执行日志,确保错误可复现。
unset unset 五、评估 unset
unset 本节对 GPU-Fuzz 的有效性和效率进行评估,旨在解答以下研究问题(RQ):
RQ1: GPU-Fuzz 在发现主流深度学习框架中的实际漏洞方面效果如何? RQ2:在测试用例生成和漏洞发现方面,尤其是针对 GPU 内存错误的检测, GPU-Fuzz 与当前主流的深度学习模糊测试工具相比表现如何? 5.1 实验设置 所有实验均在一台配置如表 2 所示的服务器上完成。
我们为 PyTorch、TensorFlow、飞桨三个目标框架分别搭建了独立的 Conda 环境,以管理各自的专属依赖;
所有测试均使用相同的核心硬件、操作系统和 NVIDIA 驱动。 5.2 漏洞发现效果 在评估过程中,GPU-Fuzz 在三个深度学习框架中共发现 13 个此前未被发现的漏洞,表 3 对这些发现进行了汇总。
这些漏洞涵盖多种故障模式,从底层内存损坏到 API 层级的异常均有涉及;其中我们 识别出 7 类不同的内存访问违规问题 (如越界访问、未对齐写入),且有 5 类为静默内存损坏——这类错误不会触发任何 API 层级的崩溃,仅能通过 compute-sanitizer[19]等专用工具检测。
漏洞模式 我们的研究发现,所有漏洞可归为三类不同的故障模式,且各模式呈现出明显的规律:
静默内存损坏 :最关键的漏洞类别,该类错误会引发越界或未对齐的内存访问,但不会触发任何 API 层级的错误提示。这类漏洞的隐蔽性极强,是最危险的内存错误,仅能通过底层内存调试工具检测。 GPU 层级异常 :第二类漏洞,无效的参数或配置会导致 CUDA、cuDNN 或 CUBLAS 库返回错误,该错误通常会被框架捕获并上报。 CPU 端断言失败 :最后一类漏洞,在 CPU 端计算内核参数时会出现整数溢出等问题,直接阻止 GPU 内核的启动。 所有框架中漏洞的一个常见根本原因是 网格维度计算错误 或 边界检查逻辑缺陷 ,其中 转置卷积算子 是漏洞的高发区。
5.3 对比研究 为从数量上验证 GPU-Fuzz 的有效性,我们 将其与当前主流的深度学习模糊测试工具 NNSmith[15]进行对比实验 。在同一硬件上,我们针对 PyTorch 框架分别对两款工具进行 5 次独立的 4 小时模糊测试,且两款工具均运行在相同的 Conda 环境中。
表 4 汇总了对比实验结果:
NNSmith 平均生成
个测试用例, 发现 个漏洞,且其发现的漏洞大多为数值不匹配问题,并非内存安全问题; 而 GPU-Fuzz 平均生成
个测试用例,排除内存不足错误后 共发现 个实际漏洞,其中包含 个严重的内存错误和 个配置错误 。这些内存错误属于严重的安全漏洞,可能导致数据损坏、信息泄露或系统崩溃。 核心发现
我们的分析得出两个关键结论:
第一,GPU-Fuzz 生成的测试用例数量约为 NNSmith 的 3 倍,证明了 基于约束引导的参数模糊测试在系统性探查算子参数空间方面的高效性; 第二,GPU-Fuzz 发现了 个具有安全风险的内存错误,而 NNSmith 发现的漏洞主要为数值精度问题,通常不会威胁内存安全。 这一结果表明, GPU-Fuzz 填补了现有深度学习模糊测试工具在 GPU 内存安全测试方面的盲区 。两款工具的测试方法形成互补:NNSmith 擅长发现编译器相关漏洞和数值不一致问题,而 GPU-Fuzz 则填补了算子参数层级 GPU 内存安全测试的空白。
5.4 案例研究
为验证 GPU-Fuzz 的实际实用性,我们以 PyTorch 的二维转置卷积(ConvTranspose2d)算子中发现的一个内存损坏漏洞为例,给出最简可验证性证明(PoC),如图 8 所示。
触发该漏洞的关键在于 GPU-Fuzz 自动生成的参数组合,尤其是超大的步长值 与输入维度
的组合。 尽管这些参数值符合 PyTorch API 的语义规则,但属于手动测试中极难覆盖的边缘场景。
如图 8 所示,该漏洞的根本原因是 C++主机端代码中的 整数溢出 :
在计算 CUDA 内核的总元素数时,64 位整数值被强制转换为 32 位整数,导致数值被截断; 该溢出后的数值随后被用于计算 CUDA 网格维度,生成的网格尺寸过小,无法覆盖所有必要的内存操作。 当 col2im_kernel 内核执行时,线程计算出的 64 位索引会超出实际分配的缓冲区大小,最终引发内存越界写入。
如图 9 所示,compute-sanitizer 检测到有 CUDA 线程试图向越界地址写入数据,且该地址位于最近的有效内存分配区域之前。 这类静默内存损坏是严重的漏洞,它不会引发显式的 Python 程序崩溃,却可能导致计算结果错误或程序行为不可预测。
这一案例证明,GPU-Fuzz 能够通过探查非平凡的参数空间,系统性地发现成熟深度学习框架中隐藏的严重漏洞。
unset unset 六、讨论 unset unset 尽管实验结果验证了 GPU-Fuzz 的有效性,但我们也认识到该工具存在一些局限性,同时也明确了未来的研究方向:
手动建模的工作量 :GPU-Fuzz 的性能依赖于其约束库的完整性。当前我们的约束库仅支持 13 类算子,而深度学习框架中存在数百类算子,扩展算子覆盖范围需要手动进行约束建模(每类算子约需 100-150 行代码)。未来的研究可探索从框架文档中半自动提取约束规则的方法,以提升工具的可扩展性。 测试判定器的局限性 :我们主要使用的测试判定器 compute-sanitizer 擅长发现内存错误,但无法检测静默的数值正确性问题或性能退化问题。将模糊测试与可信的 CPU 实现进行差分测试,是实现更全面测试判定器的可行方向。 unset unset 七、相关工作 unset unset
近年来,深度学习系统的模糊测试研究受到持续关注[25]。为检测复杂的现代深度学习编译器栈中的漏洞,一种有效的方法是生成合法的神经网络模型。
NNSmith[15]、TVMFuzz[25]、HirGen[16]等研究开创了这一方向,证明了该方法在发现编译器相关漏洞(如图层优化问题、中间表示转换错误)方面的有效性。在此基础上,其他研究开始针对深度学习栈的不同组件开展测试:
例如 LEMON[26]通过 生成模型变体检测不同库实现之间的不一致性 ,从而对深度学习库进行测试; Orion[11]等近期研究则 基于历史漏洞模式生成测试输入,专门针对 API 层级开展测试。 尽管这些方法均有成效,但它们主要在较高的抽象层级执行测试,并未被设计用于系统性探查执行算子的 GPU 内核中的底层内存访问模式。
而针对 GPU 内核的测试本身也形成了独立的研究方向:
GPUVerify[2]采用形式化方法,通过检测数据竞争和屏障分歧验证内核的正确性; DeepSmith[4]通过从头生成随机的 CUDA 程序,对 CUDA 编译器本身进行压力测试[9]。 相比之下, GPU-Fuzz 与上述研究均存在差异 :它既不像 NNSmith[15]那样生成完整的神经网络模型,也不像 DeepSmith[4]那样生成完整的 CUDA 程序,而是 聚焦于现有深度学习算子的参数空间模糊测试,以发现内核层级的漏洞。
unset unset 八、负责任的披露 unset unset 我们已通过在 PyTorch[22]、TensorFlow[1]、飞桨[17]的官方代码仓库中提交详细的漏洞报告,向各框架的开发团队负责任地披露了发现的全部 13 个漏洞。在撰写本文时,多个漏洞已得到开发人员的确认。我们将继续与框架维护者合作,助力提升深度学习生态的安全性和鲁棒性。
unset
unset 九、结论 unset unset 本文提出了 GPU-Fuzz 这一基于约束引导的模糊测试工具,其专门用于发现深度学习算子中的 GPU 内存错误。通过将测试重点从网络模型转移到算子参数空间,GPU-Fuzz 能够探查可能触发底层漏洞的边界条件。在 PyTorch、TensorFlow、飞桨等主流深度学习框架中的实验表明,该工具发现了 13 个此前未被发现的漏洞,且其中大部分为静默内存错误。
本研究表明,保障现代人工智能系统的安全,可采用 模型层级模糊测试 与 算子参数空间模糊测试 相结合的互补策略。我们希望通过公开 GPU-Fuzz 工具和相关研究发现,为提升这些基础技术的可靠性和安全性做出贡献。