对Meltdown进行技术深度研究,是否有效?

崩溃彻底席卷了互联网。 攻击看起来非常简单而优雅,但是白皮书中没有列出有关特定漏洞的关键细节。 它主要依赖于高速缓存定时辅助通道和访问全局映射内核页面的推测执行的组合。

这次深入学习假定您对CPU架构和OS内核行为有所了解。 首先阅读背景部分 ,以获取有关分页和内存保护的入门知识。

简化版的攻击:

  1. 推测性内存读取到内核映射的(主管)页面,然后对值进行计算。
  2. 根据计算结果有条件地从内存向其他一些非缓存位置发出负载。
  3. 尽管第二次加载将在故障异常退出时从管道中取消,但它已经向L2 $发出了加载请求,并且确保未完成的内存请求仍像预取一样将行带入缓存层次结构。
  4. 最后,一个单独的过程可以将负载发布到那些相同的内存位置,并测量这些负载的时间。 缓存命中将比缓存未命中要快得多,后者可用于表示二进制1(即命中)和二进制0(即未命中)。

第1部分和第2部分与推测性执行指令有关,而第3部分和第4部分则使微体系结构状态(即是否在缓存中)提交到体系结构状态。

攻击可信吗?

Meltdown白皮书中未指定的是特定的x86指令序列或CPU状态可以使内存访问以推测方式执行,并允许向量或整数单位使用该值。 或L2 $。 在现代的Intel CPU中,当发生诸如页面错误之类的故障时,直到违规指令退出之前,流水线才会被挤压/压扁。 但是,在加载甚至在L1D $中查找或进入内存之前,都会在所谓的地址生成(AGU)阶段和TLB查找阶段对页保护,分段限制和规范检查进行内存许可检查。 在下面的更多内容。

执行内存权限检查

英特尔CPU实现了带有物理标记的 L1D $和L1I $,这需要先将线性(虚拟)地址转换为物理地址,然后L1D $才能通过标记匹配确定它是否在缓存中命中或未命中。 这意味着CPU将尝试在(翻译后备缓冲区)TLB缓存中查找翻译。 TLB将这些转换以及页面表或页面目录权限一起缓存(访问页面所需的特权也与物理地址转换一起存储在页面表中)。

TLB条目可能包含以下内容:

  • 有效
  • 物理地址减去页面偏移量。
  • 读/写
  • 用户/主管
  • 已访问
  • 记忆型

因此,即使是已经知道访问该页面所需的许可的推测负载也将与当前特权级别(CPL)和所需的op特权进行比较,因此可以阻止任何算术单元使用该推测负载。

此类权限检查包括:

  • 细分限制检查
  • 写故障
  • 用户/主管故障
  • 页面不存在故障

实际上,这就是许多x86 CPU 设计的目的 。 当操作退出时,直到故障稍后由软件/ uCode处理后,负载才会被拒绝。 负载将在整数/矢量单位的途中归零。 换句话说,User / Supervisor保护故障上的故障类似于页面不存在故障或其他页面转换问题,这意味着从L1D $中读出的行应立即丢弃,而uOp只是处于等待状态。

防止整数/浮动单元消耗故障负载不仅有益于防止此类泄漏,而且实际上可以提高性能。 即,加载该故障将不会用错误的数据训练预取器,分配缓冲区以跟踪内存顺序或分配填充缓冲区以从L2 $中获取数据(如果它错过了L1D $)。 这些是现代CPU中有限的资源,无论如何都不应该被负载消耗掉。

实际上,如果负载错过了TLB并不得不执行页面遍历,则如果在遍历过程中发生错误,某些Intel CPU甚至会终止PMH(页面未命中处理程序)中的页面遍历。 页面遍历会执行大量的指针追逐操作,并且必须消耗宝贵的加载周期,因此,如果以后将其丢弃,则可以取消。 此外,PMH有限状态机通常只能同时处理几个页面浏览。

换句话说,从性能的角度来看,中止L1D加载uOp实际上是一件好事。 媒体报道称,英特尔之所以滑倒,是因为他们试图以不那么安全的权衡取舍尽可能多的性能,这是不正确的,除非他们希望声称推测和缓存的基本概念被视为权衡。

解决方法

但这并不意味着Meltdown漏洞不存在。 除了白皮书和大多数新闻文章讨论的内容外,故事的内容还不止这些。 大多数职位要求只具有投机性的存储器访问和缓存攻击时机可以创造进攻的单纯行为 ,而现在英特尔已经完全重新设计的CPU或消除投机执行。

实际上,错误修复可能是对门的一些更改,以便在L1D $管道中添加正确的拒绝逻辑以掩盖负载冲击。 英特尔CPU肯定已经掌握了信息,因为无论如何要确定L1D $缓存命中之前,必须完成地址生成和TLB查找阶段。

导致漏洞的所有方案都是未知的。 是某些CPU设计错过了对此体系结构行为的验证吗? 是绕过这些检查的特殊x86指令序列,还是设置CPU状态以确保实际执行加载的其他一些步骤? 零计划认为,只有当故障负载达到L1D $时,攻击才会发生。 也许英特尔在未命中路径上有逻辑,但在命中路径上有逻辑错误? 如果某些Intel OoO设计能够抵抗Meltdown的影响,我不会感到惊讶,因为它是特定的CPU设计和验证问题,而不是一般的CPU体系结构问题。

