标签 KPTI 下的文章

我们知道有问题,但是并不知道问题的详细情况。

(本文发表于 1 月份)最近 Windows 和 Linux 都发送了重大安全更新,为防范这个尚未完全公开的问题,在最坏的情况下,它可能会导致性能下降多达一半。

在过去的几周,Linux 内核陆续打了几个补丁。Microsoft 自 11 月份开始也内部测试了 Windows 更新,并且它预计在下周二的例行补丁中将这个改进推送到主流 Windows 构建版中。Microsoft 的 Azure 也在下周的维护窗口中做好了安排,而 Amazon 的 AWS 也安排在周五对相关的设施进行维护。

自从 Linux 第一个补丁 (参见 KPTI:内核页表隔离的当前的发展) 明确描绘了出现的错误以后。虽然 Linux 和 Windows 基于不同的考虑,对此持有不同的看法,但是这两个操作系统 —— 当然还有其它的 x86 操作系统,比如 FreeBSD 和 macOS — 对系统内存的处理采用了相同的方式,因为对于操作系统在这一部分特性是与底层的处理器高度耦合的。

保持地址跟踪

在一个系统中的每个内存字节都是隐性编码的,这些编码数字是每个字节的地址。早期的操作系统使用物理内存地址,但是,物理内存地址由于各种原因,它并不很合适。例如,在地址中经常会有空隙,并且(尤其是 32 位的系统上)物理地址很难操作,需要 36 位数字,甚至更多。

因此,现在操作系统完全依赖一个叫虚拟内存的概念。虚拟内存系统允许程序和内核一起在一个简单、清晰、统一的环境中各自去操作。而不是使用空隙和其它奇怪的东西的物理内存,每个程序和内核自身都使用虚拟地址去访问内存。这些虚拟地址是连续的 —— 不用担心有空隙 —— 并且合适的大小也更便于操作。32 位的程序仅可以看到 32 位的地址,而不用管物理地址是 36 位还是更多位。

虽然虚拟地址对每个软件几乎是透明的,但是,处理器最终还是需要知道虚拟地址引用的物理地址是哪个。因此,有一个虚拟地址到物理地址的映射,它保存在一个被称为页面表的数据结构中。操作系统构建页面表,使用一个由处理器决定的布局,并且处理器和操作系统在虚拟地址和物理地址之间进行转换时就需要用到页面表。

这个映射过程是非常重要的,它也是现代操作系统和处理器的重要基础,处理器有专用的缓存 — Translation Lookaside Buffer(简称 TLB)—— 它保存了一定数量的虚拟地址到物理地址的映射,这样就不需要每次都使用全部页面。

虚拟内存的使用为我们提供了很多除了简单寻址之外的有用的特性。其中最主要的是,每个程序都有了自己独立的一组虚拟地址,有了它自己的一组虚拟地址到物理地址的映射。这就是用于提供“内存保护”的关键技术,一个程序不能破坏或者篡改其它程序使用的内存,因为其它程序的内存并不在它的地址映射范围之内。

由于每个进程使用一个单独的映射,因此每个程序也就有了一个额外的页面表,这就使得 TLB 缓存很拥挤。TLB 并不大 —— 一般情况下总共可以容纳几百个映射 —— 而系统使用的页面表越多,TLB 能够包含的任何特定的虚拟地址到物理地址的映射就越少。

一半一半

为了更好地使用 TLB,每个主流的操作系统都将虚拟地址范围一分为二。一半用于程序;另一半用于内核。当进程切换时,仅有一半的页面表条目发生变化 —— 仅属于程序的那一半。内核的那一半是每个程序公用的(因为只有一个内核)并且因此它可以为每个进程使用相同的页面表映射。这对 TLB 的帮助非常大;虽然它仍然会丢弃属于进程的那一半内存地址映射;但是它还保持着另一半属于内核的映射。

这种设计并不是一成不变的。在 Linux 上做了一项工作,使它可以为一个 32 位的进程提供整个地址范围,而不用在内核页面表和每个进程之间共享。虽然这样为程序提供了更多的地址空间,但这是以牺牲性能为代价的,因为每次内核代码需要运行时,TLB 重新加载内核的页面表条目。因此,这种方法并没有广泛应用到 x86 的系统上。

在内核和每个程序之间分割虚拟地址的这种做法的一个负面影响是,内存保护被削弱了。如果内核有它自己的一组页面表和虚拟地址,它将在不同的程序之间提供相同的保护;内核内存将是简单的不可见。但是使用地址分割之后,用户程序和内核使用了相同的地址范围,并且从原理上来说,一个用户程序有可能去读写内核内存。

为避免这种明显不好的情况,处理器和虚拟地址系统有一个 “Ring” 或者 “模式”的概念。x86 处理器有许多 Ring,但是对于这个问题,仅有两个是相关的:“user” (Ring 3)和 “supervisor”(ring 0)。当运行普通的用户程序时,处理器将置为用户模式 (Ring 3)。当运行内核代码时,处理器将处于 Ring 0 —— supervisor 模式,也称为内核模式。

这些 Ring 也用于从用户程序中保护内核内存。页面表并不仅仅有虚拟地址到物理地址的映射;它也包含关于这些地址的元数据,包含哪个 Ring 可能访问哪个地址的信息。内核页面表条目被标记为仅有 Ring 0 可以访问;程序的条目被标记为任何 Ring 都可以访问。如果一个处于 Ring 3 中的进程去尝试访问标记为 Ring 0 的内存,处理器将阻止这个访问并生成一个意外错误信息。运行在 Ring 3 中的用户程序不能得到内核以及运行在 Ring 0 内存中的任何东西。

