[用于软件缺陷检测的DL模型调查,论文个人学习分享]An Empirical Study of Deep Learning Models for Vulnerability Detection

An Empirical Study of Deep Learning Models for Vulnerability Detection

* Authors: Benjamin Steenhoek, Md Mahbubur Rahman, Richard Jiles, Wei Le


阅读内容总结

1 论文摘要(Abstract)

尽管现在有许多大模型被提出,并且在一些情景中DL模型已经远远超过静态的方法,但是我们对这些模型的机制仍然没有很好的理解,这限制模型的鲁棒性,调试和对故障检测的应用的长足发展。
这篇文章主要工作是:
1. 在常用的故障检测数据集Devign和MSR上研究并复现了9种最流行的DL模型。研究了关于模型能力,训练数据和模型解释性三个方面上的六个问题。
2. 通过实验证明了模型的不同运行与不同模型输出之间的低一致性之间的可变性。
3. 研究比较了针对特定类型的漏洞训练的模型和一次所有漏洞训练的模型。
4. 探索了 DL 可以考虑“硬”处理的程序类型。
5. 研究了训练数据大小和训练数据组合与模型性能的关系。
6. 研究了模型解释并分析了用于进行预测的重要特征。发现可以帮助更好地理解模型结果,为准备训练数据提供指导,提高模型的鲁棒性。

2 研究动机(Motivation/Introduction)

虽然DL漏洞检测现在并没有达到CV和大语言模型相同的实践高度,主要限制是我们不知道:选取的模型能或不能解决哪种类型的程序;究竟是应该为每种漏洞构建模型还是构建一个适合所有漏洞的模型;好的训练集是什么样的;模型到底用哪些信息进行决策(what type of programs the model can/cannot handle well, whether we should build models for each vulnerability type or we should build one model for all vulnerability types, what is a good training dataset, and what information the model has used to make the decisions.)这篇文章不是为了解决DL模型漏洞检测的问题,而是对解决这些目标的方向进行的一些探索。
三个方面的六个问题是:
第一个方面,了解DL处理漏洞检测问题的能力:

  • RQ.1模型是否同意漏洞检测结果。模型在不同运行和不同模型之间的变量是什么;
  • RQ.2不同漏洞监测之间效果有无差异,是应该构建多样的模型还是单一的通用模型;
  • RQ.3当前模型是否更难正确预测具有某些代码特征的程序,如果是这样,这些代码特征是什么

第二个方面,训练数据:

  • RQ4. 增加数据集容量能否提高漏洞检测模型的表现;
  • RQ5. 训练集中的数据构成比例对模型表现得影响;

第三个方面,模型的解释性:

  • RQ6. 源代码中哪些信息被用于预测,模型是否都遵从其中得重要特征

选取的数据集是Devign和MSR原因有三:1.两个数据集都包含真实项目和缺陷;2.本文中大多数模型都用Devign数据集来评估和调整;3.MSR数据集包含 310 个项目,其数据具有漏洞类型的注释,这是研究RQ 所必需的。

3 符号系统(Notation)

4 结论(Conclusion)

不同模型预测结果差异大;针对单一漏洞的模型好于全漏洞模型;模型表现并不随数据集规模上升而上升,最优在1k的规模取得;开发了一种逻辑回归模型可以用于发现模型难以准确预测的程序;解释工具表明这些模型都使用相同的特征进行预测,特征的范围大概是最重要的10行中的3.88到6.88行,报告了模型经常突出显示为重要特征的代码模式,未来将研究这些模式。

5 主体工作

5.1 每种方案可能存在的问题与可靠性考量

RQ2 中的分组受到偏差的影响,因为不同的研究人员可能会以不同的方式划分漏洞类型。在这里,两个具有领域知识的作者分别检查了 CWE 列表并讨论了并同意分组。为了减轻特定项目组合可能带来的偏差,RQ5 进行了 5 折交叉验证。对于 RQ6,作者选择了 SOTA 模型解释工具;然而,这些技术可能不足以确定模型使用的重要特征。RQ2、RQ4 和 RQ5 的实验要求模型与我们的没有模型附带的定制数据一起工作。我们为我们观察到的任何可疑数据尝试了不同的随机种子,例如,当模型报告所有 0s 或 1s 时。在调整无法解决问题时,我们在结果中排除了此类模型
在这里插入图片描述

