When Speculation Is Risky: Understanding Meltdown and Spectre
By Vit Sembera
For several days, rumors circulated about a serious vulnerability in Intel processors. It wasn’t until January 3 that the official disclosure of the Meltdown and Spectre vulnerabilities was made, and it became clear how serious the problems were. To summarize, Meltdown and Spectre both allow malicious code to read memory that they would normally not have permission to.
The vulnerability can allow an attacker to steal information such as passwords, encryption keys, or essentially anything that the affected system has processed. Unfortunately, the desire to improve performance significantly compromised the existing security building blocks of mainstream operating systems (Windows, Linux, and Mac OS at least) that protects the privacy of user data. Proof of concept code for both attacks has been made public; no attacks are believed to have used these newly discovered vulnerabilities.
This post explains what these vulnerabilities are, how these vulnerabilities arose in the first place, and what vendors are doing to mitigate this threat.
Background: What is Memory Isolation
Memory virtualization is one of the basic security concepts in current operating systems. It brings memory isolation between user processes, ensuring one user cannot access and modify another user’s data. This is implemented nowadays with paging. There are large and complex kernel tree structures for each process called page tables (PT), describing the mapping between virtual and physical addresses and also defining access privileges. Supporting hardware called the memory management unit (MMU) in each modern CPU ensures this translation will be as efficient as possible. There are several layers of caches, called the translation lookaside buffer (TLB), that contain translation data. Each TLB miss leads to a time-consuming lookup in the PT hierarchy executed by the page fault trap handler.
Current operating systems like Windows, Linux, and macOS (including their mobile derivatives like Android and iOS) all use the same concept. Initially, it was expected that kernel privileged code and data would be mapped to the same virtual address of each process to simplify kernel code access to user data. Each change of virtual mapping (switching PT) usually leads to TLB flushing and is inevitable during process context switches. There was another reason for mapping kernel space to user virtual space – to reduce TLB misses when changing a virtual address mapping during the switch from user mode to the kernel code and back. This was so common that Intel recommended it as a best practice and allocated a single register to keep a pointer to the actual PT. This register is then expected to be populated during context switches. The ARM architecture, by contrast, has two PT pointer registers instead.
Kernel code/data is protected from direct access by user code with MMU access control. Many kinds of attacks have been discovered exploiting kernel code bugs, leading to privilege escalation and system control. To carry out these attacks, the attacker would need to know two things: what the vulnerability is, and what is the address of related kernel code and/or data.
To defend against this, operating systems implemented address space layout randomization (ASLR) years ago. Specifically, in the case of the kernel, it is kernel ASLR (KASLR). Protection is based on keeping the addresses of kernel structures secret from user processes. There are many attacks against KASLR, some of which can be found here. Many of these attacks are based on measuring statistical differences between accessing memory when TLB is hit or missed; these statistics are based on the hardware implementation of the MMU and cannot be easily hidden.
In October 2017, researchers from Graz TU published a proposal to split the process PT into two. One is active when the process is executing kernel code (this is essentially the original PT). The second is a partial copy used for mapping user pages and some additional kernel pages needed for context switching, syscalls, and interrupt handling. The rest of kernel space is invisible; this PT is active when executing in user space. The kernel switches between these PTs when it is entering and exiting the syscall. This technique was called KAISER (Kernel Address Isolation to have Side-channels Efficiently Removed) and was able to defend against all known KASLR attacks with an added overhead of less than 1%.
Soon enough, work began to implement KAISER. In the Linux kernel, urgent (but silent) work began on a kernel page-table isolation (KPTI) implementation in November of 2017, which was based on KAISER. This part of the kernel is sporadically changed, with discussions taking place long before any code is written. Needless to say, the work to implement KPTI caught the attention of some observers because of its unusual nature.
Changes in this part of the kernel can have a significant impact on performance. Early tests showed a 5% impact in most cases, with worst-case tests indicating a 50% performance hit. On November 16, it became clear that something like KAISER was being implemented in Windows as well. The Linux KPTI was finally committed to the kernel on December 29.
Meltdown and Spectre
It soon became clear why KAISER was suddenly being implemented: it was an effective defense against Meltdown.
Both Meltdown and Spectre rely on security flaws in the speculative execution of CPU instructions. Modern processors are so fast that executing instructions in order one-by-one would lead to the CPU waiting for memory access, which takes several hundred clock cycles. Modern CPUs try to execute instructions that are ready for execution while waiting for memory read/write operations. It can be checked later if the instructions that were executed speculatively were correct; if the results are not needed, the effect on the CPU’s internal state and memory should be removed. This is called speculative execution and out of order execution.
Unfortunately, some side effects of speculative execution remain in the CPU’s state at low levels. For example, if there is an unsuccessful speculative move of a word from memory to a register at the end, the register contains the original value, but the cache is modified by the read cycle. The researchers who discovered Meltdown and Spectre used low-level CPU states to gain access to protected memory regions.
Meltdown (CVE-2017-5754) allows an unprivileged user to access the complete kernel (and physical) memory of a computer. This attack is relatively simple to execute; to carry it out, attackers need to run their own program on the target system. This attack is particularly damaging to shared systems (such as cloud services), as an attacker with access to one virtual machine can use Meltdown to access other VMs on the same physical system. Meltdown is specific to Intel systems; AMD and ARM processors are not affected.
Spectre (CVE-2017-5753, CVE-2017-5715) is a broader vulnerability. Spectre relies on issues with speculative execution itself to be carried out. In its current form, the attack is more complicated as more prerequisites must be fulfilled. One of them is a code gadget, which must be found in code shared by both victim and attacker. One Spectre variant limits attack to a single process space; the second requires superuser access.”
The real challenge with Spectre is mitigation. Unlike Meltdown (which could be mitigated via patches to the operating system), Spectre requires changes to the hardware itself. All modern x86 processors from Intel and AMD, as well as ARM processors, are believed to be vulnerable. This makes mitigating this vulnerability extremely costly, making it a long-term problem for the technology industry as a whole. Now that awareness about Spectre and the problems with speculative execution have been raised, it is up to CPU manufacturers to see how both high performance and good security can be maintained moving forward.
Solutions and best practices
Users have no way to mitigate this threat; the responsibility of doing so ultimately falls on vendors who have released multiple patches to mitigate Meltdown. Microsoft has released documents that cover both server and client versions of Windows:
- Windows Server guidance to protect against speculative execution side-channel vulnerabilities
- Windows Client Guidance for IT Pros to protect against speculative execution side-channel vulnerabilities
Note that in order to receive automatic updates from Microsoft, a registry key must be in place on the affected system. Details can be found in this article.
Apple’s December updates for macOS (released last December 2017) already resolved this vulnerability as well. As noted earlier, patches for Meltdown have been merged into the Linux kernel. It is up to individual vendors to release this update for their distribution; some vendors such as Debian, Red Hat, and SUSE have released bulletins and patches as appropriate.