至少理论上是这样的。大量的补丁和更新表明,这个地方已经被突破了。这就是最大的谜团所在。

Ring 间迁移

这就是我们所知道的。每个现代处理器都执行一定数量的推测运行。例如,给一些指令,让两个数加起来,然后将结果保存在内存中,在查明内存中的目标是否可访问和可写入之前,一个处理器可能已经推测性地做了加法。在一些常见案例中,在地址可写入的地方,处理器节省了一些时间,因为它以并行方式计算出内存中的目标是什么。如果它发现目标位置不可写入 —— 例如,一个程序尝试去写入到一个没有映射的地址或压根就不存在的物理位置 —— 然后它将产生一个意外错误,而推测运行就白做了。

Intel 处理器,尤其是(虽然不是 AMD 的)允许对 Ring 3 代码进行推测运行并写入到 Ring 0 内存中的处理器上。处理器并不完全阻止这种写入,但是推测运行轻微扰乱了处理器状态,因为,为了查明目标位置是否可写入,某些数据已经被加载到缓存和 TLB 中。这又意味着一些操作可能快几个周期,或者慢几个周期,这取决于它们所需要的数据是否仍然在缓存中。除此之外,Intel 的处理器还有一些特殊的功能,比如,在 Skylake 处理器上引入的软件保护扩展(SGX)指令,它改变了一点点访问内存的方式。同样的,处理器仍然是保护 Ring 0 的内存不被来自 Ring 3 的程序所访问,但是同样的,它的缓存和其它内部状态已经发生了变化,产生了可测量的差异。

我们至今仍然并不知道具体的情况,到底有多少内核的内存信息泄露给了用户程序,或者信息泄露的情况有多容易发生。以及有哪些 Intel 处理器会受到影响?也或者并不完全清楚,但是,有迹象表明每个 Intel 芯片都使用了推测运行(是自 1995 年 Pentium Pro 以来的所有主流处理器吗?),它们都可能会因此而泄露信息。

这个问题第一次被披露是由来自 奥地利的 Graz Technical University 的研究者。他们披露的信息表明这个问题已经足够破坏内核模式地址空间布局随机化(内核 ASLR,或称 KASLR)。ASLR 是防范 缓冲区溢出 漏洞利用的最后一道防线。启用 ASLR 之后,程序和它们的数据被置于随机的内存地址中,它将使一些安全漏洞利用更加困难。KASLR 将这种随机化应用到内核中,这样就使内核的数据(包括页面表)和代码也随机化分布。

Graz 的研究者开发了 KAISER,一组防范这个问题的 Linux 内核补丁。

如果这个问题正好使 ASLR 的随机化被破坏了,这或许将成为一个巨大的灾难。ASLR 是一个非常强大的保护措施,但是它并不是完美的,这意味着对于黑客来说将是一个很大的障碍,一个无法逾越的障碍。整个行业对此的反应是 —— Windows 和 Linux 都有一个非常重要的变化,秘密开发 —— 这表明不仅是 ASLR 被破坏了,而且从内核泄露出信息的更普遍的技术被开发出来了。确实是这样的,研究者已经 在 Twitter 上发布信息,他们已经可以随意泄露和读取内核数据了。另一种可能是,漏洞可能被用于从虚拟机中“越狱”,并可能会危及 hypervisor。

Windows 和 Linux 选择的解决方案是非常相似的,将 KAISER 分为两个区域:内核页面表的条目不再是由每个进程共享。在 Linux 中,这被称为内核页面表隔离(KPTI)。

应用补丁后,内存地址仍然被一分为二:这样使内核的那一半几乎是空的。当然它并不是非常的空,因为一些内核片断需要永久映射,不论进程是运行在 Ring 3 还是 Ring 0 中,它都几乎是空的。这意味着如果恶意用户程序尝试去探测内核内存以及泄露信息,它将会失败 —— 因为那里几乎没有信息。而真正的内核页面中只有当内核自身运行的时刻它才能被用到。

这样做就破坏了最初将地址空间分割的理由。现在,每次切换到用户程序时,TLB 需要实时去清除与内核页面表相关的所有条目,这样就失去了启用分割带来的性能提升。

影响的具体大小取决于工作负载。每当一个程序被调入到内核 —— 从磁盘读入、发送数据到网络、打开一个文件等等 —— 这种调用的成本可能会增加一点点,因为它强制 TLB 清除了缓存并实时加载内核页面表。不使用内核的程序可能会观测到 2 - 3 个百分点的性能影响 —— 这里仍然有一些开销,因为内核仍然是偶尔会运行去处理一些事情,比如多任务等等。

但是大量调用进入到内核的工作负载将观测到很大的性能损失。在一个基准测试中,一个除了调入到内核之外什么都不做的程序,观察到 它的性能下降大约为 50%;换句话说就是,打补丁后每次对内核的调用的时间要比不打补丁调用内核的时间增加一倍。基准测试使用的 Linux 的网络回环(loopback)也观测到一个很大的影响,比如,在 Postgres 的基准测试中大约是 17%。真实的数据库负载使用了实时网络可能观测到的影响要低一些,因为使用实时网络时,内核调用的开销基本是使用真实网络的开销。

虽然对 Intel 系统的影响是众所周知的,但是它们可能并不是唯一受影响的。其它的一些平台,比如 SPARC 和 IBM 的 S390,是不受这个问题影响的,因为它们的处理器的内存管理并不需要分割地址空间和共享内核页面表;在这些平台上的操作系统一直就是将它们的内核页面表从用户模式中隔离出来的。但是其它的,比如 ARM,可能就没有这么幸运了;适用于 ARM Linux 的类似补丁 正在开发中。