Devign和Reval都在集成了控制流、数据依赖和AST的属性图上使用GNN结构;ReGVD在token上使用GNN;Code2Vec在AST上使用多层感知器(MLP);VulDeeLocator使用连续模型RNN;SySeVR基于连续模型Bi-LSTMs;最近的一些模型如CodeBERT、VulBERTa-CNN、VulBERTa-MLP、PLBART和LineVul运用的都是预训练迁移学习.
在这里插入图片描述

除了ReVal之外,每个复现的模型相差度都小于2%;ReVal的作者确认我们的结果修正了原论文中的数据缺陷,Devign因为不开源,所以采用的是其他人提供的版本。

在接下来的实验中使用Devign和MSR数据集(前者是一个平衡的数据集,由大致相同数量的脆弱和非脆弱示例组成,共有27,318个样本;后者是一个不平衡的数据集,由 10,900 个易受攻击的示例和 177,736 个非易受攻击的示例组成。)数据集中的样本都标有它们的源项目及其共同弱点枚举条目 (CWE),表明漏洞的类型。
因为SeSyVR和VulDeeLocator无法修改得同时支持Devign和MSR数据集所以只使用9个模型继续研究。

5.2 RQ1研究

目标是测量漏洞检测这种可变性实际上的数值。此外,我们希望发现不同深度学习模型之间以及具有相似架构的模型之间存在多少一致性。
在Devign数据集的相同训练/有效/测试分区上使用3个不同的随机种子训练模型,测量稳定输入的百分比——对所有 3 个随机种子具有相同二进制标签的输入占比。然后,我们比较了模型中的稳定输入来衡量它们的一致性。

5.3 RQ2研究

在这里插入图片描述

数据集设置:
MSR数据集,将错误类型分为缓冲溢出,值错误,资源错误,外部非法输入错误和权限错误五种。
划分原则是
(1)每组包含相似根本原因和语义的错误(2)每组都有一个足够大的数据集来有效地训练模型。CWE样例是具有CWE注释的脆弱样本
把这个数据集按80%/10%/10%的比例划分为训练集,验证集和测试集,分别在五组错误中训练每种模型,最后在融合数据中训练每种模型;当训练和测试数据具有相同的错误类型时,相同的错误类型性能报告测试 F1 分数。当训练和测试数据具有不同的错误类型时,交叉错误类型性能报告测试 F1 分数。

5.4 RQ3研究

目标是探究是否可以确认哪些程序能被检测得更好或更难以及是否不同模型都对这些困难有一致性。在程序分析中我们知道有的特征难以处理如循环和指针,我们想知道在DL模型中是否也是如此。
收集了12种代码特征:
控制流:while, for, if, goto, call,switch
非条件跳转 break, continue, return;
数据结构和指针:arrays,pointers;
辅助结构:comment,macro
构建了一个利用验证集数据训练得多元线性回归模型来从训练集中找出对预测而言困难和简单的样本,并通过深度学习模型验证LR模型的准确性,然后利用LR模型中的参数筛选出困难特征和简单特征。
LR模型: Y = σ ( ∑ i β ∗ x i + β 0 ) Y=\sigma (\sum_{i}\limits{\beta*x_i}+\beta_0) Y=σ(iβxi+β0)Y是样本的预测正确可能性, x i x_i xi是样本中每个代码特征的数量, β i β_i βi是每个 x i x_i xi的系数,在最后得出的系数 β i β_i βi中, β β β越大则说明该特征越有利于最后预测,反之值越小则说明干扰模型正确预测。
设定一个量化参数 l ( x ) = ∑ i β ∗ x i \mathcal{l}(x)=\sum_{i}\limits{\beta*x_i} l(x)=iβxi以这个参数的负值为难度分数,分数越高则越干扰正确预测。
以这一数值为基准,对测试集数据进行排序,然后取前10%和后10%进行预测,以比较结果来评估LR模型的正确性,然后通过LR模型来得到每种特征对最终模型的影响。

5.5 RQ4研究

目标是探究当前可用的数据集是否足够大以训练模型,以及增加数据集大小是否可以显着提高模型性能。
将MSR和Devign组合并剔除82个重复样本,生成一个了总共包含194,285个示例的非平衡数据集。
由于一些已发表的模型最初是在平衡模型上进行调整的,因此通过在MSR中取所有易受攻击的样本,然后随机欠采样相同数量的非易受攻击的样本,构建了45363个样本的平衡数据集。
然后分别以两个数据集的10%到100%训练10次模型,来探究数据规模对模型训练的影响;
同时以两个数据集的1%和5%进行训练,探究模型所需的最小数据量。测定值是每个模型的F1分数。

