Group of Software Security In Progress

SinkFinder Harvesting Hundreds of Unknown Interesting Function Pairs With Just One Seed

作者:Pan Bian, Bin Liang, Jianjun Huang, Wenchang Shi, Xidong Wang, Jian Zhang

单位:Renmin University of China

会议:FSE’2020

论文链接:https://rucsesec.github.io/papers/FSE2020.pdf

Abstract

作者实现了SinkFinder来使用机器学习方法,自动化地挖掘那些感兴趣的安全敏感函数对,并且只用提供一对函数作为初始化种子。最后作者自己实现了checker,并利用挖掘出的安全敏感函数对在Linux Kernel-4.9上发现了55个可疑的bug,其中有37个已经得到了确认。

1. Introduction

在检测特定类别的漏洞时,关于那些函数能够造成这一类漏洞的先验信息是非常重要的。在实践过程中,那些对安全敏感的函数通常是根据已有的知识手工收集,但明显这需要耗费大量的人力,并且还存在着收集函数的不准确性。

为此,作者利用机器学习设计了自动化挖掘出安全敏感函数对的方法,给定特定类型的函数对<kmalloc,kfree> 和<mutex_lock,mutex_unlock>,来发现其他的属于这一类的“Alloc/Free”和“Lock/Unlock”函数。

下面给出SinkFinder利用识别出属于“Alloc/Free”类的一对函数<sb_bread,brelse>检测出的UAF漏洞例子:

Linux Kernel 中的许多内存对象都用reference来记录引用此对象的个数,sb_bread函数会返回一个refcount为1的block head,brelse函数会将block head的refcount减一,当refcount为0时此内存对象才会被释放。下图代码第19行将bh的refcount减一,并在21行解引用了bh,如果在第19行和21行之间bh被其他进程释放的话,就会造成UAF。

2.Approach

2.1 OverView

定义: seed pair: 给定的函数对。 例如<kmalloc,kfree>。 positive pair: 和seed pair属于同一类别的函数。 negative pair:所有其他不感兴趣的函数对。

文中涉及的两种词向量训练方法的区别: - word2vev: 训练出的词向量仅包含上下文信息。 - fastText: 训练出的词向量包含本身携带的信息和上下文信息。

第一阶段首先从源代码中挖掘出频繁出现的函数对,然后使用fastText训练出关于函数名的词向量,在词向量的基础上来做类比推理,输出positive, negative 和unlabelled pairs。

第二阶段采用第一阶段输出的positive, negative pairs来作为训练样本,训练一个SVM分类器来从那些unlabelled pairs中识别更相似的函数对。

2.2 频繁函数对挖掘

作者认为函数对之间应当存在很强的数据流关系,并定义了以下两类的数据流关系:

  1. DataDep: 如果$g 1$的输出值流向了$g2$的参数之中,则认为函数对$<g1,g2>$存在数据依赖关系。
  2. DataShare: 如果$g1$和$g2$都使用了同一个参数,则认为函数对$<g1,g2>$存在数据共享关系。

如果在一个函数定义中,同时调用了$g1$和$g2$,并且$<g1,g2>$之间存在DataDep或者DataShare关系,那么就将此函数对的支持度加1。所以每个函数对最后的支持度,就是存在多少个函数定义中存在此类的函数对。

因此,可以设置一个阈值min_support=10,大于此阈值的认为是频繁出现的函数对。

2.3 嵌入函数向量

SinkFinder会在控制流图上过程内的进行随机游走,将随机游走得到的函数调用序列作为训练语料,来训练出函数的向量表示。

在得到了每个函数的向量表示之后,给定一个函数对$p:<f,g>$,通过计算这两个向量的差,来得到此函数对的向量表示:

这样的做法通常存在于类比推断中,比如下面例子:

2.4 推断出可靠的函数对

使用fastText训练出的函数向量进行类比推断,如果函数对$p$于seed pair之间的距离足够近,那么就认为$p$为感兴趣的函数对,相反为不感兴趣的函数对。

但是这样的一个距离阈值并不好设定,为此作者还设计了一个算法来动态的计算出最好的阈值。

2.5 函数对分类

在上一小节中,仅使用fastText向量就可以得出一部分目标函数对,比如<kmalloc,kfree>和<vmalloc,vfree>这样的。

但是kernel中还存在很多的Alloc/Free函数并不包含关键词“free”和“alloc”,比如说<sb_bread,brelse>。所以包含函数名信息的fastText词向量就不适用于挖掘这类函数,word2vec则可以利用上下文信息来进行挖掘。

但是又因为word2vec向量中既包含了感兴趣的成分,也包含了不感兴趣的成分,直接使用类比推断并不适合。因此作者使用SVM分类器来对向量的每一维度加权重,进行分类。

训练数据: 第一阶段中识别的positive pairs作为正样本,negative pairs作为负样本,进行训练。

预测: 从第一阶段剩下的那些unlabelled pairs中进行预测,来找到可能的正样本。

3. 实验

### 3.1 实验设置

作者实现了use-after-checker 和 mismatched-alloc-free checker 来根据识别的”Alloc/Free”类函数检测 Linux Kernel-4.9中的内存漏洞。

并设计了实验来回答如下问题:

RQ1. SinkFinder识别未知的目标函数对的效果怎么样? RQ2. SinkFinder识别出的函数对对未知漏洞检测能带来多大帮助?

3.2 识别目标函数对

作者使用了比较常见的六类安全函数作为seed,然后在Linux中寻找目标函数对,最后寻找到的结果如下所示:

3.3 漏洞检测

作者仅使用识别出的<Alloc/Free>类别的函数来检测uaf和mismatched-alloc-free 漏洞。

Checker报告了835个UAF 和522个mismatch 漏洞,然后作者使用一些漏洞等级排序机制,即违反检测规则越少的报告,越可能是误报,排序越靠前。

作者分别在前100个和前10个漏洞报告中,发现了52个UAF和 3个mismatch漏洞,其中有37个漏洞被开发者确认。

另外,作者还使用<CRYPTO_malloc, CRYPTO_free>和<fopen, fclose>作为seed,在OpenSSL和PostgreSQL软件上测试了SinkFinder具有泛化能力。

最后在OpenSSL和PostgreSQL中报告了92个和22个漏洞,分别有1个和3个漏洞被厂家确认。

3.4 比较分析

Coverity: coverity是一个静态漏洞检测软件,它使用kfree()作为sink来进行uaf检测。但是SinkFinder发现的漏洞,Coverity均没有进行报告。

grep-like method: 因为”Alloc/Free”类别的函数通常带有关键词“alloc”和“free”,作者使用 grep 根据$<.^alloc.^, .^free.^>$模式,在SinkFinder识别的237对函数中进行识别,发现只有35.02%的函数符合这样的模式。

4. Discussion

作者提出了关于SinkFinder,在以下几点还有可提升的空间:

  • 使用更多的seed: 在SinkFinder中,仅有一对种子被使用来寻找感兴趣的函数,比如$<kmalloc,kfree>$。 但是如果同时考虑多对种子的话,也许可以找到更多的函数。
  • 检测漏洞: 本论文中仅使用了”Alloc/Free”这样的函数对来检测内存漏洞,但是像”Lock/Unlock”这样的函数对也可以用来检测死锁之类的漏洞。
  • 引入过程间分析: SinkFinder进行的是过程内分析来发现感兴趣的函数对,若引入过程间分析的话,可能会发现更多的函数对。