PETER BRIGHT 是 Ars 的一位技术编辑。他涉及微软、编程及软件开发、Web 技术和浏览器、以及安全方面。它居住在纽约的布鲁克林。


via: https://arstechnica.com/gadgets/2018/01/whats-behind-the-intel-design-flaw-forcing-numerous-patches/

作者:PETER BRIGHT 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

 title=

Linus Torvalds 在周日发布了 Linux 的 4.15 版内核,比原计划发布时间晚了一周。了解这次发行版的关键更新。

Linus Torvalds 在周日(1 月 28 日)发布了 Linux 内核的 4.15 版,再一次比原计划晚了一周。延迟发布的罪魁祸首是 “Meltdown” 和 “Spectre” bug,由于这两个漏洞,使开发者不得不在这最后的周期中提交重大补丁。Torvalds 不愿意“赶工”,因此,他又给了一周时间去制作这个发行版本。

不出意外的话,这第一批补丁将是去修补前面提及的 Meltdown 和 Spectre 漏洞。为防范 Meltdown —— 这个影响 Intel 芯片的问题,在 x86 架构上开发者实现了页表隔离(PTI)。不论什么理由你如果想去关闭它,你可以使用内核引导选项 pti=off 去关闭这个特性。

Spectre v2 漏洞对 Intel 和 AMD 芯片都有影响,为防范它,内核现在带来了 retpoline 机制。Retpoline 要求 GCC 的版本支持 -mindirect-branch=thunk-extern 功能。由于使用了 PTI,Spectre 抑制机制可以被关闭,如果需要去关闭它,在引导时使用 spectre_v2=off 选项。尽管开发者努力去解决 Spectre v1,但是,到目前为止还没有一个解决方案,因此,在 4.15 的内核版本中并没有这个 bug 的修补程序。

对于在 ARM 上的 Meltdown 解决方案也将在下一个开发周期中推送。但是,对于 PowerPC 上的 bug,在这个发行版中包含了一个补救措施,那就是使用 L1-D 缓存的 RFI 冲刷特性

一个有趣的事情是,上面提及的所有受影响的新内核中,都带有一个 /sys/devices/system/cpu/vulnerabilities/ 虚拟目录。这个目录显示了影响你的 CPU 的漏洞以及当前应用的补救措施。

芯片带 bug (以及保守秘密的制造商)的问题重新唤起了开发可行的开源替代品的呼声。这使得已经合并到主线版本的内核提供了对 RISC-V 芯片的部分支持。RISC-V 是一个开源的指令集架构,它允许制造商去设计他们自己的基于 RISC-V 芯片的实现。并且因此也有了几个开源的芯片。虽然 RISC-V 芯片目前主要用于嵌入式设备,它能够去做像智能硬盘或者像 Arduino 这样的开发板,RISC-V 的支持者认为这个架构也可以用于个人电脑甚至是多节点的超级计算机上。

正如在上面提到的,对 RISC-V 的支持,仍然没有全部完成,它虽然包含了架构代码,但是没有设备驱动。这意味着,虽然 Linux 内核可以在 RISC-V 芯片上运行,但是没有可行的方式与底层的硬件进行实质的交互。也就是说,RISC-V 不会受到其它闭源架构上的任何 bug 的影响,并且对它的支持的开发工作也在加速进行,因为,RISC-V 基金会已经得到了一些行业巨头的支持

4.15 版新内核中的其它新特性

Torvalds 经常说他喜欢的事情是很无聊的。对他来说,幸运的是,除了 Spectre 和 Meltdown 引发的混乱之外,在 4.15 内核中的大部分其它东西都很普通,比如,对驱动的进一步改进、对新设备的支持等等。但是,还有几点需要重点指出,它们是:

  • AMD 对虚拟化安全加密的支持。它允许内核通过加密来实现对虚拟机内存的保护。加密的内存仅能够被使用它的虚拟机所解密。就算是 hypervisor 也不能看到它内部的数据。这意味着在云中虚拟机正在处理的数据,在虚拟机外的任何进程都看不到。
  • 由于 包含了显示代码, AMD GPU 得到了极大的提升,这使得 Radeon RX Vega 和 Raven Ridge 显卡得到了内核主线版本的支持,并且也在 AMD 显卡中实现了 HDMI/DP 音频。
  • 树莓派的爱好者应该很高兴,因为在新内核中, 7" 触摸屏现在已经得到原生支持,这将产生成百上千的有趣的项目。

要发现更多的特性,你可以去查看在 Kernel NewbiesPhoronix 上的内容。


via: https://www.linux.com/blog/intro-to-linux/2018/1/linux-kernel-415-unusual-release-cycle

作者:PAUL BROWN 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

现在(LCTT 译注:本文发表于 1 月初),每个人都知道一件关乎电脑安全的“大事”发生了,真见鬼,等每日邮报报道的时候,你就知道什么是糟糕了...

不管怎样,除了告诉你这篇写的及其出色的披露该问题的 Zero 项目的论文之外,我不打算去跟进这个问题已经被报道出来的细节。他们应该现在就直接颁布 2018 年的 Pwnie 奖,干的太棒了。

如果你想了解我们如何在内核中解决这些问题的技术细节,你可以保持关注了不起的 lwn.net,他们会把这些细节写成文章。

此外,这有一条很好的关于这些公告的摘要,包括了各个厂商的公告。

至于这些涉及的公司是如何处理这些问题的,这可以说是如何与 Linux 内核社区保持沟通的教科书般的例子。这件事涉及到的人和公司都知道发生了什么,我确定这件事最终会出现,但是目前我需要去关注的是如何修复这些涉及到的问题,然后不去点名指责,不管我有多么的想去这么做。