5.6 RQ5研究

目标是了解如何构造一个漏洞检测的良好数据集;同时也想了解训练集中的项目多样性对数据集的优劣的影响;了解不同的项目是否确实对模型起到不同的作用,当测试数据和训练数据来自于同一个项目时,模型的表现确实更好,那么当来自不同项目时,模型能否正确涵盖那些未出现过的项目。

第一个实验,分别在一个非多样化的训练数据集和一个多样化的训练数据集上进行模型训练,然后在相同测试集上比较性能。
在 MSR 数据集中,发现 Chrome 包含 76k 个示例,是所有 310 个项目中最大的,因此我们将其用作非多样化数据集。我们在 5 -fold交叉验证设置中进行了这个实验,以消除在选择项目时可能存在的潜在偏差。对于每个fold,我们从 MSR 数据集中随机抽取 10 k 个示例作为测试集。然后我们排除 Chrome 和测试集中使用的项目,并从剩余的项目中随机抽取总共 76 k 个示例(与 Chrome 相同的数字)。不同数据集中项目的平均数量为 50.6。

第二个实验,设置了混合项目数据集和交叉项目数据集。混合数据集中测试集与训练集分离,不考虑源项目,训练集和测试集中的一些样本可能来自同一个项目,这是本文所用的大多数DL模型采用的方式;交叉项目数据集中测试集样本必须源自与训练集的样本项目不同的项目。
同样采用5-fold交叉验证,在每一fold中,首先通过包含随机选择的项目中的所有示例来构建交叉项目的测试集,直到包含至少 10k 个样本的集合。因为每个项目都有不同数量的样本,因此结果集略大于 10k 个样本。然后,我们通过将剩余的示例随机划分为测试 (10 k)、验证 (10 k) 和训练(其余样本,约 158 k)集,混合项目的测试集就构建完成。然后利用相同的158k数据对模型进行训练,分别观察其在不同测试集上的性能。

5.7 RQ6研究

目标是了解为什么现在的DL模型能对漏洞检测有较好的表现,最好的模型(LineVul)是否使用了漏洞语义的任何方面来做出决策。
首先为不同的模型引入解释工具来获得模型中源代码特征的重要度。GNN解释器适用于Devign 和 ReGVD,LIT解释器适用于transformer模型:LineVul, VulBERTaCNN, VulBERTa-MLP, CodeBert and PLBART;
LIT解释器会为程序中的每个token提供一个评估分数;GNN解释器则会为源代码的图中每一条边提供一个分数,为了统一度量,参照其他论文将图中每个节点的入射边对应的边的分数求均值作为该点的分数,每个节点中的token共享一个值。
然后设定源代码中每行代码的分数为该行代码中所有token的分数之和,将分数由高到低排列,选出前10行作为模型决策的重要特征集合I。
为了衡量两个模型的重要特征集的相似程度,引入值Jaccard index: J ( I A , I B ) = ∣ I A ∩ I B ∣ ∣ I A ∪ I B ∣ J(I_A,I_B)=\frac{|I_{A} \cap I_B|}{|I_{A} \cup I_B|} J(IA,IB)=IAIBIAIB
衡量两个模型相似度的方法是,分别为测试集中的每个程序都计算一次该值和 ∣ I A ∩ B ∣ |I_{A\cap B}| IAB,然后求均值。
还会从正确预测,假阳性,假阴性的样例中抽取样例进行进一步的人工检查。

6 实验结果(Evaluation)

6.1 RQ1

在这里插入图片描述

结果表明,平均34.9%的测试数据(30.6%的总数据)出现了不同的预测。处理属性图的GNN模型变异性排名前2;特别是对于ReVeal,对于50%的测试数据,其输出在运行之间发生变化。与GNN和Transformer模型相比,Code2Vec报告的可变性最小。
在这里插入图片描述

只有7%的测试数据(和7%的总数据)被所有模型同意。3个GNN模型在20%的测试示例(和25%的总数)上达成一致,而3个表现最好的Transformer模型(LineVul, PLBART和VulBERTa-CNN)在34%的测试数据(和44%的总数)上达成一致。但是,当我们比较所有5Transformer模型,只有22%的测试实例(总共29%)是一致的。
不同模型之间的低一致性意味着,当没有基础真值标签时,作为常用方法的跨模型比较的差分测试方法可能用途有限。

