Meltdown: Reading Kernel Memory from User Space
  sMeEbFHuuvQi 2023年11月01日 43 0

Meltdown漏洞,是一个处理器硬件级别的漏洞,谷歌的Zero Project团队、密歇根大学的Kocher在2018年的一篇顶会论文中介绍了这个漏洞。该漏洞被命名为“熔断”,有种高温岩浆熔断围墙的感觉,突破用户空间和内核空间的边界限制。它和Spectre系列漏洞有一定关系,也可以被称为Spectre V3,不过目前的学术界将两者清晰的划分为不同种类:乱序执行类、预测执行类。
本文将从论文内容、漏洞利用过程两个方面进行介绍。

论文内容介绍

论文的标题为:《Meltdown: Reading Kernel Memory from User Space》,获取链接,因为是会议论文,所以作者在youtube上发布了一个讲说视频,还有一个官网。论文的主要内容分布在Meltdown章节,将漏洞利用过程分为3个环节,给出一些漏洞优化建议,分析现有防御措施的效果。

摘要

计算机系统的安全性建立在内存隔离的基础上。比如:用户进程无法访问内核地址,用户进程A无法访问用户进程B的内存地址。

本文提出的Meltdown,利用现代处理器普遍具有的乱序执行功能,读取内存的任意地址,可以轻松窃取个人数据和密码等隐私信息。

Meltdown要求攻击者具备攻击程序的执行权限,不依赖某个操作系统,也不依赖某个软件漏洞,打破了地址空间隔离以及半虚拟化环境提供的所有安全机制。

研究表明,针对KASLR的KAISER防御机制,对Meldown攻击有着防护作用。因此,我们建议大家部署KAISER,防御Meltdown攻击。

相信大家看到这里,会对一些名词产生好奇,不要慌,在Background部分有相关介绍,比如什么是“乱序执行”?什么是KASLR?什么是KAISER防御机制?为什么内核被映射到进程的虚拟地址空间?如何映射?

Intro

操作系统的核心安全特征是内存隔离,必须确保用户A不能访问其他用户的内存和操作系统内核部分。否则,很多强大的功能就会变得非常危险,比如:一台个人设备同时运行多个应用程序,云上同时执行多个用户的进程。

处理器使用一个超级位来实现用户进程和内核进程的隔离,该超级位(CPU内部某个寄存器的某个比特位)告知处理器当前进程的权限信息,这也是“用户态”和“内核态”的区分。用户进程没有权限对超级位进行修改。

为了提高效率,操作系统将内核进程的地址空间映射到用户进程的地址空间。这样的话,如果需要临时从用户态转换为内核态(比如处理中断),处理器就可以不切换上下文,直接执行相应的内核代码。

注:linux等操作系统为了方便内核程序直接操作,将完整的物理内存映射进内核进程的地址空间。
也就是说,用户地址空间 包含 内核地址空间,内核地址空间 包含 完整的物理内存。所以,用户进程也有可能观察到完整的物理内存,ahahaha。这里一直提“地址空间”,是因为进程只能看到或者使用逻辑地址来操作内存。

Meltdown,帮助用户进程访问内核地址,读取秘密信息,借助侧信道攻击向外界传递秘密信息。

乱序执行可以提高处理器的效率,处理器如果在一条指令卡住的话,不会傻等着,而是尝试性地执行后面一些指令,比如不依赖指令结果的那些后续指令,甚至处理器的分支预测单元会猜出一个结果,让后面指令用它来执行。毕竟处理器的频率比内存读取快多了。

从宏观架构的角度来看,这种优化机制没有任何安全问题。比方说,用户进程在处理器执行下述操作(指令A):将内核地址的数据加载到寄存器,处理器基于该寄存器的值访问某个数组。如果之后,处理器发现指令A没有权限被执行,就撤销该指令的结果(修改该寄存器的状态为不可读),程序继续执行。

但是,从微架构的角度来看,这种优化机制存在严重问题,只要指令A曾经执行过,就一定存在痕迹,攻击者收集并分析这些“痕迹”,就可以恢复出指令A的运算结果(内核地址的数据)。指令A的操作会影响到缓存,通过cache侧信道可以检测到这些变化。

因此,乱序执行能够允许指令A暂时读取特权内存,通过微架构隐蔽信道(如Flush+Reload)将数据传输到外界。在隐蔽信道的接收端,攻击者恢复出该寄存器的值。理论上,完整的物理内存,对于攻击者唾手可得。

我们评估了PC、笔记本和云端服务器的攻击效果,Meltdown攻击能够帮助非特权进程(用户态进程)读取内核地址空间(映射)的所有数据,包括Linux、Android和OS X上的完整物理内存,Windows上的大部分物理内存。虽然攻击效果取决于机器性能,比如处理器速度等,但是实验中导出任意内存的速度达到3.2KB/s~503KB/s。