你现在能做什么

如果你的 Linux 系统正在运行一个正常的 Linux 发行版,那么升级你的内核。它们都应该已经更新了,然后在接下来的几个星期里保持更新。我们会统计大量在极端情况下出现的 bug ,这里涉及的测试很复杂,包括庞大的受影响的各种各样的系统和工作任务。如果你的 Linux 发行版没有升级内核,我强烈的建议你马上更换一个 Linux 发行版。

然而有很多的系统因为各种各样的原因(听说它们比起“传统”的企业发行版更多)不是在运行“正常的” Linux 发行版上。它们依靠长期支持版本(LTS)的内核升级,或者是正常的稳定内核升级,或者是内部的某人打造版本的内核。对于这部分人,这篇介绍了你能使用的上游内核中发生的混乱是怎么回事。

Meltdown – x86

现在,Linus 的内核树包含了我们当前所知的为 x86 架构解决 meltdown 漏洞的所有修复。开启 CONFIG_PAGE_TABLE_ISOLATION 这个内核构建选项,然后进行重构和重启,所有的设备应该就安全了。

然而,Linus 的内核树当前处于 4.15-rc6 这个版本加上一些未完成的补丁。4.15-rc7 版本要明天才会推出,里面的一些补丁会解决一些问题。但是大部分的人不会在一个“正常”的环境里运行 -rc 内核。

因为这个原因,x86 内核开发者在 页表隔离 page table isolation 代码的开发过程中做了一个非常好的工作,好到要反向移植到最新推出的稳定内核 4.14 的话,我们只需要做一些微不足道的工作。这意味着最新的 4.14 版本(本文发表时是 4.14.12 版本),就是你应该运行的版本。4.14.13 会在接下来的几天里推出,这个更新里有一些额外的修复补丁,这些补丁是一些运行 4.14.12 内核且有启动时间问题的系统所需要的(这是一个显而易见的问题,如果它不启动,就把这些补丁加入更新排队中)。

我个人要感谢 Andy Lutomirski、Thomas Gleixner、Ingo Molnar、 Borislav Petkov、 Dave Hansen、 Peter Zijlstra、 Josh Poimboeuf、 Juergen Gross 和 Linus Torvalds。他们开发出了这些修复补丁,并且为了让我能轻松地使稳定版本能够正常工作,还把这些补丁以一种形式融合到了上游分支里。没有这些工作,我甚至不敢想会发生什么。

对于老的长期支持内核(LTS),我主要依靠 Hugh Dickins、 Dave Hansen、 Jiri Kosina 和 Borislav Petkov 优秀的工作,来为 4.4 到 4.9 的稳定内核代码树分支带去相同的功能。我同样在追踪讨厌的 bug 和缺失的补丁方面从 Guenter Roeck、 Kees Cook、 Jamie Iles 以及其他很多人那里得到了极大的帮助。我要感谢 David Woodhouse、 Eduardo Valentin、 Laura Abbott 和 Rik van Riel 在反向移植和集成方面的帮助,他们的帮助在许多棘手的地方是必不可少的。

这些长期支持版本的内核同样有 CONFIG_PAGE_TABLE_ISOLATION 这个内核构建选项,你应该开启它来获得全方面的保护。

从主线版本 4.14 和 4.15 的反向移植是非常不一样的,它们会出现不同的 bug,我们现在知道了一些在工作中遇见的 VDSO 问题。一些特殊的虚拟机安装的时候会报一些奇怪的错,但这是只是现在出现的少数情况,这种情况不应该阻止你进行升级。如果你在这些版本中遇到了问题,请让我们在稳定内核邮件列表中知道这件事。

如果你依赖于 4.4 和 4.9 或是现在的 4.14 以外的内核代码树分支,并且没有发行版支持你的话,你就太不幸了。比起你当前版本内核包含的上百个已知的漏洞和 bug,缺少补丁去解决 meltdown 问题算是一个小问题了。你现在最需要考虑的就是马上把你的系统升级到最新。

与此同时,臭骂那些强迫你运行一个已被废弃且不安全的内核版本的人,他们是那些需要知道这是完全不顾后果的行为的人中的一份子。

Meltdown – ARM64

现在 ARM64 为解决 Meltdown 问题而开发的补丁还没有并入 Linus 的代码树,一旦 4.15 在接下来的几周里成功发布,他们就准备阶段式地并入 4.16-rc1,因为这些补丁还没有在一个 Linus 发布的内核中,我不能把它们反向移植进一个稳定的内核版本里(额……我们有这个规矩是有原因的)

由于它们还没有在一个已发布的内核版本中,如果你的系统是用的 ARM64 的芯片(例如 Android ),我建议你选择 Android 公共内核代码树,现在,所有的 ARM64 补丁都并入 3.184.44.9 分支 中。

我强烈建议你关注这些分支,看随着时间的过去,由于测试了已并入补丁的已发布的上游内核版本,会不会有更多的修复补丁被补充进来,特别是我不知道这些补丁会在什么时候加进稳定的长期支持内核版本里。

对于 4.4 到 4.9 的长期支持内核版本,这些补丁有很大概率永远不会并入它们,因为需要大量的先决补丁。而所有的这些先决补丁长期以来都一直在 Android 公共内核版本中测试和合并,所以我认为现在对于 ARM 系统来说,仅仅依赖这些内核分支而不是长期支持版本是一个更好的主意。

同样需要注意的是,我合并所有的长期支持内核版本的更新到这些分支后通常会在一天之内或者这个时间点左右进行发布,所以你无论如何都要关注这些分支,来确保你的 ARM 系统是最新且安全的。

Spectre

现在,事情变得“有趣”了……

