Analysis of Spectre & Meltdown by a Computer Guy

This has been a very interesting New Year – and I have something technical to wax lyrical about again. There’s a lot of flak and misinformation flying around, and it’s hard for most people to see what, precisely, is going on. That’s understandable, since what is going on is pretty weird.

So here’s a brief summary of what, exactly, the three security vulnerabilities are:

Spectre v1: “Bounds-Check Bypass”.

The CPU is tricked into speculatively loading data from outside the bounds of an array which is bounds-checked, ie. at a virtual address chosen by the attacker. The bounds-check means that the data is never actually loaded into registers visible to the program. However, the data can be passed through several subsequent speculative instructions, including loads from dependent addresses, so cache-timing effects can be used as a side-channel to exfiltrate the data. The data, however, must legitimately be readable by the same process.

This vulnerability is difficult to exploit usefully. In most cases where it’s possible to inject code to perform the attack, you can simply inject code to read the data directly, instead. Proofs of concept use JIT compilers (eBPF and Javascript) to implement the attack.

Vulnerable CPUs: Potentially anything with branch-prediction and a sufficiently deep pipeline. This is not an x86-specific exploit. The newer the CPU, the more likely it is vulnerable. In particular on the AMD side, Piledriver, Excavator and Ryzen are confirmed to be vulnerable – but this is nothing special. Potentially even K6 and Pentium Pro are vulnerable, but early Atoms and the Pentium-MMX are not.

Software Mitigation: Bounds-checked array accesses in untrusted JIT-compiled code should be associated with a memory barrier, so that the array access itself is not speculatively executed with respect to the bounds check. This has a small performance impact on JIT-compiled code.

Spectre v2: “Branch Target Injection”.

The CPU is tricked into mispredicting an indirect branch (commonly used to implement ‘virtual’ functions in C++, or jump tables in the kernel) to speculatively execute program code chosen by the attacker. This code can directly read data visible to the process executing the branch, then perform a dependent read to permit exfiltration over the same cache-timing side-channel as Spectre v1. The exfiltrated data may reside in a privileged address space, if the targeted branch happens to be in privileged code.

The architectural results of this speculative execution are cancelled when the true branch target becomes known to the CPU, and true execution resumes from the correct address; it is therefore difficult to detect that the attack has taken place. The branch-target injection can be performed by another process or thread executing on the same CPU core as the target process, since the Branch Target Buffer (BTB) is shared between them.

This vulnerability is potentially useful to a local attacker. It can obtain secret data from a privileged address space, such as cryptographic tokens or the location of a viable Rowhammer target.

Vulnerable CPUs: This attack requires poisoning the CPU’s BTB. This is easy on at least Intel Haswell CPUs (and probably some other Intel CPUs), because BTB entries are aliased in a very predictable way. Some recent ARM Cortex-A series CPU cores are reportedly vulnerable too, for the same reason. It is much more difficult on all AMD CPUs, because BTB entries are not aliased – the attacker must know (and be able to execute arbitrary code at) the exact address of the targeted branch instruction.

Software Mitigation: Indirect branches that can be mispredicted should be removed from privileged code. This is apparently being done in the Linux kernel on vulnerable CPUs. It’s not yet clear what the performance impact is, but it should be small.

Meltdown: “Rogue Data Cache Load”.

The CPU is tricked into speculatively loading data which is in the L1 D-cache, but which is marked as unreadable in the page tables. Such data is typically accessible to privileged code running in the same process (eg. upon executing a syscall), and is left mapped but unreadable as a performance optimisation. As with the Spectre attacks, the attack relies on passing the data through further speculatively-executed instructions to perform side-channel exfiltration, and normal execution resumes with no obvious side-effects once the speculation window closes.

This vulnerability is potentially useful to a local attacker. It can obtain secret data from a privileged address space, such as cryptographic tokens or the location of a viable Rowhammer target.

Vulnerable CPUs: This attack requires that the CPU fails to promptly check security flags while performing L1 D-cache loads for a speculatively-executed instruction. Various Intel CPUs (the full extent is not yet clear) are vulnerable. AMD CPUs are not vulnerable.

Software Mitigation: Operating Systems can fully unmap privileged address spaces, instead of merely marking them as inaccessible, when kernel-mode code is not being executed. This means that the rogue load in the attack code will not find the target data. This carries a significant overhead for each syscall, because switching to the alternative page tables and back requires flushing the TLBs twice. Most workloads could see a 30% slowdown, but over 50% performance loss has been reported on newer Intel CPUs, such as the i7 8700k. 

Leave a Reply