最近爆出来的 Intel CPU 的底层漏洞可谓是影响巨大,过去20年的电脑都可能会受影响。前几天 Raspberry Pi 的官方 Twitter(@Raspberry_Pi) 转推了这篇文章,通过简单的 Python 程序分析了各种硬件术语和漏洞攻击模式,内容简单易懂,看后神清气爽。今天抽空将其翻译,分享给大家。本人英语也不算太好,对着百度磕磕绊绊的翻译了出来,如有错误请多多包涵。——2018年1月8日

原文地址:https://www.raspberrypi.org/blog/why-raspberry-pi-isnt-vulnerable-to-spectre-or-meltdown

在过去的几天里,有许多关于一对叫 Spectre 和 Meltdown 的安全漏洞的讨论。这影响到所有近代的英特尔处理器,许多AMD处理器(在 Spectre 漏洞下)和 ARM 核心。 Spectre 允许攻击者绕过软件检查,去读取当前地址空间中任意位置的数据; Meltdown 允许攻击者去读取操作系统内核地址空间中(通常对用户程序不可访问)任意位置的数据。

这两个漏洞利用许多现代处理器常见的性能特征(缓存和预测执行),通过所谓的侧信道攻击(side-channel attack)来泄漏数据。幸运的是,树莓派不会受到这些漏洞的影响,因为我们使用特别的(particular)ARM 内核。

为了帮助我们理解为什么,这里有一点关于现代处理器设计中的一些概念。我们将使用像下面那样的简单的 Python 程序去说明这些概念:

t = a+b
u = c+d
v = e+f
w = v+g
x = h+i
y = j+k

虽然计算机中的处理器不直接执行 Python ,但这里的语句很简单,它们大致相当于一个机器指令。我们将详细介绍一些细节(尤其是流水线(pipelining)和寄存器重命名(register renaming)),这对于处理器设计者来说非常重要,但并不是理解 Spectre 和 Meltdown 所必须的。