再一次,如果你正在运行一个发行版的内核,一些内核融入了各种各样的声称能缓解目前大部分问题的补丁,你的内核可能就被包含在其中。如果你担心这一类的攻击的话,我建议你更新并测试看看。

对于上游来说,很好,现状就是仍然没有任何的上游代码树分支合并了这些类型的问题相关的修复补丁。有很多的邮件列表在讨论如何去解决这些问题的解决方案,大量的补丁在这些邮件列表中广为流传,但是它们尚处于开发前期,一些补丁系列甚至没有被构建或者应用到任何已知的代码树,这些补丁系列彼此之间相互冲突,这是常见的混乱。

这是由于 Spectre 问题是最近被内核开发者解决的。我们所有人都在 Meltdown 问题上工作,我们没有精确的 Spectre 问题全部的真实信息,而四处散乱的补丁甚至比公开发布的补丁还要糟糕。

因为所有的这些原因,我们打算在内核社区里花上几个星期去解决这些问题并把它们合并到上游去。修复补丁会进入到所有内核的各种各样的子系统中,而且在它们被合并后,会集成并在稳定内核的更新中发布,所以再次提醒,无论你使用的是发行版的内核还是长期支持的稳定内核版本,你最好并保持更新到最新版。

这不是好消息,我知道,但是这就是现实。如果有所安慰的话,似乎没有任何其它的操作系统完全地解决了这些问题,现在整个产业都在同一条船上,我们只需要等待,并让开发者尽快地解决这些问题。

提出的解决方案并非毫不重要,但是它们中的一些还是非常好的。一些新概念会被创造出来来帮助解决这些问题,Paul Turner 提出的 Retpoline 方法就是其中的一个例子。这将是未来大量研究的一个领域,想出方法去减轻硬件中涉及的潜在问题,希望在它发生前就去预见它。

其他架构的芯片

现在,我没有看见任何 x86 和 arm64 架构以外的芯片架构的补丁,听说在一些企业发行版中有一些用于其他类型的处理器的补丁,希望他们在这几周里能浮出水面,合并到合适的上游那里。我不知道什么时候会发生,如果你使用着一个特殊的架构,我建议在 arch-specific 邮件列表上问这件事来得到一个直接的回答。

结论

再次说一遍,更新你的内核,不要耽搁,不要止步。更新会在很长的一段时间里持续地解决这些问题。同样的,稳定和长期支持内核发行版里仍然有很多其它的 bug 和安全问题,它们和问题的类型无关,所以一直保持更新始终是一个好主意。

现在,有很多非常劳累、坏脾气、缺少睡眠的人,他们通常会生气地让内核开发人员竭尽全力地解决这些问题,即使这些问题完全不是开发人员自己造成的。请关爱这些可怜的程序猿。他们需要爱、支持,我们可以为他们免费提供的他们最爱的饮料,以此来确保我们都可以尽可能快地结束修补系统。


via: http://kroah.com/log/blog/2018/01/06/meltdown-status/

作者:Greg Kroah-Hartman 译者:hopefully2333 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

本文勘误与补充

长文预警: 这是一个目前严格限制的、禁止披露的安全 bug(LCTT 译注:目前已经部分披露),它影响到目前几乎所有实现虚拟内存的 CPU 架构,需要硬件的改变才能完全解决这个 bug。通过软件来缓解这种影响的紧急开发工作正在进行中,并且最近在 Linux 内核中已经得以实现,并且,在 11 月份,在 NT 内核中也开始了一个类似的紧急开发。在最糟糕的情况下,软件修复会导致一般工作负载出现巨大的减速(LCTT 译注:外在表现为 CPU 性能下降)。这里有一个提示,攻击会影响虚拟化环境,包括 Amazon EC2 和 Google 计算引擎,以及另外的提示是,这种精确的攻击可能涉及一个新的 Rowhammer 变种(LCTT 译注:一个由 Google 安全团队提出的 DRAM 的安全漏洞,在文章的后面部分会简单介绍)。

我一般不太关心安全问题,但是,对于这个 bug 我有点好奇,而一般会去写这个主题的人似乎都很忙,要么就是知道这个主题细节的人会保持沉默。这让我在新年的第一天(元旦那天)花了几个小时深入去挖掘关于这个谜团的更多信息,并且我将这些信息片断拼凑到了一起。

注意,这是一件相互之间高度相关的事件,因此,它的主要描述都是猜测,除非过一段时间,它的限制禁令被取消。我所看到的,包括涉及到的供应商、许多争论和这种戏剧性场面,将在限制禁令取消的那一天出现。

LWN

这个事件的线索出现于 12 月 20 日 LWN 上的 内核页面表的当前状况:页面隔离这篇文章。从文章语气上明显可以看到这项工作的紧急程度,内核的核心开发者紧急加入了 KAISER 补丁系列的开发——它由奥地利的 TU Graz 的一组研究人员首次发表于去年 10 月份。

这一系列的补丁的用途从概念上说很简单:为了阻止运行在用户空间的进程在进程页面表中通过映射得到内核空间页面的各种攻击方式,它可以很好地阻止了从非特权的用户空间代码中识别到内核虚拟地址的攻击企图。

这个小组在描述 KAISER 的论文《KASLR 已死:KASLR 永存》摘要中特别指出,当用户代码在 CPU 上处于活动状态的时候,在内存管理硬件中删除所有内核地址空间的信息。

这个补丁集的魅力在于它触及到了核心,内核的全部基柱(以及与用户空间的接口),显然,它应该被最优先考虑。遍观 Linux 中内存管理方面的变化,通常某个变化的首次引入会发生在该改变被合并的很久之前,并且,通常会进行多次的评估、拒绝、以及因各种原因爆发争论的一系列过程。