不幸的是,x86通过内存执行单元有许多不同的流程。 例如,某些指令(例如MOVNTDQA)与标准可缓存负载相比,具有不同的内存顺序和L1D $中的流。 Haswell事务性同步扩展和锁甚至增加了额外的复杂性以验证正确性。 指令提取与D端加载通过的路径不同。 验证状态空间很大。 放入所有旁路网络中,然后您可以看到有多少不同的地方需要进行故障检查。

可以肯定的是,缓存和推测不会很快消失。 如果是逻辑错误,则可能是将来的Intel CPU的简单修复。

为什么今天这种攻击更容易?

假设有一条指令可以使负载即使在出现故障时也能命中和消耗,或者我在上述问题上错了,为什么它现在发生而不是几十年前发现。

  1. 当今的CPU具有更深层次的管道咳嗽 Prescott 咳嗽 ,它在推测性内存访问与这些错误访问的实际核/压扁之间提供了更大的窗口。 直到指令退回/致力于处理器体系结构状态时,才会处理错误指令。 只有在退休时,管道才被淘汰。 较长的流水线允许在执行错误指令与撤消错误指令之间留出较大的窗口,从而使其他推测性指令得以抢先一步。
  2. 相对于仅使用高速CPU的操作(例如高速缓存命中/整数操作),较大的高速缓存层次结构和较慢的内存结构速度会在高速缓存命中和高速缓存未命中/内存之间的周期中提供更大的时间差,从而实现更强大的高速缓存定时攻击。 当今的大型多核服务器CPU具有精心设计的网格结构,可以连接数十个或数百个内核。
  3. 增加了用于细粒度高速缓存控制的性能增强功能,例如x86 CLFLUSH和PREFETx,可以更好地控制高速缓存定时攻击。
  4. 可以同时启用并行整数,浮点运算和内存运算的较宽发行处理器。 可以在错误指令之前放置长浮点运算(例如除法或sqrt),以使内核保持繁忙,但仍然使整数和内存管道不受攻击。 由于有故障的指令在退出之前不会破坏管道,因此它必须等待直到指令序列中的任何较早指令被提交,包括长时间运行的浮点运算。
  5. 虚拟化和PaaS。 许多网络规模的公司现在正在运行工作负载云提供商,例如AWS和Azure。 在使用云技术之前,财富500强公司将在自己的硬件上运行自己的受信任的应用程序。 因此,与今天不同,来自不同公司的应用程序在物理上是分开的。 虽然尚不清楚Meltdown是否可以允许来宾OS进入虚拟机管理程序或主机OS,但已知的是,许多虚拟化技术比完整的VT-x轻巧。 例如,Heroku,AWS Beanstalk或Azure Web应用程序中的多个应用程序以及Docker容器都在同一VM中运行。 公司不再为每个应用程序启动单独的VM。 这可能允许恶意应用程序读取特定VM的内核内存。 在Pentium Pro / Pentium III的OoO执行成为主流的情况下,共享资源在90年代已不是问题。
  6. 使用x86页面条目中的Global和User / Supervisor位可以使内核内存空间映射到每个用户进程中(但可以防止Ring3代码执行),从而减轻了TLB的压力并减慢了上下文切换到单独的内核进程的速度。 从1990年代开始就进行了性能优化。

这是x86专用的吗?

首先,缓存定时攻击和推测性执行并不特定于Intel或x86 CPU。 大多数现代CPU在手表或微波炉的一些嵌入式微处理器之外实现多层缓存和大量推测。

这不是特定于Intel的问题或x86问题,而是一般CPU体系结构中的一个基本问题。 现在有人声称,特定的OoO ARM CPU(例如iPhone和智能手机中的CPU)也存在此缺陷。 自从Tomasulo算法引入以来,乱序执行已经完成。 同时,缓存定时攻击已经有数十年的历史了,因为众所周知,某些东西本可以在不应该的时候加载到缓存中的。 但是,传统上已使用高速缓存定时攻击来查找内核内存的位置,而不是实际读取它的能力。 它更多是根据微体系结构启用的竞争条件和窗口。 一些CPU的流水线比其他CPU的流水更浅,从而导致核泄漏发生得更快。 诸如x86之类的现代台式机/服务器CPU具有从CLFLUSH到PREFETCHTx的更精细的功能,这些功能可以作为使连接更牢固的附加工具。

内存分页的背景

自从分页引入386和Windows 3.0以来,操作系统已使用此功能将一个进程的内存空间与另一个进程隔离。 一个进程将映射到其自己的独立虚拟地址空间,该地址空间独立于另一个正在运行的进程的地址空间。 这些虚拟地址空间由物理内存支持(页面可以换出到磁盘,但这不在本文讨论范围之内)。