为了综合描述处理器设计和现代计算机体系结构的其他方面,你不能做得比 Hennessy and Patterson’s classic Computer 体系结构更好:一种定量方法。(原文:you can’t do better than Hennessy and Patterson’s classic Computer Architecture: A Quantitative Approach.

什么是标量处理器

最简单的现代处理器每周期执行一条指令,我们称之为标量处理器(scalar processor)。上面的示例将在标量处理器上以六个周期执行。

标量处理器的例子包括 Intel 486 和在 Raspberry Pi 1 与 Raspberry Pi Zero 上使用的 ARM1176 核心。

什么是超标量处理器

使标量处理器(实际上是任何处理器)运行得更快的明显方法是增加它的时钟速度(clock speed)。但是,我们很快达到了处理器内部逻辑门运行速度的极限。因此,处理器设计者开始寻找几种同时执行多个指令的方法。

顺序(in-order)超标量处理器(superscalar processor)检查传入的指令流,并尝试在一个流水线(pipelines -> pipes)中同时执行多个指令流,但要遵守指令之间的依赖关系。依赖关系很重要:你可能认为双路(two-way)超标量处理器可以结对(dual-issue)六个指令,像下面的例子一样:

t, u = a+b, c+d
v, w = e+f, v+g
x, y = h+i, j+k

但这没有意义:在计算 w 之前,我们必须计算 v ,所以第三和第四指令不能同时执行。我们的双路超标量处理器实际上不可能找到任何与第三指令相匹配的指令,所以我们的示例将以四个周期执行:

t, u = a+b, c+d
v = e+f # second pipe does nothing here
w, x = v+g, h+i
y = j+k

超标量处理器的例子包括 Intel Pentium ,在 Raspberry Pi 2 与 Raspberry Pi 3 上使用的 ARM Cortex-A7 与 Cortex-A53 核心。 Raspberry Pi 3 的时钟速度只比 Raspberry Pi 2 快了 33% ,但性能近乎翻倍:额外性能的部分原因是 Cortex-A53 的指令结对能力比 Cortex-A7 具有更广泛的指令范围。

什么是乱序处理器

回到我们的例子,我们可以看到,虽然我们在 v 和 w 之间有一个依赖项,但是在程序的后面有其他的独立指令,我们或许可以在第二个周期中用来填充流水线。乱序(out-of-order)超标量处理器具有打乱即将到来的指令的能力(遵循依赖关系),以便提高流水线的效率。

在我们的示例中,乱序处理器可能有效的交换 w 和 x 的定义:

t = a+b
u = c+d
v = e+f
x = h+i
w = v+g
y = j+k

将其以三个周期执行:

t, u = a+b, c+d
v, x = e+f, h+i
w, y = v+g, j+k

乱序处理器的例子包括 Intel Pentium 2 (绝大多数的 Intel 和 AMD x86 处理器,除了一些 Intel Atom 和 Intel Quark 设备),最新的 ARM 核心,像 Cortex-A9, -A15, -A17, and -A57 。

什么是分支预测器

上面的例子是一段顺序代码。当然,真正的程序不是这样的:它们还包含向前分支(forward branches,用于实现条件操作,如if语句)和向后分支(backward branches,用于实现循环)。分支可能是无条件的(总是执行),或条件的(是否执行取决于计算值)。

在获取指令时,处理器可能遇到依赖于尚未计算值的条件分支。为了避免停顿,处理器必须猜测下一个要取的指令:在内存中的一个指令(对应不执行分支),或分支目标中的一个(对应执行分支)。分支预测器(branch predictor)可帮助处理器对是否执行分支进行智能猜测。它通过收集有关过去特定分支的执行频率的统计数据来做到这一点。

现代分支预测是非常复杂的,可以产生非常准确的预测。Raspberry Pi 3 的额外性能的部分原因是由于分支预测在 Cortex-A7 和 Cortex-A53 之间的改进。然而,通过执行精心编制的一系列分支,攻击者可以错误地训练分支预测器,从而做出糟糕的预测。

什么是推测

重排(reordering)顺序指令是使更多指令级并行的强有力方法,但是随着处理器变得更强大(能够将三或四个指令结对),要使所有这些流水线忙起来变得困难。因此,现代处理器推测(speculation)的能力也变得更强。推测执行允许我们发出可能不需要的指令(因为代码可能会存在分支),这会使流水线保持繁忙(使用或丢弃),如果结果表明该指令未被执行,我们就可以将其丢弃。

推测执行不必要的指令(底层需要支持推测和重排)消耗额外的时间,但在许多情况下,这被认为是获得额外单线程性能的一个合算的折衷。分支预测器被用来选择程序最可能的路径,最大限度地提高推测的回报。

为了演示推测的好处,让我们看看另一个例子:

t = a+b
u = t+c
v = u+d
if v:
w = e+f
x = w+g
y = x+h

现在我们有了从 t 到 u 到 v ,从 w 到 x 到 y 的依赖关系,所以没有推测的双路乱序处理器永远不能填满它的第二个流水线。处理器花费三个周期计算 t 、 u 和 v ,之后将知道 if 语句的主体部分是否执行,在执行 if 语句主体的情况下,再花费三个周期计算 w 、 x 和 y 。假设 if 语句(由一个分支指令实现)需要一个周期,我们的示例将花费四个周期(如果 v 为 0)或七个周期(如果 v 为非 0)。

如果分支预测器表明该 if 语句体可能执行,经推测有效地打乱后的程序是这样的:

t = a+b
u = t+c
v = u+d
w_ = e+f
x_ = w_+g
y_ = x_+h
if v:
w, x, y = w_, x_, y_

因此我们现在有了额外的指令并行来保持我们的流水线繁忙:

t, w_ = a+b, e+f
u, x_ = t+c, w_+g
v, y_ = u+d, x_+h
if v:
w, x, y = w_, x_, y_

循环计数在推测乱序处理器中定义不太好(原文:Cycle counting becomes less well defined in speculative out-of-order processors),但 w 、 x 和 y 的分支和条件更新是大约不占用时间的,所以我们的示例大约在三个周期中执行。

什么是缓存

在过去的好日子里,处理器的速度与内存访问速度匹配得很好。我的 BBC Micro 有 2MHz ,执行一条指令大约 2μs ,存储周期(memory cycle time)为 0.25μs 。在接下来的35年里,处理器已经变得很快,但内存还仅仅是那样。在 Raspberry Pi 3 中的一个 Cortex-A53 核心,执行一条指令大约 0.5ns ,但可能需要多达 100ns 去访问主存。

乍一看,这听起来像一个灾难:我们每次访问内存,要等待 100ns 后才得到结果返回。下面这个例子需要花费 200ns :

a = mem[0]
b = mem[1]

然而,在实际中,程序倾向于以相对可预测的方式去访问内存,同时显示时间局部性(temporal locality ,如果我访问一个位置,我很可能很快就会再次访问它)和空间局部性(spatial locality ,如果我访问一个位置,我很可能很快就会访问它附近的位置)。缓存利用了这些特性,以减少访问内存的平均成本。

缓存是一个容量小的芯片存储器,靠近处理器,存储最近使用的地址(及其附近)的内容的副本,以便它们在后续访问中很快可用。有了缓存,上面的例子会执行一个多 100ns :

a = mem[0]    # 100ns delay, copies mem[0:15] into cache
b = mem[1] # mem[1] is in the cache

从 Spectre 和 Meltdown 的角度来看,重要的一点是,如果能够计算内存访问的时间,就可以判定所访问的地址是否在缓存。

什么是侧信道

维基百科zh-cn

侧信道攻击(英语:Side-channel attack)是一种攻击方式,它基于从密码系统的物理实现中获取的信息而非暴力破解法或是算法中的理论性弱点(较之密码分析)。例如:时间信息、功率消耗、电磁泄露或甚是声音可以提供额外的信息来源,这可被利用于进一步对系统的破解。

Spectre 和 Meltdown 是侧信道攻击, 它推断出内存位置的内容, 而内存位置通常不应使用定时来观察当前缓存中是否存在另一个可访问的位置。

综上所述

现在让我们来看看推测和缓存是如何结合在一起去允许一个像 Meltdown 的对处理器的攻击。考虑下面的例子,这是一个用户程序,从一个非法(内核)地址读取,导致一个错误(崩溃):

t = a+b
u = t+c
v = u+d
if v:
w = kern_mem[address] # if we get here, fault
x = w&0x100
y = user_mem[x]

现在,如果我们能训练分支预测器相信 v 可能是非 0 的,我们双路乱序超标量处理器将会这样打乱程序:

t, w_ = a+b, kern_mem[address]
u, x_ = t+c, w_&0x100
v, y_ = u+d, user_mem[x_] if v:
# fault
w, x, y = w_, x_, y_ # we never get here

即使处理器总是从内核地址地读取, 它也必须延迟所产生的错误, 直到它知道 v 是非零的。从表面上看,这感觉很安全,因为:

  • v 为零,因此非法读取的结果不会被提交到 w
  • v 为非零,但在将读取提交到 w 之前发生故障

但是,假设我们在执行代码之前清空缓存,并排列 a、b、c 和 d, 以便 v 实际上是零。现在,在第三周期中推测读取

v, y_ = u+d, user_mem[x_]

将访问用户地址 0x000 或地址 0x100 ,具体取决于非法读取的结果的第八位,将该地址及其附近加载到缓存中。由于 v 为零,因此将丢弃推测性指令的结果,并继续执行。如果我们对其中一个地址进行后续访问, 我们就可以确定哪个地址在缓存中。恭喜你,你刚刚从内核的地址空间读取了一位!

真正的 Meltdown 利用比这更为复杂(特别是为了避免错误地训练分支预测器,作者更愿意无条件地执行非法读取并处理结果异常),但原理是一样的。 Spectre 使用类似的方法来颠覆软件数组边界检查。

结论

现代处理器不遗余力地保持抽象,即它们是直接访问存储器的顺序的标量机器。而实际上使用许多技术,包括缓存、指令重排和推测,可以提供比简单处理器更高的性能。 Meltdown 和 Spectre 是我们在抽象的背景下对安全进行推理的例子,然后在抽象和现实之间遇到细微的差异。

在 Raspberry Pi 中,ARM1176、Cortex-A7 和 Cortex-A53 核心的缺少推测功能使我们对这种类型的攻击免疫。

为什么树莓派不会受到 Spectre 和 Meltdown 攻击的更多相关文章

  1. Meltdown攻击

    Meltdown攻击处理器A级漏洞MELTDOWN(熔毁)和SPECTRE(幽灵)分析报告AntiyLabs • 2018年01月05日 • 漏洞 • 阅读 1162一.概述安天应急处理中心在2018 ...

  2. CPU Meltdown和Spectre漏洞分析

    一.背景: 1月4日,国外爆出了整个一代处理器都存在的灾难性漏洞:Meltdown和Spectre. 几乎影响了全球20年内所有cpu处理器:这两个漏洞可以使攻击者通过利用并行运行进程的方式来破坏处理 ...

  3. Intel重大漏洞之Meltdown和Spectre

    史上最大漏洞危机:影响所有 iPhone.Android.PC 设备,修复困难重重 近日,英特尔的日子可并不好过. 作为全球知名芯片制造商,任何有关英特尔芯片漏洞的问题都会导致全球上百万设备遭受牵连. ...

  4. intel:spectre&Meltdown侧信道攻击(一)

    只要平时对安全领域感兴趣的读者肯定都听过spectre&Meltdown侧信道攻击,今天简单介绍一下这种攻击的原理( https://www.bilibili.com/video/av1814 ...

  5.  Meltdown论文翻译【转】

    转自:http://www.wowotech.net/basic_subject/meltdown.html#6596 摘要(Abstract) The security of computer sy ...

  6. 史上最大的CPU Bug(幽灵和熔断的OS&SQLServer补丁)

    背景 最近针对我们的处理器出现了一系列的严重的bug.这种bug导致了两个情况,就是熔断和幽灵. 这就是这几天闹得人心惶惶的CPU大Bug.消息显示,以英特尔处理器为代表的现代CPU中,存在可以导致数 ...

  7. Linux 进入 5.0 时代!

    Linux 进入 5.0 时代! 为什么 Linux 4.2 之后的版本不再是 4.21 而是 5.0? 如果你非要一个理由,那就是因为 Linux 4.x 的版本如今用手指与脚趾加在一起都要数不过来 ...

  8. Babylon.js官方性能优化文档中文翻译

    在这里列出Babylon.js官方性能优化文档的中英文对照,并在CardSimulate项目里对其中的一些优化方法进行实践. How To 如何 Optimize your scene 优化你的场景 ...

  9. 【转帖】漏洞数量242:15,英特尔和AMD CPU谁更安全?

    漏洞数量242:15,英特尔和AMD CPU谁更安全? http://www.eetop.cn/cpu_soc/6946340.html 越来越多的用户开始怀疑哪种处理器可以最好地保护他们的计算机,数 ...

随机推荐

  1. axure扫盲

    axure扫盲 zhuyuansj   2017.10.18 20:39* 字数 162 阅读 25评论 2喜欢 3 编辑文章 坐我旁边的前端今天正好初学axure,然后我就顺便学了几招比较基础的,这 ...

  2. Python的用户交互程序及格式化输出

    1.  用户输入 在Python 3 中,用户输入用input()函数即可实现用户交互程序. 例如,我们根据程序提示输入用户名和密码,并且打印输入的信息. 2. 字符串格式化输出 例如,我们根据程序提 ...

  3. Apache OFBiz源码解读之MVC模型

    节点解析 request-map 你可以将其理解为controller的配置,如果你了解或使用过struts的配置或springmvc的annotation,就会发现这个定义跟它们是很相似的: [ht ...

  4. Java----list常用方法汇总

    package ListTest; import java.util.ArrayList; import java.util.Iterator ; import java.util.List; /** ...

  5. 读《淘宝技术这十年》 总结下web架构的发展

    关键词就两 分布式 缓存 分布式 数据库,应用服务器等的多节点部署,数据库的读写分离,剥离文件系统 缓存 数据缓存 静态页面缓存 php时代 最初LAMP起步 并将数据库做读写分离,拆分为主库+从库 ...

  6. 机器学习——深度学习(Deep Learning)

    Deep Learning是机器学习中一个非常接近AI的领域,其动机在于建立.模拟人脑进行分析学习的神经网络,近期研究了机器学习中一些深度学习的相关知识,本文给出一些非常实用的资料和心得. Key W ...

  7. redis参数配置说明

    参数说明redis.conf 配置项说明如下:1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程  daemonize no2. 当Redis以守护进程方式运行 ...

  8. 项目实战12.1—企业级监控工具应用实战-zabbix安装与基础操作

    无监控,不运维.好了,废话不多说,下面都是干货. 警告:流量党勿入,图片太多!!! 项目实战系列,总架构图 http://www.cnblogs.com/along21/p/8000812.html ...

  9. Springboot 之 解决IDEA读取properties配置文件的中文乱码问题

    问题描述 当在.properties的配置文件中有中文时,读取出来的总是乱码.比如我的application.properties配置文件的内容如下: server.port=9090 test.ms ...

  10. atom添加eslint插件

    在atom编辑器里添加插件,操作步骤如下:以atom-ide-vue插件为例 //切换到插件目录cd /Users/name/.atom/packages //将需要下载插件的源代码拉下来git cl ...