而 KAISER(就是现在的 KPTI)系列(从引入到)被合并还不足三个月。

ASLR 概述

从表面上看,这些补丁设计以确保 地址空间布局随机化 Address Space Layout Randomization (ASLR)仍然有效:这是一个现代操作系统的安全特性,它试图将更多的随机位引入到公共映射对象的地址空间中。

例如,在引用 /usr/bin/python 时,动态链接将对系统的 C 库、堆、线程栈、以及主要的可执行文件进行排布,去接受随机分配的地址范围:

$ bash -c ‘grep heap /proc/$$/maps’
019de000-01acb000 rw-p 00000000 00:00 0                                  [heap]
$ bash -c 'grep heap /proc/$$/maps’
023ac000-02499000 rw-p 00000000 00:00 0                                  [heap]

注意两次运行的 bash 进程的堆(heap)的开始和结束偏移量上的变化。

如果一个缓存区管理的 bug 将导致攻击者可以去覆写一些程序代码指向的内存地址,而那个地址之后将在程序控制流中使用,这样这种攻击者就可以使控制流转向到一个包含他们所选择的内容的缓冲区上。而这个特性的作用是,对于攻击者来说,使用机器代码来填充缓冲区做他们想做的事情(例如,调用 system() C 库函数)将更困难,因为那个函数的地址在不同的运行进程上不同的。

这是一个简单的示例,ASLR 被设计用于去保护类似这样的许多场景,包括阻止攻击者了解有可能被用来修改控制流的程序数据的地址或者实现一个攻击。

KASLR 是应用到内核本身的一个 “简化的” ASLR:在每个重新引导的系统上,属于内核的地址范围是随机的,这样就使得,虽然被攻击者操控的控制流运行在内核模式上,但是,他们不能猜测到为实现他们的攻击目的所需要的函数和结构的地址,比如,定位当前进程的数据段,将活动的 UID 从一个非特权用户提升到 root 用户,等等。

坏消息:缓减这种攻击的软件运行成本过于贵重

之前的方式,Linux 将内核的内存映射到用户内存的同一个页面表中的主要原因是,当用户的代码触发一个系统调用、故障、或者产生中断时,就不需要改变正在运行的进程的虚拟内存布局。

因为它不需要去改变虚拟内存布局,进而也就不需要去清洗掉(flush)依赖于该布局的与 CPU 性能高度相关的缓存(LCTT 译注:意即如果清掉这些高速缓存,CPU 性能就会下降),而主要是通过 转换查找缓冲器 Translation Lookaside Buffer (TLB)(LCTT 译注:TLB ,将虚拟地址转换为物理地址)。

随着页面表分割补丁的合并,内核每次开始运行时,需要将内核的缓存清掉,并且,每次用户代码恢复运行时都会这样。对于大多数工作负载,在每个系统调用中,TLB 的实际总损失将导致明显的变慢:@grsecurity 测量的一个简单的案例,在一个最新的 AMD CPU 上,Linux du -s 命令变慢了 50%。

34C3

在今年的 CCC 大会上,你可以找到 TU Graz 的另外一位研究人员,《描述了一个纯 Javascript 的 ASLR 攻击》,通过仔细地掌握 CPU 内存管理单元的操作时机,遍历了描述虚拟内存布局的页面表,来实现 ASLR 攻击。它通过高度精确的时间掌握和选择性回收的 CPU 缓存行的组合方式来实现这种结果,一个运行在 web 浏览器的 Javascript 程序可以找回一个 Javascript 对象的虚拟地址,使得可以利用浏览器内存管理 bug 进行接下来的攻击。(LCTT 译注:本文作者勘误说,上述链接 CCC 的讲演与 KAISER 补丁完全无关,是作者弄错了)

因此,从表面上看,我们有一组 KAISER 补丁,也展示了解除 ASLR 化地址的技术,并且,这个展示使用的是 Javascript,它很快就可以在一个操作系统内核上进行重新部署。

虚拟内存概述

在通常情况下,当一些机器码尝试去加载、存储、或者跳转到一个内存地址时,现代的 CPU 必须首先去转换这个 虚拟地址 到一个 物理地址 ,这是通过遍历一系列操作系统托管的数组(被称为页面表)的方式进行的,这些数组描述了虚拟地址和安装在这台机器上的物理内存之间的映射。

在现代操作系统中,虚拟内存可能是最重要的强大特性:它可以避免什么发生呢?例如,一个濒临死亡的进程崩溃了操作系统、一个 web 浏览器 bug 崩溃了你的桌面环境、或者一个运行在 Amazon EC2 中的虚拟机的变化影响了同一台主机上的另一个虚拟机。

这种攻击的原理是,利用 CPU 上维护的大量的缓存,通过仔细地操纵这些缓存的内容,它可以去推测内存管理单元的地址,以去访问页面表的不同层级,因为一个未缓存的访问将比一个缓存的访问花费更长的时间(以实时而言)。通过检测页面表上可访问的元素,它可能能够恢复在 MMU(LCTT 译注:存储器管理单元)忙于解决的虚拟地址中的大部分比特(bits)。

这种动机的证据,但是不用恐慌

我们找到了动机,但是到目前为止,我们并没有看到这项工作引进任何恐慌。总的来说,ASLR 并不能完全缓减这种风险,并且也是一道最后的防线:仅在这 6 个月的周期内,即便是一个没有安全意识的人也能看到一些关于解除(unmasking) ASLR 化的指针的新闻,并且,实际上这种事从 ASLR 出现时就有了。

单独的修复 ASLR 并不足于去描述这项工作高优先级背后的动机。