KAISER本来是针对KASLR侧信道攻击的防御措施,实验发现,它对Meltdown有不错的防御效果。因此,我们强烈建议所有系统部署KAISER。幸运的是,在论文发表前,Windows、Linux和OS X基于KAISER,开发了对应补丁。

贡献:

  1. 对乱序执行流进行描述。
  2. 展示乱序执行 + 微架构隐蔽信道的结合。
  3. 将乱序执行 + 异常处理程序(或TSX)结合,提出一种端到端攻击。
  4. 评估Meltdown的性能,和KAISER的防御效果。

Background

乱序执行

乱序执行是一种优化技术,用于提高处理器的利用率。处理器没有严格按照程序指令的顺序执行,如果当前指令要求的操作单元被占用了,就先运行其他的操作单元。一般来说,只要指令执行的过程、结果在架构层次是安全的,处理器就可以并行处理这些指令。

支持乱序执行功能的处理器,推测性地进行操作。也就是说,一定程度上,在处理器确认某个指令需要执行并且完整提交之前,支持乱序执行的处理器会先执行该指令。

1967年,Tomasulo开发了一个算法来实现指令的动态调度、乱序执行。他提出一个“保留站”的概念,使得处理器在计算出一个数据值后可以直接使用它,而不必将其存储到寄存器或内存,再次读取。保留站,通过重命名寄存器,对错误的计算结果撤销,能够避免写后读、读后写、写后写危害。

Intel架构中,流水线由前端、执行引擎(后端)和内存子系统组成,x86指令由前端从内存中获取,解码为微操作,然后传输给执行引擎。执行引擎中实现“乱序执行”。Reorder buffer负责寄存器分配、寄存器重命名和丢弃,同时负责 move elimination和zero idioms的识别。Scheduler(保留站)接收传来的微指令,重新排序,然后传递给Execution Units。Excution Units中的每一个执行单元执行不同的任务,比如ALU、AES、AGU和内存的加载、存储。其中,AGU和内存的加载、存储单元,和内存子系统直接连接。

CPU通常线性处理指令流,而是使用分支预测单元对下一条指令是否应该执行进行提前预测。其中,分支上没有任何依赖关系的指令可以提前被执行,这样的话,一旦该指令确实应该被执行,处理器就可以直接使用其结果;否则,就通过清除Reorder buffer和初始化保留站,来回滚到正常状态。

分支预测的实现,有很多种方法。比如静态分支预测,基于指令本身对结果进行预测;动态分支预测,在运行时收集统计数据,预测结果;一级分支预测,使用1位或2位的计数器来记录分支的最终结果;现代处理器通常使用两级自适应预测,保留最后n个结果,可以预测定期重复的一些模式;神经分支预测,也是最近被采纳的新方法。

地址空间

虚拟地址空间的实现,是通过一个multi-level page translation table,它定义了虚拟地址到物理地址的映射,提供了一些特权检查的保护措施,包括的特权有:可读、可写、可执行、可访问的用户。当前使用的转化表保存在CPU的一个特殊的寄存器内。

通过设置table的可访问权限,避免应用程序直接访问地址空间中的kernel部分。

完整的物理内存会被映射到kernel中,不同的操作系统使用不同的映射方式:

  • Linux和OS X中,采用直接的物理映射
  • Windows中,设置了paged pools、non-pages pools和system cache。三者映射物理内存的不同部分。

一般来说,利用内存错误的漏洞,都需要提前猜测到特定数据所在的地址。现有的ASLR、金丝雀,或者设置栈中不可执行的安全措施可以一定程度防范此类漏洞。但是,近些年也出现了一些对应的攻击手段,比如侧信道攻击、利用JavaScript使ASLR失效。

侧信道攻击

侧信道攻击利用正常运行单元不可避免产生的一些“痕迹”,比如电压、时间等,来泄露信息。缓存攻击是一种常用的侧信道攻击。

对于经常使用的数据,CPU和内存间设置了多级缓存,其中,地址空间转换表也会被缓存在这里。

缓存攻击关注缓存机制造成的时间上的差异,有很多例子。比如Flush+Reload缓存攻击,通过clflush指令将目标内存清理出缓存,运行攻击程序,然后测量重新加载目标内存数据所需要的时间,获取秘密。

侧信道攻击的另一个特殊用例是隐蔽通道。

一个简易例子

本节介绍一个简单的代码片段,来说明受害者程序中,乱序执行改变微架构状态的行为会泄露信息。

