MIT6.S081
  • 简介
  • Lec01 Introduction and Examples (Robert)
    • 1.1 课程内容简介
    • 1.2 操作系统结构
    • 1.3 Why Hard and Interesting
    • 1.4 课程结构和资源
    • 1.5 read, write, exit系统调用
    • 1.6 open系统调用
    • 1.7 Shell
    • 1.8 fork系统调用
    • 1.9 exec, wait系统调用
    • 1.10 I/O Redirect
  • Lec03 OS Organization and System Calls (Frans)
    • 3.1 上一节课回顾
    • 3.2 操作系统隔离性(isolation)
    • 3.3 操作系统防御性(Defensive)
    • 3.4 硬件对于强隔离的支持
    • 3.5 User/Kernel mode切换
    • 3.6 宏内核 vs 微内核 (Monolithic Kernel vs Micro Kernel)
    • 3.7 编译运行kernel
    • 3.8 QEMU
    • 3.9 XV6 启动过程
  • Lec04 Page tables (Frans)
    • 4.1 课程内容简介
    • 4.2 地址空间(Address Spaces)
    • 4.3 页表(Page Table)
    • 4.4 页表缓存(Translation Lookaside Buffer)
    • 4.5 Kernel Page Table
    • 4.6 kvminit 函数
    • 4.7 kvminithart 函数
    • 4.8 walk 函数
  • Lec05 Calling conventions and stack frames RISC-V (TA)
    • 5.1 C程序到汇编程序的转换
    • 5.2 RISC-V vs x86
    • 5.3 gdb和汇编代码执行
    • 5.4 RISC-V寄存器
    • 5.5 Stack
    • 5.6 Struct
  • Lec06 Isolation & system call entry/exit (Robert)
    • 6.1 Trap机制
    • 6.2 Trap代码执行流程
    • 6.3 ECALL指令之前的状态
    • 6.4 ECALL指令之后的状态
    • 6.5 uservec函数
    • 6.6 usertrap函数
    • 6.7 usertrapret函数
    • 6.8 userret函数
  • Lec08 Page faults (Frans)
    • 8.1 Page Fault Basics
    • 8.2 Lazy page allocation
    • 8.3 Zero Fill On Demand
    • 8.4 Copy On Write Fork
    • 8.5 Demand Paging
    • 8.6 Memory Mapped Files
  • Lec09 Interrupts (Frans)
    • 9.1 真实操作系统内存使用情况
    • 9.2 Interrupt硬件部分
    • 9.3 设备驱动概述
    • 9.4 在XV6中设置中断
    • 9.5 UART驱动的top部分
    • 9.6 UART驱动的bottom部分
    • 9.7 Interrupt相关的并发
    • 9.8 UART读取键盘输入
    • 9.9 Interrupt的演进
  • Lec10 Multiprocessors and locking (Frans)
    • 10.1 为什么要使用锁?
    • 10.2 锁如何避免race condition?
    • 10.3 什么时候使用锁?
    • 10.4 锁的特性和死锁
    • 10.5 锁与性能
    • 10.6 XV6中UART模块对于锁的使用
    • 10.7 自旋锁(Spin lock)的实现(一)
    • 10.8 自旋锁(Spin lock)的实现(二)
  • Lec11 Thread switching (Robert)
    • 11.1 线程(Thread)概述
    • 11.2 XV6线程调度
    • 11.3 XV6线程切换(一)
    • 11.4 XV6线程切换(二)
    • 11.5 XV6进程切换示例程序
    • 11.6 XV6线程切换 --- yield/sched函数
    • 11.7 XV6线程切换 --- switch函数
    • 11.8 XV6线程切换 --- scheduler函数
    • 11.9 XV6线程第一次调用switch函数
  • Lec13 Sleep & Wake up (Robert)
    • 13.1 线程切换过程中锁的限制
    • 13.2 Sleep&Wakeup 接口
    • 13.3 Lost wakeup
    • 13.4 如何避免Lost wakeup
    • 13.5 Pipe中的sleep和wakeup
    • 13.6 exit系统调用
    • 13.7 wait系统调用
    • 13.8 kill系统调用
  • Lec14 File systems (Frans)
    • 14.1 Why Interesting
    • 14.2 File system实现概述
    • 14.3 How file system uses disk
    • 14.4 inode
    • 14.5 File system工作示例
    • 14.6 XV6创建inode代码展示
    • 14.7 Sleep Lock
  • Lec15 Crash recovery (Frans)
    • 15.1 File system crash概述
    • 15.2 File system crash示例
    • 15.3 File system logging
    • 15.4 log_write函数
    • 15.5 end_op函数
    • 15.6 File system recovering
    • 15.7 Log写磁盘流程
    • 15.8 File system challenges
  • Lec16 File system performance and fast crash recovery (Robert)
    • 16.1 Why logging
    • 16.2 XV6 File system logging回顾
    • 16.3 ext3 file system log format
    • 16.4 ext3如何提升性能
    • 16.5 ext3文件系统调用格式
    • 16.6 ext3 transaction commit步骤
    • 16.7 ext3 file system恢复过程
    • 16.8 为什么新transaction需要等前一个transaction中系统调用执行完成
    • 16.9 总结
  • Lec17 Virtual memory for applications (Frans)
    • 17.1 应用程序使用虚拟内存所需要的特性
    • 17.2 支持应用程序使用虚拟内存的系统调用
    • 17.3 虚拟内存系统如何支持用户应用程序
    • 17.4 构建大的缓存表
    • 17.5 Baker's Real-Time Copying Garbage Collector
    • 17.6 使用虚拟内存特性的GC
    • 17.7 使用虚拟内存特性的GC代码展示
  • Lec18 OS organization (Robert)
    • 18.1 Monolithic kernel
    • 18.2 Micro kernel
    • 18.3 Why micro kernel?
    • 18.4 L4 micro kernel
    • 18.5 Improving IPC by Kernel Design
    • 18.6 Run Linux on top of L4 micro kernel
    • 18.7 L4 Linux性能分析
  • Lec19 Virtual Machines (Robert)
    • 19.1 Why Virtual Machine?
    • 19.2 Trap-and-Emulate --- Trap
    • 19.3 Trap-and-Emulate --- Emulate
    • 19.4 Trap-and-Emulate --- Page Table
    • 19.5 Trap-and-Emulate --- Devices
    • 19.6 硬件对虚拟机的支持
    • 19.7 Dune: Safe User-level Access to Privileged CPU Features
  • Lec20 Kernels and HLL (Frans)
    • 20.1 C语言实现操作系统的优劣势
    • 20.2 高级编程语言实现操作系统的优劣势
    • 20.3 高级编程语言选择 --- Golang
    • 20.4 Biscuit
    • 20.5 Heap exhaustion
    • 20.6 Heap exhaustion solution
    • 20.7 Evaluation: HLL benefits
    • 20.8 Evaluation: HLL performance cost(1)
    • 20.9 Evaluation: HLL performance cost(2)
    • 20.10 Should one use HLL for a new kernel?
  • Lec21 Networking (Robert)
    • 21.1计算机网络概述
    • 21.2 二层网络 --- Ethernet
    • 21.3 二/三层地址转换 --- ARP
    • 21.4 三层网络 --- Internet
    • 21.5 四层网络 --- UDP
    • 21.6 网络协议栈(Network Stack)
    • 21.7 Ring Buffer
    • 21.8 Receive Livelock
    • 21.9 如何解决Livelock
  • Lec22 Meltdown (Robert)
    • 22.1 Meltdown发生的背景
    • 22.2 Speculative execution(1)
    • 22.3 Speculative execution(2)
    • 22.4 CPU caches
    • 22.5 Flush and Reload
    • 22.6 Meltdown Attack
    • 22.7 Meltdown Fix
  • Lec23 RCU (Robert)
    • 23.1 使用锁带来的问题
    • 23.2 读写锁 (Read-Write Lock)
    • 23.3 RCU实现(1) - 基本实现
    • 23.4 RCU实现(2) - Memory barrier
    • 23.5 RCU实现(3) - 读写规则
    • 23.6 RCU用例代码
    • 23.7 RCU总结
