共计 12237 个字符,预计需要花费 31 分钟才能阅读完成。
对于本文
2018 年的第二天 Meltdown 和 Spectre 破绽在计算机界如同放了一个核弹,IT 码农们都炸开了锅,各大厂商的各路大神都在挑灯夜战的做各种测试和打补丁,各路技术爱好者也纷纷在微信群中热烈探讨破绽的技术问题和研读论文。
本文是猫王大神(Xiao Grangrong)同学花了一个周末工夫,参考了各路的论文和材料撰写进去,心愿对喜爱技术的各位朋友能有一丁点的帮忙,感激猫王大神的精彩文章。
本文作者简介:
Xiao Guangrong:Linux 内核、KVM/QEMU 社区外围开发者和维护者。
注释
2018 年或者注定就是不平庸的一年,这一年刚开始就爆进去两个硬件设计级别的破绽,其影响之深令人咋舌。破绽之一是 Meltdown,目前发现 Intel CPU 和 ARM Cortex A75 受影响。其次是 Spectre,其影响了简直全副支流 CPU 包含 Intel,AMD,ARM (IBM CPU 是否受影响还未知)。破绽爆出之后,简直所有媒体都在做铺天盖地的报道,科技公司也在颁布各自的解决方案和修改日期。然而因为技术背景参差不齐,有些报道没有说到点子上,令人哭笑不得。
本文的次要材料来源于各论文 3 与以及相干的 Blog1,其次补充了这些材料中有所疏忽或者是互相冲突的中央。因为篇幅起因,在这一篇文章里次要剖析了 Meltdown。在后续的文章里再来剖析 Spectre。
- 背景常识
在深入分析 Meltdown 之前,咱们须要理解一些背景常识。它包含 CPU Cache,CPU 指令执行,操作系统地址空间隔离的设计。接下来咱们顺次来看这些知识点。
1.1 CPU Cache
古代处理器执行指令的瓶颈曾经不在 CPU 端,而是在内存拜访端。因为 CPU 的处理速度要远远大于物理内存的访问速度,所以为了加重 CPU 期待数据的工夫,在古代处理器设计中都设置了多级的 cache 单元。
图 1 经典处理器的存储构造
如图 1 所示,一个领有 2 个 CPU 的零碎, 每个 CPU 有两个 Core, 每个 Core 有两个线程的 Cache 架构。每一个 Core 有独自的 L1 cache, 它由其中的线程所共享, 每一个 CPU 中的所有 Core 共享同一个 L2 Cache 和 L3 Cache。
L1 cache 最靠近处理器外围,因而它的访问速度也是最快的,当然它的容量也是最小的。CPU 拜访各级的 Cache 速度和提早是不一样的,L1 Cache 的提早最小,L2 Cache 其次,L3 Cache 最慢。
上面是 Xeon 5500 Series 的各级 cache 的拜访提早:(依据 CPU 主频的不同,1 个时钟周期代表的工夫也不一样,在 1GHz 主频的 CPU 下,一个时钟周期大略是 1 纳秒,在 2.1GHz 主频的 CPU 下,拜访 L1 Cache 也就 2 个纳秒)。
表 1:各级存储构造的拜访提早
拜访类型 提早
L1 cache 命中 约 4 个时钟周期
L2 cache 命中 约 10 个时钟周期
L3 cache 命中 约 40 个时钟周期
拜访本地 DDR 约 60 纳秒
拜访远端内存节点 DDR 约 100 纳秒
如表 1 所示,咱们能够看到各级内存拜访的提早有很大的差别。CPU 拜访一块新的内存时,它会首先把蕴含这块内存的 Cache Line 大小的内容获取到 L3 Cache,而后是载入到 L2 Cache,最初载入到了 L1 Cache。这个过程须要拜访主存储器,因而提早会很大,大概须要几十纳秒。当下次再读取雷同一块数据的时候间接从 L1 Cache 里取数据的话,这个提早大概只有 4 个时钟周期。当 L1 Cache 满了并且有新的数据要进来,那么依据 Cache 的置换算法会抉择一个 Cache line 置换到 L2 Cache 里,L3 Cache 也是同样的情理。
1.2 cache 攻打
咱们曾经晓得同一个 CPU 上的 Core 共享 L2 cache 和 L3 Cache, 如果内存曾经被缓存到 CPU cache 里, 那么同一个 CPU 的 Core 就会用较短的工夫取到内存里的内容, 否则取内存的工夫就会较长。两者的工夫差别非常明显(大概有 300 个 CPU 时钟周期), 因而攻击者能够利用这个工夫差别来进行攻打。
来看上面的示例代码:
1: clflush for user_probe[]; // 把 user_probe_addr 对应的 cache 全副都 flush 掉
2: u8 index = (u8 ) attacked _mem_addr; // attacked_mem_addr 寄存被攻打的地址
3: data = user_probe_addr[index * 4096]; // user_probe_addr
寄存攻击者能够放拜访的基地址
user_probe_addr[]是一个攻击者能够拜访的, 255 * 4096 大小的数组。
第 1 行, 把 user_probe_addr 数组对应的 cache 全副革除掉。
第 2 行, 咱们设法拜访到 attacked_mem_addr 中的内容. 因为 CPU 权限的爱护, 咱们不能间接获得外面的内容, 然而能够利用它来造成咱们能够察看到影响。
第 3 行, 咱们用拜访到的值做偏移, 以 4096 为单位, 去拜访攻击者有权限拜访的数组, 这样对应偏移处的内存就能够缓存到 CPU cache 里。
这样, 尽管咱们在第 2 行处拿到的数据不能间接看到, 然而它的值对 CPU cache 曾经造成了影响。
接下来能够利用 CPU cache 来间接拿到这个值. 咱们以 4096 为单位顺次拜访 user_probe_addr 对应内存单位的前几个字节, 并且测量这该次内存拜访的工夫, 就能够察看到工夫差别, 如果拜访工夫短, 那么能够揣测访内存曾经被 cache, 能够反推出示例代码中的 index 的值。
在这个例子里, 之所以用 4096 字节做为拜访单位是为了防止内存预读带来的影响, 因为 CPU 在每次从主存拜访内存的时候, 依据局部性原理, 有可能将邻将的内存也读进来。Intel 的开发手册上指明 CPU 的内存预取不会跨页面, 而每个页面的大小是 4096。
Meltdown[3]论文中给出了他们所做试验的后果, 援用如下:
图 2 cache 攻打数据比照
据此, 他们反推出 index 的值为 84。
1.3 指令执行
经典处理器架构应用五级流水线:取指(IF)、译码(ID)、执行(EX)、数据内存拜访(MEM)和写回(WB)。
古代处理器在设计上都采纳了超标量体系结构(Superscalar Architecture)和乱序执行(Out-of-Order)技术,极大地提高了处理器计算能力。超标量技术可能在一个时钟周期内执行多个指令,实现指令级的并行,无效进步了 ILP(InstructionLevel Parallelism)指令级的并行效率,同时也减少了整个 cache 和 memory 层次结构的实现难度。
在一个反对超标量和乱序执行技术的处理器中,一条指令的执行过程被合成为若干步骤。指令首先进入流水线(pipeline)的前端(Front-End),包含预取(fetch)和译码(decode),通过散发(dispatch)和调度(scheduler)后进入执行单元,最初提交执行后果。所有的指令采纳程序形式(In-Order)通过前端,并采纳乱序的形式进行发射,而后乱序执行,最初用程序形式提交后果。若是一条存储读写指令最终后果更新到 LSQ(Load-StoreQueue)部件。LSQ 部件是指令流水线的一个执行部件,能够了解为存储子系统的最高层,其上接管来自 CPU 的存储器指令,其下连贯着存储器子系统。其次要性能是将来自 CPU 的存储器申请发送到存储器子系统,并解决其下存储器子系统的应答数据和音讯。
图 3 经典 x86 处理器架构
如图 3 所示,在 x86 微处理器经典架构中,指令从 L1 指令 cache 中读取指令,L1 指令 cache 会做指令加载、指令预取、指令预解码,以及分支预测。而后进入 Fetch& Decode 单元,会把指令解码成 macro-ops 微操作指令,而后由 Dispatch 部件散发到 Integer Unit 或者 Float Point Unit。Integer Unit 由 Integer Scheduler 和 Execution Unit 组成,Execution Unit 蕴含算术逻辑单元(arithmetic-logic unit,ALU)和地址生成单元(address generation unit,AGU),在 ALU 计算实现之后进入 AGU,计算无效地址结束后,将后果发送到 LSQ 部件。LSQ 部件首先依据处理器零碎要求的内存一致性(memory consistency)模型确定拜访时序,另外 LSQ 还须要解决存储器指令间的依赖关系,最初 LSQ 须要筹备 L1 cache 应用的地址,包含无效地址的计算和虚实地址转换,将地址发送到 L1 DataCache 中。
1.4 乱序执行(out-of-order execution)
方才提到了古代的处理器为了进步性能,实现了乱序执行(Out-of-Order,OOO)技术。在古老的处理器设计中,指令在处理器外部执行是严格依照指令编程程序的,这种处理器叫做程序执行的处理器。在程序执行的处理器中,当一条指令须要拜访内存的时候,如果所须要的内存数据不在 Cache 中,那么须要去拜访主存储器,拜访主存储器的速度是很慢的,那么这时候程序执行的处理器会进行流水线执行,在数据被读取进来之后,而后流水线才持续工作。这种工作形式大家都晓得肯定会很慢,因为前面的指令可能不须要等这个内存数据,也不依赖以后指令的后果,在期待的过程中能够先把它们放到流水线下来执行。所以这个有点像在火车站排队买票,正在买票的人发现钱包不见了,正在焦急找钱,可是前面的人也必须停下来等,因为不能插队。
1967 年 Tomasulo 提出了一系列的算法来实现指令的动静调整从而实现乱序执行,这个就是驰名的 Tomasulo 算法。这个算法的外围是实现一个叫做寄存器重命名(Register Rename)来打消寄存器数据流之间依赖关系,从而实现指令的并行执行。它在乱序执行的流水线中有两个作用,一是打消指令之间的寄存器读后写相干(Write-after-Read,WAR)和写后写相干(Write-after-Write,WAW);二是当指令执行产生例外或者转移指令猜想谬误而勾销前面的指令时,可用来保障现场的准确。其思路为当一条指令写一个后果寄存器时不间接写到这个后果寄存器,而是先写到一个两头寄存器过渡,当这条指令提交时再写到后果寄存器中。
通常处理器实现了一个对立的保留站(reservationstation),它容许处理器把曾经执行的指令的后果保留到这里,而后在最初指令提交的时候会去做寄存器重命名来保障指令程序的正确性。
如图 3 所示,经典的 X86 处理器中的“整数重命名”和“浮点重命名”部件(英文叫做 reorder buffer,简称 ROB),它会负责寄存器的调配、寄存器重命名以及指令抛弃(retiring)等作用。
x86 的指令从 L1 指令 cache 中预取之后,进入前端解决局部(Front-end),这里会做指令的分支预测和指令编码等工作,这里是程序执行的(in-order)。指令译码的时候会把 x86 指令变成泛滥的微指令(uOPs),这些微指令会依照程序发送到执行引擎(Execution Engine)。执行引擎这边开始乱序执行了。这些指令首先会进入到重命名缓存(ROB)里,而后 ROB 部件会把这些指令经由调度器单元产生到各个执行单元(Execution Unit,简称 EU)里。假如有一条指令须要拜访内存,这个 EU 单元就进行期待了,然而前面的指令不须要停顿下来等这条指令,因为 ROB 会把前面的指令发送给闲暇的 EU 单元,这样就实现了乱序执行。
如果用高速公路要做比喻的话,多发射的处理器就像多车道一样,汽车不须要依照发车的程序在高速公路上按程序执行,它们能够随便超车。一个形象的比喻是,如果一个汽车抛锚了,前面的汽车不须要排队等待这辆汽车,能够超车。
在高速公里的起点设置了一个很大的停车场,所有的指令都必须在停车场里等待,而后停车场里有设置了一个进口,所有指令从这个进口进来的时候必须依照指令本来的程序,并且指令在进口的时候必须进行写寄存器操作。这样从进口的角度看,指令就是依照原来的逻辑程序一条一条进来并且写寄存器。
这样从处理器角度看,指令是程序发车,乱序超车,程序离队。那么这个停车场就是 ROB,这个缓存机制能够称为保留站(reservation station),这种乱序执行的机制就是人们常说的乱序执行。
1.5 地址空间
古代的处理器为了实现 CPU 的过程虚拟化,都采纳了分页机制,分页机制保障了每个过程的地址空间的隔离性。分页机制也实现了虚拟地址到物理地址的转换,这个过程须要查问页表,页表能够是多级页表。那么这个页表除了实现虚拟地址到物理地址的转换之外还定义了拜访属性,比方这个虚构页面是只读的还是可写的还是可执行的还是只有特权用户能力拜访等等权限。
每个过程的虚拟地址空间都是一样的,然而它映射的物理地址是不一样的,所以每一个过程都有本人的页表,在操作系统做过程切换的时候,会把下一个过程的页表的基地址填入到寄存器,从而实现过程地址空间的切换。以外,因为 TLB 里还缓存着上一个过程的地址映射关系,所以在切换过程的时候须要把 TLB 对应的部份也革除掉。
当过程在运行的时候不可避免地须要和内核交互,例如零碎调用,硬件中断。当陷入到内核后,就须要去拜访内核空间,为了防止这种切换带来的性能损失以及 TLB 刷新,古代 OS 的设计都把用户空间和内核空间的映射放到了同一张页表里。这两个空间有一个显著的分界线,在 Linux Kernel 的源码中对应 PAGE_OFFSET。
图 4 过程地址空间
如图 4 所示,尽管两者是在同一张页表里,然而他们对应的权限不一样,内核空间部份标记为仅在特权层能够拜访,而用户空间部份在特权层与非特权层都能够拜访。这样就完满地把用户空间和内核空间隔离开来:当过程跑在用户空间时只能拜访用户空间的地址映射,而陷入到内核后就即能够拜访内核空间也能够拜访用户空间。
对应地,页表中的用户空间映射部份只蕴含本机程能够拜访的物理内存映射,而任意的物理内存都有可能会被映射到内核空间局部。
1.5 异样解决
CPU 指令在执行的过程过有可能会产生异样,然而咱们的处理器是反对乱序执行的,那么有可能异样指令前面的指令都曾经执行了,那怎么办?
咱们从处理器外部来考查这个异样的产生。操作系统为了解决异样,有一个要求就是,当异样产生的时候,异样产生之前的指令都曾经执行实现,异样指令前面的所有指令都没有执行。然而咱们的处理器是反对乱序执行的,那么有可能异样指令前面的指令都曾经执行了,那怎么办?
那么这时候 ROB 就要起到清道夫的作用了。从之前的介绍咱们晓得乱序执行的时候,要批改什么货色都通过两头的寄存器临时记录着,等到在 ROB 排队进来的时候才真正提交批改,从而保护指令之间的程序关系。那么当一条指令产生异样的时候,它就会带着异样“宝剑”来到 ROB 中排队。ROB 按程序把之前的失常的指令都提交发送进来,当看到这个带着异样“宝剑”的指令的时候,那么就启动应急预案,把进口封闭了,也就是异样指令和其前面的指令会被抛弃掉,不提交。
然而,为了保障程序执行的正确性,尽管异样指令前面的指令不会提交,可是因为乱序执行机制,前面的一些访存指令曾经把物理内存数据预取到 cache 中了,这就给 Meltdown 破绽留下来前面,尽管这些数据会最终被抛弃掉。
2.Meltdown 剖析
上面咱们对 Meltdown 破绽做一些原理性的剖析和后续修补的计划。
2.1 破绽剖析
了解了上述的背景常识当前就能够来看 Meltdown 是怎么回事了. 咱们再回过头看看下面的例子:
1: clflush for user_probe[]; // 把 user_probe_addr 对应的 cache 全副都 flush 掉
2: u8 index = (u8 ) attacked _mem_addr; // attacked_mem_addr 寄存被攻打的地址
3: data = user_probe_addr[index * 4096]; // user_probe_addr 寄存攻击者能够放拜访的基地址
如果 attached_mem_addr 位于内核, 咱们就能够利用它来读取内核空间的内容。
如果 CPU 程序执行, 在第 2 行就会发现它拜访了一个没有权限地址, 产生 page fault (缺页异样), 进而被内核捕捉, 第 3 行就没有机会运行。可怜的是, CPU 会乱序执行, 在某些条件满足的状况下, 它获得了 attacked _mem_addr 里的值, 并在 CPU 将该指令标记为异样之前将它传递给了下一条指令, 并且随后的指令利用它来触发了内存拜访。在指令提交的阶段 CPU 发现了异样, 再将曾经乱序执行指令的后果抛弃掉。这样尽管没有对指令的正确性造成影响, 然而乱序执行产生的 CPU cache 影响仍然还是在那里, 并能被利用。
该场景有个前置条件,该条件在 Meltdown[3]的论文里没有被提到,但在 cyber[1] 的文章指出,attached_mem_addr 必须要曾经被缓存到了 CPU L1,因为这样才会有可能在 CPU 将指令标记为异样之前指数据传给后续的指令。并且 cyber 指出,只有 attacked_mem_addr 曾经被缓存到 CPU L1 才有可能胜利,在 L2,L3 均不行,其理由是:
“The L1 Cache is a so called VIPT or Virtually Indexed, PhysicallyTagged cache. This means the data can be looked up by directly using thevirtual address of the load request”
“If the requested data was not found in the L1 cache the load must bepassed down the cache hierarchy. This is the point where the page tables comeinto play. The page tables are used to translate the virtual address into aphysical address. This is essentially how paging is enabled on x64. It isduring this translation that privileges are checked”
这几点理由很值得商讨:
1) AMD 的开发手册 [10] 没有找到 L1 cache 是 VIPT 的证据,Intel 的开发手册 [9] 上只能从”L1 Data Cache Context Mode”的形容上揣测 NetBurst 架构的 L1 cache 是 VIPT 的。
2) 就算 L1 cache 是 VIPT,那也须要取得 physicaladdress,必然会用到 TLB 里的内容或者进行页表的遍历。
那么如何来将要被攻打的内存缓存到 L1 里呢? 有两种办法:
1) 利用零碎调用进入内核。如果该零碎调用的门路拜访到了该内存,那么很有可能会将该内存缓存到 L1 (在 footprint 不大于 L1 大小的状况下)。
2) 其次是利用 prefetch 指令。有钻研 [8] 显示,Intel 的 prefetch 指令会齐全疏忽权限查看,将数据读到 cache。
咱们晓得,如果过程触发了不可修复的 page fault,内核会向其发送 SIGSEGV 信号,而不能持续往下执行。所以这里有两种操作方法,其一是创立一个子过程,在子过程中触发上述的代码拜访,而后在父过程中去测算 user_probe_addr[]的拜访工夫。所以每一次探测都须要另起一个新过程,这样会影响效率。
另一种办法是利用 Intel 的事务内存解决(Intel®Transactional Synchronization Extensions),该机制以事务为单元来对一系列内存操作做原子操作,如果一个事务内的内存操作全副胜利实现且没有其它 CPU 造成内存的竞争,那么就会将该事务对应的后果进行提交,否则将中断该事务。如果咱们将上述代码蕴含到一个内存事务中,对被攻打地址的拜访并不会造成 pagefault,只会被打断事务。这样咱们能够在不须要生成子过程的条件下继续进行攻打。
这里有一个很有意思的景象,上述代码在第 2 行处读到的 index 有时会全为 0,不同的材料有不同的解释:
1) cyber[1]给出的解释是:“Fortunately Idid not get a slow read suggesting that Intel null’s the result when the access is notallowed”。
2) google zero project[2]给出的解释是:“That (read from kernel address returns all-zeroes) seems to happen for memory that is not sufficiently cached but for which pagetable entries are present, at least after repeated read attempts. For unmapped memory, the kernel address read does not return a result at all.”
3) Meltdown paper[3]给出的解释是:“If the exception is triggered whiletrying to read from an inaccessible kernel address,the register where the data shouldbe stored,appears to bezeroed out. This is reasonable because if the exception is unhandled,the user space application isterminated,and the valuefrom the inaccessible kernel address could be observed in the register contentsstored in the core dump of the crashed process. The direct solution to fix thisproblem is to zero out the corresponding registers. If the zeroing out of theregister is faster than the execution of the sub- sequent instruction (line 5in Listing 2),the attackermay read a false value in the third step”。
这个解释比拟有意思,他们首先认为,将读到的内容清零是有必要的,否则读到的内容会保留到这个程序的 core dump 里。果真会如此么? Terminate 过程和生产 core dump 都须要 OS 去做,软件不可能间接拜访到乱序执行所拜访的寄存器。
其次他们认为,该问到 0 是因为值传递给下一条指令的速度要慢于将值清 0 的操作,所以他们的解决办法是:
“prevent the tran- sientinstruction sequence from continuing with a wrong value,i.e.,‘0’,Meltdown retries reading the address until itencounters a value different from‘0’”
所以他们的示例代码是长这样的:
图片
他们在读到 0 时现再重试. 然而, 如果真的读到清 0 的数据, retry 并不会有机会再被执行到, 因为此时很有可能异样曾经被捕捉。
2.2 破绽修复
在破绽被报告给相干厂商后,各 OS 和开源社区开始了修复工作,LinuxKernel 采纳的是 Kernelpage-table isolation (KPTI)6,据说 Windows 和 Mac OS 的修复也是相似的思路。
在后面的背景常识中看到, 以后的 OS 采纳用户空间和内核空间分段的设计, 这样使得 Kernel 和 Usersapce 应用同一张页表, 位于同一个 TLB context 中, 所以 CPU 在做预取和乱序的时候能够应用 TLB 中的 cache 做地址转换, 进而取得 CPU Cache 中的数据, 如果咱们可能让用户空间不能应用 TLB 中对于内核地址映射的信息, 这样就能够断掉用户空间对 Cache 中 kernel 数据的拜访,这也是 KPTI 的思路。
KPTI 将之前 OS 设计中, 每个过程应用一张页表分隔成了两张, kernelspace 和 userspace 应用各自拆散的页表。咱们暂且称过程在 kernel 模式应用的页表称为 Kernel 页表, 相应地过程在用户空间应用的页表被称为用户页表。
具体地来说, 当过程运行在用户空间时, 应用的是用户页表, 当产生中断或者是异样时, 须要陷入到内核, 进入内核空间后, 有一小段内核跳板将页表切换到内核页表, 当过程从 kernel 空间跳回到用户空间时, 页表再次被切换回用户页表。
Kernel 页表蕴含了过程用户空间地址的映射和 Kernel 应用的内存映射, 所以 Kernel 仍然能够应用以后过程的内存映射。用户页表仅仅蕴含了用户空间的内存映射以及内核跳板的内存映射。
2.3 性能影响
从这里能够看到, 每一次用户空间到内核空间的切换都须要切换页表, 在没有 PCID 反对的 CPU 上, 切换页表 (reload CR3) 会 flush 除了 global page 以外的所有 TLB。在反对 PCID 的状况下, 大部分利用场景的性能损失微不足道。
(上面这段是编辑增加的)
援用几大科技公司的原话能够看出性能影响微不足道:
Apple:“Our testing with public benchmarks has shown that the changes in the December 2017 updates resulted in no measurable reduction in the performance of macOS and iOS as measured by the GeekBench 4 benchmark, or in common Web browsing benchmarks such as Speedometer, JetStream, and ARES-6.”(苹果示意在 macOS 和 iOS 上没发现有性能损失)
Microsoft:“The majority of Azure customers should not see a noticeable performance impact with this update. We’ve worked to optimize the CPU and disk I/O path and are not seeing noticeable performance impact after the fix has been applied.”(微软示意在 Azure 中没看到性能影响)
Amazon:“We have not observed meaningful performance impact for the overwhelming majority of EC2 workloads.”(亚马逊说在 EC2 利用场景中没察看到性能损失)
Google:“On most of our workloads, including our cloud infrastructure, we see negligible impact on performance.”(谷歌示意在它们绝大部分的利用场景中包含云设施,都只是微不足道的性能影响)
- 总结
在这里须要指出的是, 也是所有 paper 没有提到的, 尽管在以后的 OS 的设计中, 过程在内核空间和用户空间应用的是同一张页表, 然而该页表的内核部份映射的生成是 on-demand 的, 即在拜访的时候才会被逐步映射, 因而只有在零碎调用上被 touch 到的内存才有可能被映射到页表里。所以被严格限度零碎调用的用户攻打难度会更大一些, 例如应用 seccomp,而后尽管如此, 所有的代码门路不可能齐全被审计到。
Meltdown 破绽并不需要利用已有的软件缺陷, 仅仅只需攻击者和受害者在只有一个地址空间中就会有影响, 比方基于 container 的 Docker、Xen 的 PV guest 等等。基于硬件虚拟化的 VM 并不会受其影响,然而状况不容乐观, 接下来要剖析的 Spectre 具备更大范畴的破坏力。
尽管这篇文章是以 cache 为例来形容攻打, 然而对体系体构可察看到的影响都能够拿来作为攻打的伎俩, 比方诱发 CPU 算术单元的忙碌运算后再来观突某条算术指令执行的工夫, 再如察看不同状况下的电力耗费等等。
这一次破绽的影响之大足以被写进教科书, 甚至会影响接下来所有硬件和 OS 的设计, 2018 年或者是 OS, Hardware, Security 的新起点。
参考资料
[1] Negative Result:Reading Kernel Memory From User Modehttps://cyber.wtf/2017/07/28/…
[2] Google Zero Projecthttps://googleprojectzero.blo…
[3] Meltdownhttps://meltdownattack.com/me…
[4] Spectre Attacks:Exploiting Speculative Execution https://spectreattack.com/spe…
[5] KAISER: hiding thekernel from user space https://lwn.net/Articles/738975/
[6] The current state ofkernel page-table isolation https://lwn.net/Articles/741878/
[7] Kernel page-tableisolation https://en.wikipedia.org/wiki…
[8] Prefetch Side-ChannelAttacks: Bypassing SMAP and Kernel ASLR https://gruss.cc/files/prefet…
[9] Intel® 64 and IA-32architectures software developer’s manualhttps://software.intel.com/si…
[10] AMD64 ArchitectureProgrammer’s Manual https://developer.amd.com/res…