跟着白泽读paper丨Check It Again: Detecting Lacking-Recheck Bugs in OS Kernels

Check It Again: Detecting Lacking-Recheck Bugs in OS Kernels

开源项目地址:https://github.com/kengiter/lrsan

本文发表在ACM Conference on Computer and Communications Security(CCS)2018,第一作者是来自University of Minnesota的Wenwen Wang。第二作者是Kangjie Lu,发表过多篇有关内核安全的顶会文章。

主要内容

Security Checks在内核中是十分普遍的,常被用于检查敏感的或者存在漏洞风险的变量。比如,添加security check可以确保用户提供的指针不指向内核空间,确保访存用的offset不会造成越界读写等。但是在kernel的实现中,一些通过了security checks的变量在真正被使用前可能被修改,假如攻击者能够控制这种修改操作,就等同于越过了kernel的security checks。本文作者认为这样的security check是improper check,作者首次将这类问题归纳为Lacking-Recheck Bugs(后文简称为LRC),并设计了对应的检测方法,实现了开源的静态分析工具LRSan

作者在version 4.17的kernel上进行了实验,用LRSan发现了2808个潜在的LRC cases。通过两位安全研究人员约40小时的人工确认,总计发现了19个LRC Bugs,向Linux kernel开发者报告后,17个Bug被确认,其中的12个截止到投稿时已被修复。

问题定义

作者在本文中首次归纳出了LRC这类Bug,给出了正式的定义,并阐述了其与已知漏洞类型的关系。

跟着白泽读paper丨Check It Again: Detecting Lacking-Recheck Bugs in OS Kernels_第1张图片
LRC Bugs的产生

LRC Bugs的定义:

  1. 存在一条check-use chain,即存在一条执行路径包含了对security variable的检查和使用。

  2. 在check-use chain上,在检查和使用之间,必须存在对security variable的写操作。

  3. 在满足了条件(a),(b)后,在真正使用security variable时没有进行re-check。

  4. 修改用的source三类:来自于用户态与kernel的竞争;来自于当前线程和其他kernel线程的竞争;来自于当前线程的自修改。

作者归纳的Security-check的pattern:

  1. 是有2个branch的条件判断语句。

  2. 其中一条分支一定返回kernel的error code。

  3. 另一条分支一定要有可能不返回kernel的error code。

LRC Bugs与已知漏洞类型的关系:

  1. LRC Bugs是Time-of-Check-to-Time-of-Use Bugs的一个子类。

  2. LRC Bugs与Double-fetch Bug之间有交集,因为LRC Bugs同样考虑用户态和内核态之间的race。

设计与实现

本文作者主要采用静态分析的方法来检测LRC Cases:

跟着白泽读paper丨Check It Again: Detecting Lacking-Recheck Bugs in OS Kernels_第2张图片
LRSan的工作机制

核心的静态分析模块主要包含4个部分:

  1. Security-check identification。该步骤主要为了找出kernel中所有符合作者提出的Pattern的security-checks。所用的方法是,首先收集kernel中所有的error code(定义在errno.h和errno-base.h中)。为了省去繁杂的data-flow analysis,作者构建了基于error code CFG(ECFG),只关心一个function的return value,以及对return value的写操作,标记出那些将return value置为error code的block,进而在ECFG上进行security-check的检测与定位。

  2. Critical-variable identification。作者进一步基于所有找到的security checks,找到与之对应的critical variable,即敏感变量。该步骤中存在一个递归的过程,即先确认security check正在检查的变量,然后回溯得到该变量的源,之后从该源变量出发找到所有与之相关的变量,这些变量都有可能违反security check所定义的规则。

  3. Check-use chain construction。找到所有的security check和与之对应的敏感变量后,就可以遍历所有的执行路径来构造check-use chain了。

  4. Modification inference。在所有的check-use chain上确认是否存在对敏感变量的修改,同时缺乏recheck的情况,若有,则找到了一个LRC Cases。主要关注的llvm中的store指令,一直一些会包含写操作的api比如memcpy,copy_from_user等。

作者对LRSan产生false postive和false negative的原因做了相对全面的解释:

  1. False Negative。作者在本文中采用了非常strong的pattern来检测security checks,比如,假设security-check都是简单的分支指令,并且作为error-handing的分支一定会返回error code。Strong的pattern带来的好处是减少了很多静态分析的challenge,但是坏处就是不可避免的带来了False Negative,因为kernel中真实存在不符合这种pattern的security check。

  2. False Positive。产生false positive的原因较多,其中主要的3类为:(a)Checked Modification。即对敏感变量修改时的源值也是符合security check的值。(b)Satisfiable Modification。比如在range-check之后,index一直在范围内执行自增操作。(c)Uncontrollable Modification。即敏感变量被修改为定值,这种场景下攻击者难以进行bug利用,故也可认为是false positive。

评价

从结果上来说,LRSan的确找到了19个kernel bug,其贡献值得肯定。但是LRC Bugs很难被认为是一种全新的bug类型,按照作者的定义,其所涵盖的范围与已知的漏洞都有交集,如TOCTTOU,Double fetch等。同时,因为引入了有关security check非常strong的pattern,technique challenge就大幅降低了。再者,该工具最终检测出的只是LRC cases,bug的确认需要人工的干预。但总的来说,文章的概念的定义上都比较formal,结果分析全面,从漏洞发现数量上来看结果也比较可观。

文丨DJR, BlackMax, xcz


你可能感兴趣的:(跟着白泽读paper丨Check It Again: Detecting Lacking-Recheck Bugs in OS Kernels)