Powered by GitBook
On this page

Was this helpful?

  1. Lec22 Meltdown (Robert)

22.7 Meltdown Fix

Previous22.6 Meltdown AttackNextLec23 RCU (Robert)

Last updated 4 years ago

Was this helpful?

我最后想讨论的是Meltdown的修复,你们实际已经接触了一些了。当发表的时候,它获取了很多的关注。实际中还有另一篇论文,也是由这篇论文的部分作者参与完成,另一篇论文讨论了一种使用了CPU内一种叫做Spectre的不同的预测执行的不同攻击方法。这一对论文的同时出现让人非常兴奋( ̄▽ ̄)"。

所以人们现在发现危害太大了,因为现在我们讨论的是操作系统的隔离性被破坏了。这里的技术破坏了Page Table的保护,这是我们用来实现用户和内核间隔离的技术,所以这是一个非常基础的攻击,或者至少以一种非常通用的方式破坏了安全性非常重要的一个部分。所以人们非常非常迫切的想要修复Meltdown。

很多操作系统在这篇论文发表之后数周内就推出的一个快速修复,这是一个叫做KAISER,现在在Linux中被称为KPTI的技术(Kernel page-table isolation)。这里的想法很简单,也就是不将内核内存映射到用户的Page Table中,相应的就像XV6一样,在系统调用时切换Page Table。所以在用户空间时,Page Table只有用户内存地址的映射,如果执行了系统调用,会有类似于XV6中trampoline的机制,切换到拥有内核内存映射的另一个Page Table中,这样才能执行内核代码。