它是硬件安全 bug 的证据

通过阅读这一系列补丁,可以明确许多事情。

第一,正如 @grsecurity 指出 的,代码中的一些注释已经被编辑掉了(redacted),并且,描述这项工作的附加的主文档文件已经在 Linux 源代码树中看不到了。

通过检查该代码,这些补丁以运行时补丁的方式构建而成,在系统引导时仅当内核检测到该系统是受影响的系统时,这些补丁才会被应用。这里采用了和对著名的 Pentium F00F bug 的缓解措施完全相同的机制:

更多的线索:Microsoft 也已经实现了页面表的分割

通过对 FreeBSD 源代码的一个简单挖掘可以看出,目前,其它的自由操作系统没有实现页面表分割,但是,通过 Alex Ioniscu 在 Twitter 上的提示,这项工作已经不局限于 Linux 了:从 11 月起,公开的 NT 内核也已经实现了同样的技术。

猜测:Rowhammer

对 TU Graz 研究人员的工作的进一步挖掘,我们找到这篇 《当 rowhammer 仅敲一次》,这是 12 月 4 日通告的一个 新的 Rowhammer 攻击的变种

在这篇论文中,我们提出了新的 Rowhammer 攻击和漏洞的原始利用方式,表明即便是组合了所有防御也没有效果。我们的新攻击技术,对一个位置的反复 “敲打”(hammering),打破了以前假定的触发 Rowhammer bug 的前提条件。

快速回顾一下,Rowhammer 是多数(全部?)种类的商业 DRAM 的一类根本性问题,比如,在普通的计算机中的内存上。通过精确操作内存中的一个区域,这可能会导致内存该区域存储的相关(但是逻辑上是独立的)内容被毁坏。效果是,Rowhammer 可能被用于去反转内存中的比特(bits),使未经授权的用户代码可以访问到,比如,这个比特位描述了系统中的其它代码的访问权限。

我发现在 Rowhammer 上,这项工作很有意思,尤其是它反转的位接近页面表分割补丁时,但是,因为 Rowhammer 攻击要求一个目标:你必须知道你尝试去反转的比特在内存中的物理地址,并且,第一步是得到的物理地址可能是一个虚拟地址,就像在 KASLR 中的解除(unmasking)工作。

猜测:它影响主要的云供应商

在我能看到的内核邮件列表中,除了该子系统维护者的名字之外,e-mail 地址属于 Intel、Amazon 和 Google 的雇员,这表示这两个大的云计算供应商对此特别感兴趣,这为我们提供了一个强大的线索,这项工作很大的可能是受虚拟化安全驱动的。

它可能会导致产生更多的猜测:虚拟机 RAM 和由这些虚拟机所使用的虚拟内存地址,最终表示为在主机上大量的相邻的数组,那些数组,尤其是在一个主机上只有两个租户的情况下,在 Xen 和 Linux 内核中是通过内存分配来确定的,这样可能会有(准确性)非常高的可预测行为。

最喜欢的猜测:这是一个提升特权的攻击

把这些综合到一起,我并不难预测,可能是我们在 2018 年会使用的这些存在提升特权的 bug 的发行版,或者类似的系统推动了如此紧急的进展,并且在补丁集的抄送列表中出现如此多的感兴趣者的名字。

最后的一个趣闻,虽然我在阅读补丁集的时候没有找到我要的东西,但是,在一些代码中标记,paravirtual 或者 HVM Xen 是不受此影响的。

吃瓜群众表示 2018 将很有趣

这些猜想是完全有可能的,它离实现很近,但是可以肯定的是,当这些事情被公开后,那将是一个非常令人激动的几个星期。


via: http://pythonsweetness.tumblr.com/post/169166980422/the-mysterious-case-of-the-linux-page-table

作者:python sweetness 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

英特尔处理器曝出了一个严重的硬件设计漏洞,迫使包括 Linux、Windows 在内的主要操作系统和各大云计算服务商都忙着打补丁。因为漏洞信息没有解密,所以目前只能通过已发布的补丁反推这个漏洞

这里是一篇对该漏洞的技术分析文章。

在十月底的时候,KAISER 补丁集被披露了;它做了一项工作,将内核空间与用户空间使用的 页表 page tables 进行了隔离,以解决 x86 处理器上向攻击者透露内核布局的安全漏洞。这些补丁是自它们被公布以来,这一星期中最值关注的事情,但是,它们似乎正在接近最终的状态。这应该是再次审视它们的合适机会。

这项工作被重命名为 “ 内核页表隔离 kernel page-table isolation ” (KPTI),但是目的是一样的:分割页表,将现在被用户空间和内核空间共享使用的这张表分成两套,内核空间和用户空间各自使用一个。这对内核的内存管理产生了根本性的变化,并且,这是本来人们期望先争论多年再做决定的,尤其是考虑到它的性能影响的时候。不过,KPTI 仍然处于快速发展的轨道上。一组预备补丁 已被被合并到 4.15 - rc4 之后的主版本线上了 — 一般情况下仅重要的修复才被允许这样做 — 并且其余的似乎被确定进入 4.16 版的合并窗口中。许多内核开发者都在这项工作上投入了大量的时间,并且 Linus Torvalds 要求 将这项工作 回迁 backport 到长期稳定内核中。

也就是说,KPTI 已经在最后期限的压力下安全补丁的所有标记都已经就绪了。对于任何基于 ARM 的读者,在这里值的注意的是,在这项工作中有一个 为 arm64 的等效补丁集

51 个补丁乃至更多