char data = *(char*)0xFFFF8E19;    // raise_exception();
access(probe_array[data * 4096]);  // this line should never be reached

该代码,首先引发一个异常,再访问一个数组。类似于0xFFFF8E19的高地址,一般都会分配给内核使用,因此准确来说普通用户程序是无法得到data的。但是只要我们将probe_array数组提前清出缓存,如果后面的数组访问指令曾经执行过,那么data*4096这个地址就会被缓存,攻击者就可以将秘密恢复出来。

关于操作系统对“异常”的处理,引发后,控制流不会继续执行异常后的代码,而是跳转到操作系统的异常处理程序。因此,理论上,该代码中的访问数组操作不会被执行。但是,因为处理器的乱序执行特性,CPU可能已经执行了该指令,因为它不依赖于“触发异常”的那条指令。

宏观来看,处理器的乱序执行不会产生任何不好的影响,毕竟处理器会根据异常处理之后,再决定乱序执行的指令的操作结果是否保留。但是,微架构层次来看,本代码中的数组已经被加载到了cache中。这样的话,我们就可以通过侧信道攻击获取缓冲中的信息,比如通过Flush+Reload来检测一个特定的内存是否被缓存了。进一步展开攻击。

构建攻击模块

运行 transient 指令

上面提到的例子中,“异常”之后的指令,被称为瞬态指令。它具有两个特点:1. 乱序执行,2. 处理器去处理“异常”了,因此对于瞬态指令的痕迹,攻击者可以利用。

transient指令,瞬态指令,因为它虽然暂时被执行了,但是处理器反应过来之后,会对其进行处理。

访问用户不可访问的页面,会触发“异常”。攻击者对“异常”的处理,一般来说,有两种方案:

  • 异常处理
  • 异常抑制

建立隐蔽信道

隐蔽信道,就是读取瞬态指令执行造成的处理器“微架构”状态改变,从状态中推断出秘密信息,然后传送出去。

隐蔽信道的发送方,是上面的transient指令,它利用内存中的某个用户程序可访问的地址。该地址被缓存,就相当于发出“1”。隐蔽信道的接收方,试图访问这个位置,可以通过访问时间(Flush+Reload),确定此时该地址是否被缓存。如果发现其被“缓存”,则相当于接收到了“1”这个隐蔽信息。

Meltdown

首先,我们讨论攻击设置以强调这种攻击的广泛适用性。

其次,我们进行攻击概述,展示Meltdown如何同时安装在个人计算机的 Windows 和 Linux 上、手机上的 Android 系统以及云中。

最后,我们讨论Meltdown的具体实现,允许以 3.2 KB/s 到 503 KB/s 的速度转储任意内核内存。

攻击设置

攻击环境包括云上的个人计算机和虚拟机

攻击者拥有普通用户权限,执行非特权代码

假定系统具有现阶段所有最先进的防御措施,比如ASLR KALSR SMAP SMEP NX PXN

假定系统没有任何bug,没有任何可利用的软件漏洞

攻击者的目标是秘密用户数据

攻击描述

Meltdown攻击的核心:

;rcx = kernel address, rbx = probe array
xor rax rax
retry:
mov al, byte [rcx]
shl rax, 0xc
jz retry
mov rbx, qword [rbx + rax]

三个步骤

  1. 加载攻击者无法访问的内存位置的内容(秘密)到寄存器
  2. transient指令根据寄存器中加载的“秘密”,访问高速缓存,相当于发送“秘密”
  3. 攻击者使用Flush+Reload来访问高速缓存,接收秘密信息
步骤1:读取秘密

为了从内存中的特权位置,读取秘密到寄存器,用户程序使用虚拟地址来引用内存中的数据。

每一个kernel的虚拟地址,通过转换都会指向一个实际的物理地址。

虚拟地址转换为物理地址的同时,处理器还会检查虚拟地址的权限位,确定该地址是用户可访问的,还是只有kernel能够访问。

用户程序访问kernel地址空间,会引发异常。但是,Meltdown利用处理器的乱序执行,在非法内存访问和引发异常之间的小时间窗口内执行命令。

步骤2:传输秘密

在内存中分配一个探测数组,并确保该数组的任何部分都没有被缓存。

为了传输秘密,transient指令序列对基于secret值计算的地址,进行间接地址访问。

shl rax, 0xc

左移12位,也就是将secret值乘以4 KB(4096 B),乘以页面大小。从而防止相邻的内存位置被加载时,影响结果。

在这里,我们一次读取一个字节,也就是0~255的数。因此,探测数组需要满足256 x 4096B的大小。

对 0 的噪声优化。

secret -> L1 cache -> L3 cache

步骤3:接收秘密