这会导致Meltdown不能工作,因为现在你会切换Page Table,本来代表内核虚拟内存地址的r1寄存器不仅是没有权限,并且也没有意义了,因为现在的用户Page Table并没有包含对它的翻译,所以CPU并不知道该如何处理这个内存地址。现在这个虚拟内存地址不会存在于cache中,甚至都不会出现在TLB中。所以当在用户空间发起Meltdown Attack时,也就没有办法知道对应这个虚拟内存地址的数据是什么。这个虚拟内存地址并不是非法的,只是在用户空间没有意义了,这样会导致Meltdown Attack不能工作。

KAISER的缺点是,系统调用的代价更高了,因为如果不做任何事情的话,切换Page Table会导致TLB被清空,因为现在TLB中的映射关系都是前一个Page Table的。同时也会导致L1 cache被清空,因为其中对应的虚拟内存地址对于新的Page Table也没有意义了。在一些机器上,切换Page Table会使得系统调用明显变慢。

最近的CPU拥有叫做PCID(process-context identifiers)的技术,它可以帮助你在切换Page Table时避免清空Cache,尽管它还是要花费一些时间。

如果你上网看的话,当时人们有很多顾虑,当时人们认为这种两个Page Table的方案是不可接受的慢。但是实际中这并不是一个严重的问题,你上网看的话就可以发现人们有对于工作负载的整体影响的评估,因为毕竟程序也不是一直在进出内核,这里的影响大概是5%,所以这并不是一个坏的主意。人们非常快的采用了这种方案,实际上在论文发表时,已经有内核采用了这种方案来抵御其他的攻击。

除此之外,还有一个合理的硬件修复。我相信Intel在最近的处理器上已经添加了这个修复,AMD之前就已经有这个修复。

这是Cache的结构,当指令从L1 cache中加载某个数据时,比如说我们想要窃取的内核数据,人们认为数据的权限标志位就在L1 cache中,所以CPU完全可以在获取数据的时候检查权限标志位。实际中,AMD CPU和最近的Intel CPU会在很早的时候检查权限标志位。如果检查不能通过,CPU不会返回数据到CPU核中。所以没有一个预测执行指令可以看到不该看到的数据。

学生提问:为什么你觉得Intel会做这个呢?对我来说这里像是个讨论,我们应该为预测执行指令检查权限标志位吗?Intel的回答是不,为什么要检查呢?

