首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

[linux][kernel]meltdown攻击和retpoline防御分析

前言: Intel爆出来的漏洞,搞了一个大新闻,然后Linus也对Intel的补丁批判了一番。 关于meltdown攻击的原理,以及retpoline防御,见下文。 分析: 1,MMU & CPU Cache & CPL & spectulative exection & Syscall 有几个关键的概念需要说明: MMU,Memory Management Unit。在CPU(本文的CPU默认是x86)跑在protected mode下的时候,使用的是虚拟地址,MMU是一个硬件,负责把虚拟地址翻译成虚拟地址。同时,也会处理一些异常情况,例如,在进程访问空指针的时候,MMU会产生异常,交给CPU处理。 CPU Cache,CPU访问内存的速度相对于CPU的主频,是比较慢的。为了加速CPU访问速度,在CPU和内存之间,有了CPU cache。在Linux上执行lscpu,可以看到L1,L2,甚至L3的大小。根据局部性原理,CPU在短时间内访问较小的地址范围,CPU cache把当前访问的地址加载到cache中,会加速CPU的访问。 CPL,Current Privilege Level。Linux使用0和3两个特权级,分别表示内核态和用户态。区别就是内核态有更高的访问权限,可以访问所有地址。用户态的权限比较低,只能访问用户态地址空间。否则,CPU就会产生异常,kernel处理异常的时候发现,访问的权限超出,给进程发送signal 11,也就是常说的segmentation fault。 spectulative exection。当代CPU大多都具有一定的预执行能力,用来提高指令的执行效率。作者曾经做过实验,在主频差不多的情况下,x86的E5和arm a53上分别跑redis,跑分结果x86差不多是arm的4倍。这里面,x86的分支预测明显是优于arm的。 Syscall,系统调用。用户态(CPL3)请求内核服务的时候,需要陷入到内核态(CPL0)。内核处理完成后,再返回用户态(CPL3)。在这期间,是有一段时间,CPU是处于内核态的。 上面的概念,是这次meltdown攻击的基础。另外,https://meltdownattack.com/meltdown.pdf 这里有一篇更加详细的论文。 2,spectulative exection

如上文的程序流,在触发了exception之后,进入内核态来处理异常,再exception handler中处理。正常的程序流中不会执行到右侧灰色的指令。但是,因为CPU的spectulative exection,灰色的指令片段会被执行CPU偷偷的执行,而且,是以内核态的权限来执行(因为它的上一条指令,触发了exception,已经进入了内核态)。 这部分灰色的代码片段,就是meltdown攻击可以做文章的地方。 3,meltdown attack 在攻击之前,在用户态声明一个数组probe_array[256][4096]。再来看下文:

把这段放到灰色的代码片段中,如果CPU投机执行了这一段会发生什么: 第1行,把想要攻击的内核地址放到rcx中;这个地址本不能被用户态访问到,但是因为exception已经陷入到内核态,这段将会以内核态权限执行。 第2行,把刚刚声明的用户态数组probe_array的地址放到rbx中; 第4行,把rcx的数值放到al中;也就说,把想要攻击的内核地址的数据,取出来1个byte,放到了al中。想必读者朋友们还记得大学时候,课本中的al表示ax的低八位,ah表示ax的高八位吧。假设这个地址的数据是0x10,也就是十进制的16。 第5行,把rax里面的数值左移12位;也就是16 × 4096。 第7行,rbx+rax的地址上的数值放到rbx中。实际上,就是访问了probe_array[16][0]这个地址。 这段代码投机执行完,看起来没有发生什么,而且,CPU的分支也会回滚掉刚刚的操作。寄存器中也不会有这段代码执行的残留。 但是!!! 因为访问过probe_array[16][0],CPU的cache中会加载过probe_array[16][0]。 如果执行下面的代码: for (index = 0; index < 256; index++) { tsc0 = rdtsc(); dummy = probe_array[indx][0]; tsc1 = rdtsc(); } 用tsc来计量更加精确的时间,会发现:只有index等于16的时候,tsc1-tsc0的会非常短,因为它可以直接命中CPU cache!!! 作者在实验环境上测试,如果命中了cache,两次tsc的差值差不多几十。而其他没有命中cache的两次tsc差值差不多是千这个量级的。根据时间的巨大差异,就能判断出来命中cache与否。这样就可以dump出来要攻击的内核地址的数据是0x10。依次类推。 作者使用PC测试的,和服务器的CPU会有差异,具体的表现上,是否命中cache,基本就是几十倍的访问速度差异。 4,retpoline 作者在前文《[linux][retpoline] retpoline技术分析》中分析了retpoline的具体实现,在结合上文的例子中,看看是如何防止meltdown攻击的。

上文攻击的重点,是灰色的代码片段的投机执行。用户在灰色代码片段中埋入攻击代码,实现的dump内核数据。那么retpoline的解决方案,就是防止灰色代码的投机执行。如下图:

打开了RETPOLINE配置之后,并不是直接执行的系统调用的handler。

而是让预测分支执行pause和lfence。 从而避免了CPU投机执行攻击的代码。同时,也避免了CPU投机执行正常的用户代码。性能会有一点点牺牲。 5,影响 以作者的愚见,对于IaaS层,升级kernel,打开retpoline是逃不掉的,毕竟公有云的安全第一。 作者在4.14上,打开RETPOLINE的前后对比测试,redis的性能下降了不到5%。因为redis是全内存性数据库,对于网络IO的处理,需要频繁的和内核进行数据交换,几乎是能受到影响的极限;其他CPU密集型的服务,影响更小。 对于SaaS服务,或者对性能要求极高的网络服务,对这个补丁的要求并不高。以http服务为例,毕竟只是提供GET,PUT,DELETE方法等,并不会执行用户的代码。例如redis,对外提供命令,同样也不会执行到用户代码。

下一篇
举报
领券