在这篇文章中,x86 补丁系列正处在 163 版本。它包含 51 个补丁,因此,我们应该感谢那些没有公开的版本。最初的补丁集,由 Dave Hansen 发布,由 Thomas Gleixner、Peter Zijlstra、Andy Lutomirski、和 Hugh Dickins 根据许多其它人的建议,做了大量的修订。任何还存在的缺陷都不是由于没有足够多的有经验的开发人员过目所导致的。

在现代系统中,页表是以一个树形结构进行组织的,这样可以高效地存储稀疏内存映射和支持巨页特性;可以查看这篇 2005 年的文章 了解更多细节以及它是怎么工作的示意图。在一个有四级页面表的系统上(目前的大多数大型系统都是这样),顶级是页面全局目录(PGD)。紧接着是页面上层目录(PUD)、页面中层目录(PMD)和页面表条目(PTE)。有五级页面表的系统是在 PGD 下面插入了一层(称为 P4D)。

页面故障解析通常遍历整个树去查找所需的 PTE,但是,巨页可以被更高层级的特定条目所表示。例如,一个 2MB 的内存 chunk 既可以由 PMD 层级的一个单个的巨页条目表示,也可以由一个单页 PTE 条目的完整页面表示。

在当前的内核中,每个处理器有一个单个的 PGD;在 KPTI 系列补丁中所采取的第一步的其中一个措施是,去创建一个第二个 PGD。当内核运行时,原来的仍然在使用;它映射所有的地址空间。当处理器运行在用户空间时,(在打完该系列补丁之后)第二个被激活。它指向属于该进程的页面的相同目录层次,但是,描述内核空间(位于虚拟地址空间的顶端)的部分通常都不在这里。

页表条目包含权限描述位,它们记录了内存该如何被访问;不用说都知道,这些位是用来设置阻止用户空间访问内核页面的,即便是通过那些被映射到该地址空间的页面访问。不幸的是,一些硬件级的错误允许用户空间的攻击者去确定一个给定的内核空间地址是否被映射,而不管那个页面上映射的地址是否被允许访问。而那个信息可以被用于击败内核地址空间布局随机化,可以使一个本地的攻击者更易于得逞。在 KPTI 背后的核心思想是,切换到一个没有内核空间映射的 PGD,将会使基于这个漏洞的攻击失效,而到现在为止,我们还没有看到这些攻击。

细节

这个想法很简单,但是,就像经常发生的那样,有各种各样麻烦的细节使得这个简单的想法变成了一个由 51 个部分构成的补丁集。其中最初的一个是,如果处理器在用户模式运行时响应一个硬件中断,处理中断需要的内核代码将在地址空间中不存在。因此,必须有足够的内核代码映射在用户模式中,以能够切换回到内核 PGD,使剩余的代码也可用。对于 traps、非屏蔽中断、和系统调用,也存在一个相似的情况。这个代码很小而且可以与其它部分隔离,但是,在处理安全且有效地切换时,涉及到一些很复杂的细节。

另一个难题来自 x86 本地描述符表(LDT)的构成,它可以被用于去改变用户空间的内存布局。它可以使用鲜为人知的 modify_ldt() 系统调用来做微调。例如,在 Linux 上早期的 POSIX 线程实现,使用了 LDT 去创建一个本地线程存储区域。在现在的 Linux 系统上,LDT 几乎不再使用了,但是,一些应用程序(比如,Wine)仍然需要它。当它被使用时,LDT 必须能够被用户空间和内核空间都可以访问到,但是,它必须一直处于内核空间中。KPTI 补丁集打乱内核附近的内存,在 PGD 级别上为 LDT 保留一个完全的条目;因此,vmalloc() 调用的可用空间收缩到仅有 12,800TB。那是一个非常巨大的 LDT 空间数,可以满足有很多 CPU 系统的需要。这种变化的其中一个结果是,LDT 的位置将是固定的,并且已知道用户空间 ——因此这将是个潜在的问题,由于覆写 LDT 的能力很容易被用来破坏整个系统。在这个系列的最终的补丁是映射为只读 LDT,以阻止此类攻击。

另一个潜在的安全缺陷是,如果内核可以一直被操纵直至返回用户空间,以至于不切换回经过过滤的 PGD。因为内核空间 PGD 也映射用户空间内存,这种疏忽可能在一段时间内不会被察觉到。对此问题的应对方法是将虚拟内存空间中用户空间的部分以非可执行的方式映射到内核的 PGD。只要用户空间(的程序)开始从一个错误的页面表开始执行,它将会立即崩溃。

最后,虽然所有已存在的 x86 处理器似乎都会受到这个信息泄露的漏洞影响,但是,以后的处理器可能不会受此影响。KPTI 有一个可测量的运行时成本,估计在 5%。有些用户也许不愿意为这些成本埋单,尤其是他们拿到了不存在这个问题的新处理器之后。为此将会有一个 nopti (内核)命令行选项来在启动的时候禁用这个机制。这个补丁系列也增加了一个新的“特性”标识(X86_BUG_CPU_INSECURE)去标识有漏洞的 CPU;它被设置在现在所有的 x86 CPU 上(LCTT 译注:AMD 表示不背这锅),但是在以后的硬件上可能没有。如果没有该特性标识,页面隔离将自动被关闭。

在 4.16 版的合并窗口打开之前剩下将近一个月。在这期间,针对一些新发现而不可避免的小毛病,KPTI 补丁集毫无疑问的将迎来一系列的小修订。一旦所有的事情都敲定了,看起来这些代码将会被合并同时以相对快的速度迁回到稳定版本的内核。显而易见的是,我们将会收到一个更慢,但是更安全的内核作为一个新年礼物。


via: https://lwn.net/SubscriberLink/741878/eb6c9d3913d7cb2b/

作者:Jonathan Corbet 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出