6.2 RQ2

在这里插入图片描述

此研究通过图表和性能指标的对比展示了不同漏洞类型检测模型的性能表现。关键发现包括:

  1. 不同模型对于哪种漏洞类型最容易检测的看法并不总是一致,不同漏洞类型在不同模型中表现出不同的F1得分。

  2. 输入验证和资源错误通常在不同模型中表现较差,这可能与这些漏洞类型的复杂性有关,因为它们需要考虑变量值和循环等因素。

  3. 缓冲区溢出和值错误通常相对容易检测,这可能与它们的特性有关,这些漏洞类型在程序中的表现更加明显。

  4. 使用GNN架构的模型(Devign和ReVeal)在性能上表现相似,这可能是因为它们在属性图上进行了相似性建模。

  5. 对于资源错误(Resource errors),模型的性能相对较低,这可能是因为这些错误在代码中的位置分散,长距离依赖关系难以捕捉,或者训练数据不足以识别它们的模式。

  6. 综合模型通常在性能上不如特定漏洞类型的模型,但在某些情况下,综合模型可以表现更好,尤其是在处理输入验证和资源错误这两种漏洞类型时。

  7. 在对跨漏洞类型的性能进行分析时,研究发现在大多数情况下,不同漏洞类型之间的检测性能较差,除了 LineVul。这表明不同漏洞类型对应不同的数据分布,因此在检测与训练数据分布不同的漏洞时性能较低。特别值得注意的是,LineVul在处理值错误方面表现出色。当将训练于其他漏洞类型的模型应用于值错误的检测时,通常表现出比相同漏洞类型性能更高的结果。这表明LineVul在跨不同漏洞类型中有效地捕获和识别值错误,即使这些模型并未专门为值错误进行训练。

6.3 RQ3

在这里插入图片描述

所有9个模型在简单数据集上的表现都优于在困难数据集上的表现。所有模型的易/难性能的平均差异为10.3%。对于大多数模型(9个模型中有7个),原始测试集的性能介于难易集的性能之间。这些结果表明,LR模型和难度分数对于深度学习模型的难易样本选择是有效的。
![[Pasted image 20231226105946.png]]

  1. 对于所有模型call, length, pointers三种特征结果都相似,而且趋近于零点,这表明这三类特征的影响微乎其微
  2. for, goto, if, jump, switch, while这6种特征在每种模型中的取值都大有不同,而且这都是控制流相关的指令
  3. 对于所有模型,arrays和switch系数都是正的,说明这两种特征都对漏洞检测有利
  4. 对于大多数模型,goto和while都是负数;if对所有模型而言都是负值。而大量的if、goto和while语句表明程序的圈复杂度很高,这种类型的程序对程序分析也具有挑战性。
  5. 特别的,对于像Devign这样基于属性图的模型让其使用控制流信息来进行预测是背道而驰的,所以for, goto, jump和while都是负的(很难)是有道理的。

6.4 RQ4

  1. 将100%的数据与10%的数据进行比较,对平衡数据集的所有模型取平均值时,测试集上的F1报告没有差异。对于非平衡数据集,F1得分的值平均提高了0.16。
  2. 在平衡数据集上,只有LineVul模型随着数据增加而增长,而其他模型表现为上下波动,尤其是VulBERTa-MLP模型,F1甚至一度下降至0.1,而采用100%数据时则比10%数据时低0.08。似乎其他因素起了更重要的作用
  3. 在非平衡数据集上,随着数据集的增加,ReVeal是改进最多的模型。在100%的数据集上,ReVeal靠近最好的模型LineVul。但是与ReVeal一样在属性图上使用了类似的GNN架构Devign,却没有显示出额外数据的好处。
  4. 在小数据上的效果却很好,除开Code BERT,大多数模型都能在只采用5%数据的平衡数据集上取得良好的性能。在非平衡数据集上,性能转折点会向后推迟。例如,ReGVD和CodeBERT需要占总数据量的50% (96.4 k)和30% (57.8 k)。其他模型需要大约5-10%的数据(9.7-19.4 k)才能达到高点。有趣的是,这个数据集有10.8%的易受攻击的例子;也就是说,模型需要大约1048-2095个易受攻击的例子才能达到良好的性能,这与平衡数据集中的5%数据量大致相当。

6.5 RQ5