Robert教授:是的,为什么要检查呢?反正用户也看不到对应的数据。如果更早的做权限检查,会在CPU核和L1 cache之间增加几个数字电路门,而CPU核和L1 cache之间路径的性能对于机器来说重要的,如果你能在这节省一些数字电路门的话,这可以使得你的CPU节省几个cycle来从L1 cache获取数据,进而更快的运行程序。所以很容易可以想到如果过早的检查权限,会在电路上增加几个晶体管。因为毕竟所有的预测执行指令都会Retired,并不是说过早的检查权限就可以节省一些后续的工作,在指令Retired的时候还是要触发Page Fault。我这里只是猜测,这里做一些权限检测并不能带来什么优势。

学生提问:既然Intel已经从CPU上修复了这个问题,有没有哪个内核计划取消KAISER来提升性能?

Robert教授:我知道在很多内核上,这个是可选项,但是我并不完全清楚Intel修复的具体内容。我很确定他们有一些修复,但是具体内容我并不知道。

Frans教授:我认为Linux中你可以查询哪些硬件修复已经存在,并根据返回要求Linux修改从软件对于硬件问题的规避。你可以在你的笔记本上运行一个Linux命令来查看它包含了哪些问题的修复,哪些问题已经在硬件中规避了。

Robert教授:你是说如果CPU包含了修复的话,Linux实际会使用combined Page Table(注,也就是将内核内存映射到用户Page Table中)?

Frans教授:是的,我99%相信是这样的,虽然我最近没有再看过了,但是我认为还是这样的。

学生提问:人们是在干什么的时候发现这个的?

Robert教授:当人们尝试入侵一个计算机的时候。谁知道人们真正想要干什么呢?论文是由学院派写的,或许他们在研究的时候发现了一些安全问题。

Frans教授:我认为很长时间他们的一个驱动力是,他们想破解Address Space Layout Randomization,他们有一些更早的论文,看起来在这个领域有一些研究者。我认为最开始的时候,人们来自不同的领域。 就像Robert说过的,人们在这个领域工作了几十年来找到可以理解和攻击的Bug。

学生提问:有多大的可能还存在另一种Meltdown?

Robert教授:非常有可能。CPU制造商在几十年间向CPU增加了非常非常多酷炫的技术,以使得CPU运行的可以更快一些。人们之前并没有太担忧或者没有觉得这会是一个严重的安全问题。现在人们非常清楚这可能会是非常严重的安全问题,但是我们现在使用的CPU已经包含了30年的聪明思想,实际上在论文发表之前,已经存在很多基于Micro-Architectural的这一类攻击。我认为还需要一段时间才能把这一类问题完全消除。

Frans教授:如果你查看过去两年的安全相关的会议,每个会议基本都有一个session是有关探索预测执行属性,来看看能不能发起一次攻击。

Robert教授:或许这是一个更大的问题,是不是我们解决了有限的问题就没事了,又或者是上层设计方法出现问题了。这可能太过悲观了,但是你知道的,人们对于操作系统的隔离寄托了太多期望,可以非常合理的认为隔离可以工作。并且我们会在这种假设下设计类似于云计算,在浏览器中运行Javascript等等场景。但是现在这种假设实际并不成立,曾经人们认为操作系统的隔离性足够接近成立,但是这一整套基于Micro-Architectural的攻击使得这里的故事不再让人信服。

学生提问:CPU设计者可以做到什么程度使得不使用Micro-Architectural又能保持高性能,同时也有很好的安全性?

Robert教授:有些内容明显是可以修复的,比如这节课介绍的Meltdown Attack是可以被修复的,并且不会牺牲任何性能。对于一些其他的攻击,并不十分确定你可以在不损伤性能的前提下修复它们。有些问题隐藏的非常非常的深,现在有很多共享的场景,例如分时共享的计算机,云计算。假设在你的云主机上有一个磁盘驱动和一个网卡驱动,你或许可以仅仅通过监测别人的流量是怎么影响你的流量的,这里的流量包括了网络流量和磁盘流量,来获取同一个主机上的其他用户信息。我不知道这是否可行,但是对于很多东西,人们都能发现可以攻击的点。

所以很多这里的Micro-Architectural带来的问题可以在不损伤性能的前提下清除掉,但是也或许不能。

(中间有一段有关如何计算机攻击的讨论,无关故略过)

论文