攻击者遍历探测数组的所有 256 页并测量每个第一个缓存行的访问时间(即偏移量) 页面上。包含在缓存的缓存行的页面编号直接对应于秘密值

Dump出完整的物理内存

重复 Meltdown 的所有 3 个步骤,攻击者可以通过遍历所有地址来转储整个内存。

由于所有主要操作系统通常也将整个物理内存映射到内核地址空间,因此,在每个用户进程中,Meltdown 还可以读取目标机器的整个物理内存

优化和限制

对 0 的固有偏差

在乱序执行的数据加载期间,如果值不可用,处理器可能会停止运作,但是也可能猜测出一个值,先继续执行着。

我们观察到,Meltdown的非法内存加载,secert值经常返回0,原因有两个:

  1. transient微指令的操作被权限检查操作优先了
  2. 处理器对权限检查的结果的猜测值,可能是1,也可能是0,而且从现有处理器的软硬件配置来说,0的可能性更高。也就是权限不允许。

因此,在secret值为0的时候,我们的Meltdown攻击会执行一定次数的重复,避免上述两个原因导致的偏差。

其余的优化措施在上面的攻击描述中,内化到了攻击代码中。

结论

本文介绍了Meltdown,一种新型攻击方法。它利用现代处理器的乱序执行测信道,使得无特权的用户空间程序能够读取任意地址的内核地址。

Meltdown不需要某种软件漏洞,也不依赖某种操作系统,能够帮助攻击者以高达 503 KB/s的速率读取云上其他进程和虚拟机中的敏感数据,影响数百万设备。

KAISER最初提出的对抗KASLR侧信道攻击的对策,无意中也阻碍了Meltdown。

KAISER建议部署在每个操作系统上,作为一种短期的解决方案,直到Meltdown在硬件上得到修复,以防止Meltdon攻击的大规模出现。

漏洞利用过程

论文中提供了现成的POC,运行即可。

不过为了提高成功率,需要将victim程序和攻击程序绑定到一个物理核的不同逻辑核上。我们以secret程序写入秘密,使用phsical_reader程序读取秘密来进行演示。

lscpu -ae

使用该命令来查看当前处理器的核心数,记下一组逻辑核(CORE相同)的数字(即CPU的数字)。

注意:不要使用0核,因为它默认会运行一些内核程序。

注意:该POC破解KASLR的程序,运行效果不佳,所以建议提前关闭测试机器的一些防御措施。具体操作如下:

sudo gedit /etc/default/grub
# 修改以下内容:
# GRUB_CMDLINE_LINUX_DEFAULT="quiet nopti nokaslr splash"
sudo update-grub
sudo reboot

然后运行 kaslr程序,记下运行结果,比如我的测试机器运行结果为0xffff888000000000

sudo ./kaslr
#运行结果为:[+] Direct physical map offset: 0xffff888000000000

在我的电脑上,2核跟6核的CORE相同,我们使用2核运行secret程序,使用6核运行phsycal_reader程序。

sudo taskset -c 2 ./secret
#运行结果为:
#[+] Secret: Welcome to the wonderful world of microarchitectural attacks
#[+] Physical address of secret: 0x1e9c79730
#[+] Exit with Ctrl+C if you are done reading the secret

这时,保持该程序处于运行状态,记下秘密的物理地址,比如我这里的0x1e9c79730

在另一个终端运行physical_reader程序

taskset -c 6 ./physical_reader 0x1e9c79730 0xffff888000000000

应该就可以看到meltdown的运行结果了!!

注意:你可能发现这里的运行命令和github演示的命令不同,这是因为机器不同。
taskset 0x2表示物理2核可以运行(0x2 = 0010),taskset 0x6表示物理2核跟物理3核都可以运行(0x6 = 0110)
taskset -c 2表示只能在逻辑2核上运行,taskset -c 6表示只能在逻辑6核上运行

文档信息
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
发表日期: 2023年2月3日

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  5NWiQFAVeqgX   2024年05月17日   34   0   0 网络安全
  pTtIhLb24H2d   2024年05月17日   35   0   0 网络安全
  OKgNPeBk991j   2024年05月18日   47   0   0 网络安全
  rKgO6TN7xbYO   2024年05月17日   39   0   0 网络安全
  5NWiQFAVeqgX   2024年05月17日   53   0   0 网络安全
  5NWiQFAVeqgX   2024年05月17日   36   0   0 网络安全
  YOkriIV1Am1d   2024年05月20日   39   0   0 网络安全
  owpmXY9hzjPv   2024年05月20日   38   0   0 网络安全
  owpmXY9hzjPv   2024年05月20日   42   0   0 网络安全
  owpmXY9hzjPv   2024年05月20日   35   0   0 网络安全