在这里插入图片描述

  1. (a)中盒型图表明,多样的训练数据相比非多样数据并没有带来显著增益,事实上,6个模型里有5个 仅采用Chrome项目的数据训练的模型F1分数的中位数要好于用多样数据的模型;
  2. (b)中,对于所有模型,混合项目测试集上的表现要明显好于交叉项目(平均高0.11,最大高0.32),这表明从一个项目看到数据确实可以帮助从同一项目预测其他数据。与直接使用已经训练的现成模型相比,漏洞检测可以极大地受益于定制的训练模型;
  3. LineVul模型在五次交叉验证中显示出非常不同的性能,这表明给定一个目标测试集,一些项目比其他项目更有用;
  4. 模型可以学习从数据集的项目特定属性(例如风格、语言特征或命名约定)中检测漏洞。

6.6 RQ6

在这里插入图片描述

  1. Linevul 和 ReGVD 在所有模型对之间具有最大的重叠性。重要特征集中,两个模型平均共享 6.88 行。
  2. 尽管模型可以对单个预测有很多分歧(如表4),但它们使用的代码信息重叠。所有模型对的重要特征集至少共有 3 行。
  3. Devign 作为唯一基于属性图的 GNN 模型,与其他模型的重叠较低,最低与 PLBART 重叠,平均 3.38 行。PLBART 与其他 Transformer 模型相比使用了不同的 Transformer 架构,并报告了与其他 Transformer 模型的低重叠。
  4. 我们还使用与表4相同的方法分析了校正后的预测示例。我们发现重要特征集对校正后的示例有更多的重叠,例如 Linevul 和 ReGVD 在重要特征集中仍然是最常见的,共享 7.29 行。
    从人工检查中得到的几个额外发现:
  5. 模型通常突出显示的代码行 for、if 和 while,以及函数签名作为重要特征。这些模型还经常突出显示 alloc、memset 和 memcpy 的内存操作,以及打印包含错误erroe或 printf 的错误消息的行。
    为验证猜想,引入下列表格
    在这里插入图片描述
  • 前7行是每个模型重要特征集中出现的token概率,每个模型中error概率都比其他token高;
  • 在 Func 行,展示了函数中出现的错误概率(函数中的总错误数/行总数)。比较这两者,我们表明出现在重要特征集中的error概率平均是程序中出现的errorr概率 2.79 倍,这表明,将error加入重要特征集是有所必要的。
    2.Transformer 模型有时会在没有看到根本原因的情况下进行预测。这是因为 Transformer 模型采用固定大小的输入,并且一些代码(有时包括根本原因)被截断。
    第二个发现的例证,用LIT模型预测左侧代码,可以看到LIT的重要特征集符合上面讨论的模式,包括第 1 行的函数签名,包含 ERROR 的行,例如第 13 行和第 16 行,以及第 21 行的 if 语句。我们还看到,对于这个项目,变量 name_len 很重要并多次包含。但是,10 行中没有一条覆盖第 14 行的内存分配,这是这个错误出现的重要原因。
    在这里插入图片描述

这个例子表明模型试图捕获漏洞的模式,而不是对原因进行推理,并且难以捕获代码中的远程语义依赖关系。但我们也在其他示例中观察到,有时突出显示为重要(见表 VII)的控制结构和记忆语句可能是漏洞依赖语句的一部分,因此它们对于检查错误的根本原因很有用。
在这里插入图片描述

这是第二个发现的另一个例子,非脆弱的程序被预测为脆弱。该模型突出了函数签名(第 2 行)、带有“ERROR”的行(第 7 节和第 10 行)、初始化(第 5 行)、if(第 6 节和第 9 行)和字段分配(第 15-17 行),并将函数预测为脆弱。结果表明,基于这些结构模式做出决策可能会导致错误。
3.通过检查所有模型遗漏的漏洞,并研究用于检测此类漏洞的重要特征集。发现这些漏洞非常特定于某些应用程序,所以此类错误没有足够的训练数据,因而错误可能会遗漏。

思考与相关工作

  1. 实验整体在9个模型和两个数据集上进行,结论的泛化性有待进一步验证。
  2. RQ2中对漏洞进行人为的五种划分,划分的人为因素可能会导致结果偏差。
  3. RQ3中使用的LR模型在文章中的准确性验证不够充分,利用这个模型进行深度学习关键代码特征的量化考量不准确。
  4. RQ6引入两种解释工具分别解释两类模型的语句token,虽然做了一定的映射转换,但也会给结果分析带来偏差。
  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值