Hacking, Code & Open Source Reads

Spectre and Meltdown - What Hardware Trust Looks Like After January 3

Christian Lehnert2018-01-15~9 min read

On January 3, three coordinated disclosures landed at once: Meltdown (CVE-2017-5754), Spectre Variant 1 (CVE-2017-5753), and Spectre Variant 2 (CVE-2017-5715). Independently discovered by Google Project Zero, Cyberus Technology, Graz University of Technology, the University of Pennsylvania, the University of Maryland, and Rambus Cryptography Research, with publication brought forward several days because The Register broke embargo, the disclosures triggered the largest emergency patching cycle in operating-system history.

Two weeks in, the immediate fire is mostly contained on supported platforms. Linux distributions, macOS, Windows, and the major hypervisors all shipped mitigations within days. The patches are real, the performance hits are real, and the underlying design problem is real and not going away. This post is about what was actually disclosed, what the mitigations are, what they cost, and what the disclosures tell us about the next decade of CPU design.

What was disclosed

All three vulnerabilities exploit speculative execution — the optimization, present in essentially every CPU shipped since the mid-1990s, where the processor executes instructions ahead of when their results are actually needed and rolls back the architectural state if a branch turns out the wrong way. The trick is that while the architectural state is rolled back, microarchitectural side effects — the contents of the cache, the state of branch predictors, the timing of operations — are not.

Side-channel attacks against caches are not new. Researchers have been exploiting cache-timing leaks for fifteen years. What changed is the realization that speculation lets an attacker cause the CPU to perform memory accesses it would not architecturally have made, leaving traces in the cache that can be read out by a separate, slower process.

Meltdown (CVE-2017-5754) exploits speculation past a privilege check on Intel and IBM POWER processors. A user-space program issues a load against a kernel address. The CPU correctly raises a fault, but only architecturally — speculatively, the load completes, and the loaded byte is used to index a probe array that the attacker controls. By measuring which line of the probe array is now in cache (timing reads against it), the attacker recovers the byte. Repeat for every byte of kernel memory. AMD CPUs are not affected because their permission check happens before the speculative load completes; Meltdown is, structurally, an Intel implementation defect, not a fundamental property of speculation.

Spectre Variant 1 (CVE-2017-5753) exploits speculation past a bounds check. The attacker arranges for a target program to execute a sequence like if (x < array1_size) y = array2[array1[x] * 256] with a value of x outside the bound. The branch predictor, trained on previous in-bounds calls, speculatively executes the body. The speculatively-loaded array1[x] is used as an index into array2, leaving cache traces. The architectural rollback hides the access; the cache state betrays it. Spectre v1 affects every CPU with a branch predictor — Intel, AMD, ARM, all of them.

Spectre Variant 2 (CVE-2017-5715) is the worst of the three from a system-software perspective. It exploits the indirect branch predictor — the unit that guesses the target of indirect calls and returns. By poisoning the predictor with addresses of the attacker's choosing, the attacker can make the victim CPU speculatively execute gadgets (short instruction sequences) inside the victim's address space, transferring the secret data through cache side channels. This is the variant that lets a guest VM read host memory across hypervisor boundaries. Affects Intel, AMD (less severely), and ARM Cortex-A series.

The mitigations

Each vulnerability has a different mitigation, and the mitigations stack rather than replace each other.

Meltdown is mitigated by Kernel Page Table Isolation (KPTI), originally developed as KAISER by the Graz team for unrelated reasons (defending against KASLR bypass attacks) and rapidly weaponized into a Meltdown defense. KPTI maintains two separate page tables: one for kernel mode, one for user mode. When the CPU transitions to user space, the kernel page tables are unmapped entirely, so the speculative load that Meltdown depends on has no kernel mapping to load from. The cost is a TLB flush on every kernel/user transition. Workloads that syscall heavily — databases, network servers, interpreters — can take 5–30% performance hits. Compute-heavy workloads that rarely syscall are barely affected. KPTI landed in Linux 4.14.11 and 4.15-rc6, was backported to 4.4 and 4.9 LTS, and is enabled by default on Intel CPUs (off on AMD, where it is unnecessary).

Spectre v1 has no clean mitigation at the OS level. The fix is per-codepath: insert speculation barriers — lfence on x86, csdb on ARM — at the bounds check, or use the array_index_nospec() macro Linux added that compiles to the appropriate barrier. This requires finding every vulnerable codepath in your kernel, libraries, and applications, which is an ongoing project that will take years.

Spectre v2 is mitigated by a combination of microcode updates and kernel changes. The Intel microcode adds three new MSRs: IBRS (Indirect Branch Restricted Speculation), IBPB (Indirect Branch Predictor Barrier), and STIBP (Single Thread Indirect Branch Predictors). The kernel uses these to flush or partition the indirect branch predictor across context switches and privilege transitions. Linux also added retpolines — a software construction by Paul Turner at Google that replaces indirect calls with a return-based trampoline that the predictor cannot poison. Retpolines work without microcode updates and are the preferred mitigation on AMD and on Intel CPUs that have not received microcode updates.

