16 KiB
关于 Linux 页面表隔离补丁的神秘情况
长文预警: 这是一个目前严格限制的、禁止披露的安全 bug,它影响到目前几乎所有实现虚拟内存的 CPU 架构,需要硬件的改变才能完全解决这个 bug。通过软件来缓解这种影响的紧急开发工作正在进行中,并且最近在 Linux 内核中已经得以实现,并且,在 11 月份,在 NT 内核中也开始了一个类似的紧急开发。在最糟糕的情况下,软件修复会导致一般工作负载出现巨大的减速(译者注:外在表现为 CPU 性能下降)。这里有一个提示,攻击会影响虚拟化环境,包括 Amazon EC2 和 Google 计算引擎,以及另外的提示是,这种精确的攻击可能涉及一个新的 Rowhammer 变种(译者注:一个由 Google 安全团队提出的 DRAM 的安全漏洞,在文章的后面部分会简单介绍)。
我一般不太关心安全问题,但是,对于这个 bug 我有点好奇,而一般会去写这个主题的人似乎都很忙,要么就是知道这个主题细节的人会保持沉默。这让我在新年的第一天(元旦那天)花了几个小时深入去挖掘关于这个谜团的更多信息,并且我将这些信息片断拼凑到了一起。
注意,这是一件相互之间高度相关的事件,因此,它的主要描述都是猜测,除非过一段时间,它的限制禁令被取消。我所看到的,包括涉及到的供应商、许多争论和这种戏剧性场面,将在限制禁令取消的那一天出现。
LWN
这个事件的线索出现于 12 月 20 日 LWN 上的 内核页面表的当前状况:页面隔离(致校对:就是昨天我翻译的那篇) 这篇文章。它在 10 月份被奥地利的 TU Graz 的一组研究人员第一次发表。从文章语气上明显可以看到这项工作的紧急程度,内核的核心开发者紧急加入了 KAISER 补丁系列。
这一系列的补丁的用途从概念上说很简单:为了阻止运行在用户空间的进程在进程页面表中,通过映射得到内核空间页面的各种攻击方式,可以很好地阻止了从非特权的用户空间代码中识别到内核虚拟地址的攻击企图。
这组论文描述的 KAISER,KASLR 已死:KASLR 永存(致校对:这里我觉得是[ASLR 已死:KASLR 永存],请查看原文出处。),在它的抽象中,通过特定的引用,在内存管理硬件中去删除所有内核地址空间的信息,即便是用户代码在这个 CPU 上处于活动状态的时候。
这个补丁集的魅力在于它触及到了核心,内核的全部基础核心(和与用户空间的接口),显然,它应该被最优先考虑。在 Linux 中当我读到关于内存管理的变化时,通常,第一个引用发生在变化被合并的很久之前,并且,通常会进行多次的评估、拒绝、以及因各种原因爆发争论的一系列过程。
KAISER(就是现在的 KPTI)系列被合并还不足三个月。
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 进程的开始和结束偏移量上的堆的变化。
这个特性的效果是,一个 buffer 管理的 bug 导致一个攻击者可以去覆写一些程序代码指向的内存地址,并且,那个地址将在程序控制流中被使用,诸如这种攻击者可以使控制流转向到一个包含他们选择的内容的 buffer 上,对于攻击者来说,使用机器代码来填充 buffer 将更困难。例如,system() C 库函数将被引用,因为,那个函数的地址在不同的运行进程上不同的。
这是一个简单的示例,ASLR 被设计用于去保护类似这样的许多场景,包括阻止攻击者从有可能被用来修改控制流或者实现一个攻击的程序数据的地址内容。
KASLR 是 “简化的” 应用到内核本身的 ASLR:在每个重新引导的系统上,属于内核的地址范围是随机的,这样就使得,虽然被攻击者转向的控制流运行在内核模式上,但是,不能猜测到为实现他们的攻击目的所需要的函数和结构的地址,比如,定位当前进程数据,将活动的 UID 从一个非特权用户提升到 root 用户,等等。
坏消息:缓减这种攻击的软件运行成本过于贵重
老的 Linux 将内核内存映射在同一个页面表中的这个行为的主要原因是,当用户的代码触发一个系统调用、故障、或者产生中断时,用户内存也是这种行为,这样就不需要改变正在运行的进程的虚拟内存布局。
因为在那样,它不需要去改变虚拟内存布局,进而也就不需要去清洗掉(flush)与 CPU 性能高度依赖的缓存(致校对:意思是如果清掉这些缓存,CPU 性能就会下降),主要是通过 转换查找缓冲器(译者注:Translation Lookaside Buffer(TLB)(将虚拟地址转换为物理地址)。
使用已合并的页面表分割补丁后变成,内核每次开始运行时,需要将内核的缓存清掉,并且,每次用户代码恢复运行时都会这样。对于大多数工作负载,在每个系统调用中,TLB 的实际总损失将导致明显的变慢:@grsecurity 测量的一个简单的案例,在一个最新的 AMD CPU 上,Linux “du -s” 变慢了 50%。
34C3
在今年的 CCC 上,你可以找到 TU Graz 的研究人员的另一篇,一个纯 Javascript 的 ASLR 攻击描述 ,通过仔细地掌握 CPU 内存管理单元的操作时机,遍历了描述虚拟内存布局的页面表,来实现 ASLR 攻击。它通过高度精确的时间掌握和选择性回收的 CPU 缓存行的组合方式来实现这种结果,一个运行在 web 浏览器的 Javascript 程序可以找回一个 Javascript 对象的虚拟地址,使得利用浏览器内存管理 bugs 被允许进行接下来的攻击。
因此,从表面上看,我们有一组 KAISER 补丁,也展示了解除 ASLR 的地址的技术,并且,这个展示使用的是 Javascript,很快就可以在一个操作系统内核上进行重新部署。
虚拟内存概述
在通常情况下,当一些机器码尝试去加载、存储、或者跳转到一个内存地址时,现代的 CPUs 必须首先去转换这个 虚拟地址 到一个 物理地址 ,通过使用一系列操作系统托管的数组(被称为页面表),来描述一个虚拟地址和安装在这台机器上的物理内存之间的映射。
在现代操作系统中,虚拟内存可能是仅有的一个非常重要的强大特性:它都阻止了什么呢?例如,一个濒临死亡的进程崩溃了操作系统、一个 web 浏览器 bugs 崩溃了你的桌面环境、或者,一个运行在 Amazon EC2 中的虚拟机的变化影响了同一台主机上的另一个虚拟机。
这种攻击的原理是,利用 CPU 上维护的大量的缓存,通过仔细地操纵这些缓存的内存,它可以去推测内存管理单元的地址,以去访问页面表的不同层级,因为一个未缓存的访问将比一个缓存的访问花费更长的时间。通过检测页面表上可访问的元素,它可能去恢复在 MMU(译者注:存储器管理单元)忙于解决的虚拟地址中的大部分比特(bits)。
这种动机的证据,但是不用恐慌
我们找到了动机,但是到目前为止,我们并没有看到这项工作引进任何恐慌。总的来说,ASLR 并不能完全缓减这种风险,并且也是一道最后的防线:仅在这 6 个月的周期内,即便是一个没有安全意识的人也能看到一些关于解除(unmasking) ASLR 的指针的新闻,并且,实际上 ASLR 已经存在了。
单独的修复 ASLR 并不足于去描述这项工作高优先级背后的动机。
它是硬件安全 bug 的证据
通过阅读这一系列补丁,可以明确许多事情。
第一,正如 @grsecurity 指出 的,代码中的一些注释已经被编辑(redacted),并且,描述这项工作的额外的主文档文件已经在 Linux 源代码树中看不到了。
测试代码已经以运行时补丁的方式构建,在系统引导时仅当内核检测到是受影响的系统时才会被应用,与对臭名昭著的 Pentium F00F bug 的缓解措施,使用完全相同的机制:
更多的线索:Microsoft 也已经实现了页面表的分割
通过对 FreeBSD 源代码的一个小挖掘可以看出,目前,其它的免费操作系统没有实现页面表分割,但是,通过 Alex Ioniscu on Twitter 的启示,这项工作已经不局限于 Linux 了:从 11 月起,公开的 NT 内核也已经实现了同样的技术。
猜测的结果:Rowhammer
在 TU Graz 上进一步挖掘对这项工作的研究,我们找到 When rowhammer only knocks once,12 月 4 日通告的一个 新的 Rowhammer 攻击的变种:
在这篇论文中,我们提出了新的 Rowhammer 攻击和原始的漏洞利用,表明即便是所有防御的组合也没有效果。我们的新攻击技术,对一个位置的反复 “敲打”(hammering),打破了以前假定的触发 Rowhammer bug 的前提条件。
作一个快速回顾,Rowhammer 是一个对主要(全部?)种类的商品 DRAMs 的基础问题的一个类别,比如,在普通的计算机中的内存上。通过精确操作内存中的一个区域,这可能会导致内存该区域存储的相关(但是逻辑上是独立的)内容被毁坏。效果是,Rowhammer 可能被用于去反转内存中的比特(bits),使未经授权的用户代码可以访问到,比如,这个比特位描述了系统中的其它代码的访问权限。
我发现在 Rowhammer 上,这项工作很有意思,尤其是它反转的位接近页面表分割补丁时,但是,因为 Rowhammer 攻击要求一个目标:你必须知道你尝试去反转的比特在内存中的物理地址,并且,第一步是得到的物理地址可能是一个虚拟地址,比如,在 KASLR 中的解除(unmasking)工作。
猜测的结果:它影响主要的云供应商
在我能看到的内核邮件列表中,除了子系统维护者的名字之外,e-mail 地址是属于 Intel、Amazon、和 Google 的雇员,这表示这两个大的云计算供应商对此特别感兴趣,这为我们提供了一个强大的线索,这项工作很大的可能是受虚拟化安全驱动的。
它可能会导致产生更多的猜测:虚拟机 RAM 和由这些虚拟机所使用的虚拟内存地址,最终表示为在主机上大量的相邻的数组,那些数组,尤其是在一个主机上只有两个租户的情况下,在 Xen 和 Linux 内核中是通过内存分配来确定的,这样可能会有(准确性)非常高的可预测行为。
最喜欢的猜测:这是一个提升特权的攻击
把这些综合到一起,我并不难预测,如果我们在 2018 年使用这些存在提升特权的 bug 的发行版,或者类似的系统去驱动如此紧急的情况,并且在补丁集的抄送列表中出现如此多的感兴趣者的名字。
最后的一个趣闻,虽然我在阅读补丁集的时候没有找到我要的东西,但是,在一些代码中标记,paravirtual 或者 HVM Xen 是不受此影响的。
Invest in popcorn, 2018 将很有趣
这些猜想是完全有可能的,它离实现很近,但是可以肯定的是,当这些事情被公开后,那将是一个非常令人激动的几个星期。
via: http://pythonsweetness.tumblr.com/post/169166980422/the-mysterious-case-of-the-linux-page-table
作者:python sweetness 译者:qhwdw 校对:校对者ID