例如,假设进程1需要4KB的内存,因此OS分配了4KB的虚拟内存空间,该虚拟内存空间的字节可寻址范围为0x0到0xFFF。 此范围由从位置0x1000开始的物理内存支持。 这意味着进程1的[0x0-0xFFF]被“安装”在物理位置[0x1000-0x1FFF] 。 如果有另一个进程正在运行,则它也需要4KB,因此OS将为此进程2映射第二个虚拟地址空间,范围为0x0到0xFFF。 此虚拟内存空间也需要由物理内存支持。 由于进程1已经在使用0x1000-0x1FFF,因此OS将决定为进程2分配下一个物理内存块[0x2000-0x2FFF]

在进行此设置后,如果进程1将内存中的负载发布到线性地址0x0,则操作系统会将其转换为物理位置0x1000。 而如果进程2从内存向线性地址0x0发出负载,则OS会将其转换为物理位置0x2000。 请注意如何进行翻译。 这就是页表的工作。

映射内存的范围称为页面 。 CPU体系结构具有定义的页面大小,例如4KB。 分页允许将内存分散到整个物理内存空间。 在上面的示例中,我们假设页面大小为4KB,因此每个进程仅映射一个页面。 现在,假设进程1执行malloc()并强制内核映射要使用的第二个4KB区域。 由于物理内存的下一页[0x2000-0x2FFF]已由进程2使用 ,因此操作系统需要为进程1分配空闲的物理内存块[0x3000-0x3FFF](注意:现代操作系统使用延迟/惰性内存分配,意味着虚拟内存可能在创建任何物理内存之前创建,直到实际访问该页面为止,但这超出了本文的讨论范围。有关更多信息,请参见x86页面访问/脏位。

地址空间看起来与该进程是连续的,但实际上是分散在整个物理内存空间中的:

流程1

工程2

在此之前还有一个额外的转换步骤,可使用x86分段将逻辑地址转换为线性地址。 但是,当今大多数操作系统在传统意义上都没有使用分段,因此我们暂时将其忽略。

记忆保护

除创建虚拟地址空间外,分页还用作一种保护形式。 上面的翻译存储在称为页表的结构 。 每个4KB页面可以具有与翻译数据本身一起存储的特定属性和访问权限。 例如,可以将页面定义为只读。 如果针对存储器的只读页面执行存储器存储,则CPU将触发故障。

直接从《 x86参考手册》开始,每个页表条目中都存储了以下非详尽的属性位列表(其行为类似于布尔true / false):

最小化上下文切换成本

我们展示了每个进程如何具有自己的虚拟地址映射。 内核进程是一个与其他进程一样的进程,并且还具有虚拟内存映射。

当CPU将上下文从一个进程切换到另一进程时,切换成本很高,因为许多架构状态需要保存到内存中,这样,挂起的旧进程可以在再次开始执行时以保存的状态恢复执行。

但是,许多系统调用需要由内核执行,例如I / O,中断等。这意味着CPU会不断在用户进程和内核进程之间切换以处理这些系统调用。

为了最大程度地降低此成本,内核工程师和计算机架构师会在用户虚拟内存空间中映射内核页面,以避免上下文切换。 这是通过用户/管理员访问权限位完成的。 操作系统映射内核空间,但其指定为主管 (又名Ring0的)访问只有让任何用户代码无法访问这些页面。 因此,这些页面对于以用户权限级别运行的任何代码(aka Ring3)都是不可见的

用户模式下运行时,如果CPU看到一条指令访问需要管理员权限的页面,则会触发页面错误。 在x86中,页面访问权限是可以触发#PF(页面错误)的与页面相关的原因之一。

全局位

我们展示了每个进程如何具有自己的虚拟地址映射。 内核进程是一个与其他进程一样的进程,并且还具有虚拟内存映射。 大多数翻译是该过程专用的。 这样可以确保进程1无法访问进程2的数据,因为不会从进程1映射到[0x2000–0x2FFF]物理内存。 但是,许多系统调用在许多进程之间共享,以处理进行I / O调用,中断等的进程。

通常,这意味着每个进程都会复制内核映射,这给缓存这些转换带来了压力,并且在进程之间进行上下文切换的成本更高。 全局位使这些特定转换(即内核内存空间)在所有进程中可见。

总结思想

深入研究安全问题总是很有趣的。 与90年代不同,现在预计系统将是安全的,并且随着加密技术,生物特征验证,移动支付和数字健康的增长,安全性将变得越来越重要。 如今,对于90年代的消费者和企业而言,大臀位更加令人恐惧。 同时,我们还需要继续就新报告进行讨论。

各方已经证明了触发Meltdown漏洞所采取的步骤。 但是,可能不仅仅是导致Meltdown的推测和缓存定时攻击的行为,也不是CPU体系结构的根本故障,而是看起来像是逻辑错误,导致验证失败。 这意味着猜测和缓存不会很快消失,英特尔也不需要全新的架构来修复Meltdown。 取而代之的是,未来x86 CPU所需的更改只是对组合逻辑的一些细微改动,这些更改会影响确定L1D $(或任何临时缓冲区)的命中率是否良好。

From: https://hackernoon.com/a-technical-deep-dive-on-meltdown-and-does-it-work-5c395579b2a1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值