Linux内核eBPF verifier界线盘算过失误差剖析与使用(CVE-2021-31440)
宣布时间 2021-05-31误差配景
克日,ZDI官网披露一个Linux内核eBPF verifier界线盘算过失误差,该误差源于eBPF验证器在Linux内核中没有准确盘算64位转32位操作的寄存器界线,导致外地攻击者可以使用此缺陷举行内核信息泄露或特权提升,该误差编号为CVE-2021-31440。
影响规模与防护步伐
(1)影响规模Linux-5.7 ~ Linux- 5.11.15Ubuntu 20.10
(2)防护步伐
实时更新升级内核将kernel.unprivileged_bpf_disabled.sysctl设置为1,暂时限制通俗用户权限
误差原理与调试剖析
(1)误差原理
该误差和CVE-2020-8835,CVE-2020-27194这两个误差的原理类似,均是在32位和64位之间举行转换操作时,过失盘算了寄存器的约束界线,导致可以绕过验证器检查实现越界读写。缺陷代码泛起在kernel/bpf/verifier.c的__reg_combine_64_into_32()函数中,该函数是在commit_id:3f50f132d840中引入的,该功效实现了用64位寄存器上的已知规模来推断该寄存器低32位的规模,可是同样泛起了类似的盘算过失,该函数实现如下:

行1316,若是smin_value和smax_value都在带符号的32位整数规模内,则将响应地更新32位的带符号规模巨细,关于有符号规模来说,这种操作是准确的。接着看,在无符号规模的响应逻辑中,对umin_value和umax_value划分在行1320和行1322举行了检查。这里逻辑不准确,例如设置dreg->umin_value=1,dreg->umax_value=1<<32,即0x100000000,当举行如上操作后,reg->u32_min_value设置为1,这个是准确的,可是reg->u32_max_value却酿成了0,高位被截断。这时reg寄存器的低32位规模已经杂乱。关于验证器来说是杂乱的,可是运行态时,reg的规模是正常的。着实关于有符号界线的情形,已经举行了修改。补丁commit为:b02709587ea3,要害补丁代码如下所示:

而未对无符号界线的情形举行解决。该误差补丁中,修改为同时对umin_value和umax_value举行了判断,如下所示:

(2)调试剖析
首先将BPF_REG_7寄存器设置为1<<32,即0x10000000,并通过两个一连的NEG指令使验证器无法跟踪寄存器的规模,同时可以包管寄存器的值在运行时稳固�?梢酝ü缦翨PF指令实现:

执行到LSH指令时,如下所示:

此时BPF_REG_7寄存器的状态如下所示:

执行完LSH后,此时BPF_REG_7寄存器的状态如下图所示:

可是此时umin_value也是0x100000000,还需将umin_value设置成0x1,可以通过如下eBPF指令实现:

断点掷中后,挪用栈如下所示:

对BPF_JGE和BPF_JGT指令举行处置惩罚,这里不是32位指令操作,执行如下代码:

若是R7 >= 0x1,则验证器准确分支上,true_reg->umin_value设置为true_reg->umin_value和true_umin之间的最大值,这里设置成true_umin,为0x1。然后挪用__reg_combine_64_into_32()函数更新一下true_reg的规模。如下代码所示:

进入该函数后,首先判断有符号规模的情形,如下代码所示:

这里同时判断有符号巨细值,效果不为真,不进入if语句,因此不会修改32位的有符号巨细值,打印true_reg的状态如下所示:

然后最先判断无符号最小值的情形,效果为真,然后修改32位无符号最小值,如下代码:

由于这里脱离举行判断,可以乐成设置reg->u32_min_value为0x1。接下来判断无符号最大值,reg->umax_value为0xffffffffffffffff,大于0xffffffff。因此条件不为真,不修改reg->u32_max_value。最后true_reg的状态如下所示:

将寄存器的umin_value和u32_min_value都设置为0x1。接下来通过如下eBPF指令组合将u32_max_value也设置为0x1。如下所示:

该指令为W7<=0x1,W7为32位寄存器。掷中止点后,挪用栈如下所示:

若是W7<=0x1,接下来设置准确分支下的true_reg->u32_max_value,如下图所示:

行7200,将true_reg->u32_max_value设置为true_umax,为0x1。此时true_reg的状态如下所示:

然后挪用__reg_combine_32_into_64()函数更新true_reg的规模,如下所示:

更新规模后,最后true_reg的状态如下所示:

此时在验证器的视角中,R7寄存器的32位规模是牢靠值,为常数0x1。接下来通过如下eBPF组合将R7变换成0,如下所示:

首先通过MOV32将R7的64位规模也设置常数0x1。执行完MOV32指令后,在验证器的视角下R7寄存器的状态如下所示:

而在运行时,R7的值为1<<32,即0x100000000,低32为0,即R7的32位规模为常数0,然后通过MUL和ADD两次操作,将R7寄存器的状态转换成在验证器的视角下为0x0,在运行时为0x1,最终便可以实现越界读写。
误差复现
在Linux-5.11.0内核版本的特定测试情形中举行误差使用测试,乐成提权。

参考链接
1.https://www.zerodayinitiative.com/blog/2021/5/26/cve-2021-31440-an-incorrect-bounds-calculation-in-the-linux-kernel-ebpf-verifier
2.https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=10bf4e83167cc68595b85fd73bb91e8f2c086e36
3.https://github.com/torvalds/linux/commit/b02709587ea3d699a608568ee8157d8db4fd8cae
4.https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31440
尊龙凯官网入口起劲防御实验室(ADLab)
ADLab建设于1999年,是中国清静行业最早建设的攻防手艺研究实验室之一,微软MAPP妄想焦点成员,“黑雀攻击”看法首推者。阻止现在,ADLab已通过CVE累计宣布清静误差近1100个,通过 CNVD/CNNVD累计宣布清静误差1000余个,一连坚持国际网络清静领域一流水准。实验室研究偏向涵盖操作系统与应用系统清静研究、智能终端清静研究、物联网智能装备清静研究、Web清静研究、工控系统清静研究、云清静研究。研究效果应用于产品焦点手艺研究、国家重点科技项目攻关、专业清静服务等。



京公网安备11010802024551号