Intel's microcode rollout has been rocky. Several microcode updates were withdrawn after causing reboots and instability on Haswell and Broadwell systems. As of mid-January, the microcode situation is unsettled and likely to remain so for months.

What it costs

The performance impact depends almost entirely on workload.

Workload type Typical impact
Syscall-heavy (databases, network servers) 5–30%
Mixed userspace and kernel 2–10%
Compute-bound <2%
Cloud guests (with full mitigations) up to 20%

PostgreSQL maintainers have benchmarked KPTI cost at 7–17% on pgbench. Redis on small reads sees similar. NGINX serving small static files takes a noticeable hit. Number-crunching workloads, ML training, video encoding, and similar see negligible impact.

For most sysadmins, the right answer is to apply the patches, measure, and accept the cost. The alternative — running unpatched — is not viable on multi-tenant systems, and "I'm only running my own code" is a weaker defense than it sounds: any browser running JavaScript is multi-tenant in the sense that matters here. (Spectre proof-of-concept exploits in JavaScript exist; they have been demonstrated against V8 and SpiderMonkey both. Browser vendors have responded by reducing timer precision and disabling SharedArrayBuffer, which makes the demonstrated attacks slower or impractical, but the underlying vulnerability remains.)

The structural lesson

Meltdown is an Intel implementation defect, fixable in future silicon. The speculative load past a permission check should never have completed, and Intel will not ship CPUs with this property again.

Spectre is the deeper problem. It exploits speculation itself — a feature of every high-performance CPU — to bypass security boundaries that the software layer assumed were enforced by hardware. The bounds checks that protect array accesses, the indirect-call dispatch that implements virtual function calls, the page-table walks that enforce process isolation: all of these were assumed to be hardware-enforced security primitives, and all of them turn out to be advisory at the speculative level.

The implications for the next decade of CPU design are still being worked out. Some possible directions:

  1. Hardware partitioning of speculative state by privilege level. This is what Intel and AMD will likely deliver in future generations. Speculative loads that cross privilege boundaries get their own partitioned cache and predictor state, eliminating the side-channel.
  2. Constant-time guarantees in hardware. Cryptographic code already requires constant-time execution to defend against timing attacks; the Spectre disclosures suggest that any code handling sensitive data may need constant-time guarantees. CPU vendors are likely to expose explicit constant-time-execute modes.
  3. Reduction of speculation aggressiveness. ARM has been designing more conservative speculation than Intel for years. Some Spectre variants do not affect ARM Cortex-M (no speculation) at all. The performance ceiling is real, but the security cost of the most aggressive speculation may be too high.
  4. Process isolation that does not assume hardware enforcement. Hypervisors and language runtimes are likely to add software-level mitigations as defense in depth, on the assumption that hardware-only isolation is no longer sufficient.
    It is worth being clear about what we are not getting back: the assumption that two processes on the same CPU are securely isolated by the operating system. That assumption was always partly a comforting fiction — physical side channels, power analysis, and various other attacks predated Spectre — but Spectre demonstrated that the side-channel attack surface includes ordinary code on ordinary CPUs without exotic equipment. Multi-tenant computing is structurally less secure than a year ago. We will adapt.

What to do this week

For a typical Linux server:

  1. Update to the latest kernel from your distribution. On Debian 9 Stretch, this is the 4.9.0-5 series with KPTI backported. On Ubuntu 16.04 and 18.04 development, the 4.13 and 4.15 kernels respectively.
  2. Update your microcode package (intel-microcode on Debian-derived systems). On Intel CPUs, this may require enabling non-free repositories. Check the version against Intel's published table of which microcode versions are stable for which CPUs — some have been withdrawn.
  3. Verify mitigations are active: cat /sys/devices/system/cpu/vulnerabilities/* will show the current state for each vulnerability. Look for "Mitigation: PTI" for Meltdown, "Mitigation: __user pointer sanitization" or similar for Spectre v1, and "Mitigation: Full generic retpoline" or IBRS for Spectre v2.
  4. Update browsers (Chrome 64, Firefox 57.0.4 or later, both shipping mid-January).
  5. Update hypervisors: Xen 4.10.x security updates, KVM/Linux as above, VMware ESXi 6.5 U1 patch, Microsoft Hyper-V via Windows Update.
    For cloud users, your provider has handled the host side, but you still need to patch your guest. Most major providers (AWS, Azure, GCP) restarted hosts during the disclosure week to apply mitigations.

The summary

Three vulnerabilities, two of which are fundamental to a feature of every modern high-performance CPU. The patches are real, the costs are real, and they are the price of having had decades of software written under assumptions that turn out to be partly false. Apply the patches. Measure the impact. Accept that hardware-enforced isolation is now defense in depth, not a guarantee.

The deeper work — redesigning CPU speculation, redesigning multi-tenant isolation, retraining a generation of programmers to think about microarchitectural side channels — will take a decade. We are at the start of it.

Tagged:
#security #linux #hardware
← Back to posts