2

How could Intel/Microsoft provide software patches to Spectre, which exploits the speculative execution nature of superscalar processors, which is a hardware feature that cannot be modified or disabled (at least not without massive loss of IPC gains stemming from speculative execution)? How do these "patches" actually work?

1
  • 4
    Why do you think it's a hardware feature, or why do you think the hardware is fixed? It may be a software layer such as microcode that actually implements x86 architecture on a RISC type CPU, or the hardware is implemented as a programmable logic like FPGA and microcode patches alter how the programmable logic works or just tells the hardware to disable that feature.
    – Justme
    Jun 3 at 4:02

2 Answers 2

8

There are various techniques to mitigate Spectre-style vulnerabilities in software without patching microcode or changing hardware, but they do incur some performance cost. I'm not familiar with how Microsoft implement these mitigations, but the Linux documentation is comprehensive.

For the Spectre variant 1, vulnerable kernel code (as determined by code audit or scanning tools) is annotated on a case by case basis to use nospec accessor macros for bounds clipping [2] to avoid any usable disclosure gadgets.

For Spectre variant 2 mitigation, the compiler turns indirect calls or jumps in the kernel into equivalent return trampolines (retpolines) [3] [9] to go to the target addresses. Speculative execution paths under retpolines are trapped in an infinite loop to prevent any speculative execution jumping to a gadget.

The references here describing the mitigation techniques aren't inherently ways to prevent Spectre-style information leakage, but they are practical solutions to the problem that come from the way the affected processors are implemented.

1
  • 6
    Also important to note that Intel's and AMD's microcode updates don't mitigate Spectre at all on their own. They provide hooks that software (such as a kernel) can use at certain points to make later branches not depend on the history of earlier branches, and stuff like that. (And for AMD, a way to set LFENCE to be a barrier to (speculative) execution; previously AMD's LFENCE was a no-op (could run 4/clock) since they didn't previously document an execution-barrier behaviour for it the way Intel did. Which is what made LFENCE useful for ordering RDTSC wrt. code being timed.) Jun 3 at 12:36
2

In some sense you are right. This is a hardware issue that can only be solved in hardware.

In fact, I would even go one step further: this is a mindset issue in the entire industry. The entire industry as a whole has made the mistake of emphasizing performance over security and of not properly considering the insanely complex interactions caused by piling complex optimization features on top of mountains of other complex optimization features each of which interacts with every other feature in highly complex, non-obvious ways.

Not only were CPUs from both major vendors of AMD64 CPUs (Intel and AMD) affected, despite having completely different microarchitectures. CPUs with completely different ISAs were affected as well. For example, every single Apple Silicon CPU at that time was also vulnerable to a very similar exploit, as were many other ARM-based CPUs as well as MIPS- and POWER-based ones. (In fact, Apple was hit pretty hard with every single Intel-based Mac as well as every single Apple Silicon-based iPhone, iPad, iPod touch, and Apple TV being vulnerable – the only "safe" device being the Apple Watch which at the time did not yet use the same hardware and software platform as the other iDevices.)

So, this does not "just" require a change in hardware, but actually a fundamental shift of priorities in the entire industry.

Spectre and Meltdown were only the beginning, there have been two dozen vulnerabilities and variants in that same family published by now.

However, there are still things that can be done without changing the hardware. Starting from the top of the stack:

User programs

User programs can turn off speculative execution for (parts of) their own code.

Security Libraries

Libraries that deal with sensitive data can implement defenses against having their memory read out.

This may not be 100% perfect and it may not be possible in all circumstances. But doing something is better than doing nothing. There is a reason most of these efforts were labelled as "mitigations", not "fixes".

System Libraries

Similar to the previous point: you can introduce features into the system libraries that mitigate the exploit. This does not help if attackers can run their own statically-linked code which doesn't use the system libraries, but it can help in some situations.

Operating Systems

Operating Systems can implement mitigations such as flushing the Branch Target Buffer between context switches of threads that run on the same physical core.

Virtual Machine Hypervisor

Similar to an OS, Hypervisor can clear / flush caches and buffers on context switches.

Compiler

Changing the compiler to not generate code that would be vulnerable and not generate code that can exploit the vulnerability.

Of course, the second one only works if you can make sure that all code running on the machine is actually compiled by a patched compiler. In other words, it does not protect against the scenario where someone runs some exploit code in a cloud VM and can read out secret data from other VMs. And whether the first one is possible depends on exactly how the vulnerability works on the specific platform.

But it still protects against some other possible attacks. For example, researchers found that they could exploit this vulnerability over the web by specially crafted JavaScript that would be compiled by Google's V8 compiler into code that exploits the vulnerability. In response, Google changed the JIT compiler in V8 to introduce mitigations. Since all JavaScript code running on your machine is always compiled by a compiler that is under your control, you can be sure that these mitigations will always be applied.

An example of this is the retpoline feature in GCC. The basic functionality of that feature was proposed in the original papers about the vulnerability, so pretty much every compiler has implemented some version of this.

The basic idea is to "trick" the CPU into not using the branch predictor but the return stack predictor. So, what the retpoline ("return trampoline") does is to replace a branch with a sequence which places a fake return address on the stack (pointing to a simple infinite loop), calls a subroutine (at which point the code which will be speculatively executed is the infinite loop at the fake return address) which fixes up the return address and returns to the "real" target.

This applies specifically to Spectre variant 2, which is based on the attacker "poisoning" the Branch Target Buffer. Retpolines trick the CPU into not using the BTB, so the part of the CPU which is under the attacker's control is bypassed.

Retbleed

But wait, there's more!

It turned out that return instructions are also vulnerable to a very similar attack. This was published in 2022. And what was it again that we did to mitigate the attacks on indirect branch prediction? Oh, that's right, put returns in there …

So, this vulnerability absolutely smashed most of the efforts to mitigate those earlier vulnerabilities in software.

Microcode

Not all functionalities in modern CPUs are implemented in hardware. In fact, a lot is implemented in microcode, and even functionality which is implemented in hardware can sometimes be overridden with microcode. Microcode is, essentially, just code loaded onto the CPU which can be upgraded and fixed.

The CPU vendors have mostly done three things:

  • Make changes that mitigate the exploits always, for cases where these mitigations only have minuscule (or no) performance impacts.
  • Introduce mitigations that can be turned on or off, for cases where theses mitigations have non-negligible performance impacts. That way, for example, cloud providers which run untrusted code from many different users in the same physical CPU cores can turn them on, whereas someone running a render farm running only trusted code can turn them off.
  • Introduce new instructions that allow user code to protect itself.

Performance

In general the performance impact is higher, the higher in the stack you perform the mitigations. That's why, even if you can mitigate it in software, it should still be fixed in the next CPU generation.

But even when fixing it in the CPU, it is not guaranteed that there won't be an impact. After all, many of these vulnerabilities strike at the very heart of what makes modern high-performance CPUs fast.

All of the above

And, of course, you can combine all of the above. For example, the compiler can use some of the new instructions to generate non-vulnerable code. Kernels, libraries, and applications can publish new versions that have been compiled with the new compiler features turned on. System libraries can provide access to the new CPU instructions using system functions. Applications and security libraries can make use of those new system functions. And so on.

But still … you are right

At the end, though, the industry needs to thoroughly re-think their approach to security as well as their cavalier attitude to the ever-increasing complexity of modern mainstream high-performance CPUs.

Retbleed is a good example. It is a very similar vulnerability to the original Spectre and Meltdown ones, and yet, it wasn't fixed by the compiler tricks, it wasn't fixed by the hardware changes that were made, it wasn't fixed by most of the mitigations, in fact.

5
  • Timing side-channels are essentially impossible to close in general, unless you make everything run the slowest it possibly could. Disabling optimizations every time someone notices that one exists (like travisdowns.github.io/blog/2021/06/17/rip-zero-opt.html) isn't a viable path forward for CPU architecture as BeeOnRope points out. The real problem is trying to strongly isolate tasks from each other including performance effects, despite sharing lots of shared resources. Most obviously SMT (hyperthreading) where multiple tasks can share a physical core simultaneously. Jun 3 at 22:24
  • One interesting development is Intel's "Data Operand Independent Timing Mode" (DOITM) bit that an OS can toggle. (See Are any instructions affected by IA32_UARCH_MISC_CTL[DOITM] in existing CPUs? for links and comments.) This could be a way to let CPUs run fast when maximum paranoia isn't needed. (e.g. when separate security domains aren't sharing the same physical core.) Jun 3 at 22:32
  • 1
    It's only been about 5 years since Spectre was made public, a previously unanticipated kind of vulnerability, so it's not surprising hardware is still finding new cases where the assumption that security of the architectural state was the only thing that mattered, not mis-speculation. No CPU architect realized there was even the possibility of such a problem until then, so it seems a bit unfair to characterize them as reckless and cavalier, and expect to have had new CPUs designed from the ground up not to have any of that whole class of vulnerabilities (Spectre or MDS). Jun 3 at 22:35
  • @Peter Cordes Superscalar architecture was originally introduced in P6, and that was quite a while back. The fact that Spectre is caused by unintended interference between superscalar and the original memory privilege mechanism and no one spotted it for so long should give everyone pause. Jun 7 at 5:56
  • @MeatballPrincess: out-of-order speculative execution is the key thing, not superscalar. For x86, superscalar was new in P5, dual-issue in-order. According to en.wikipedia.org/wiki/Out-of-order_execution, IBM S/360 in 1966 was the first processor with out-of-order exec using register-renaming with Tomasulo's algorithm and a scheduler (reservation stations). POWER1 in 1990 was the first with precise exceptions and out-of-order exec + register renaming. PowerPC 601 in 1993 (same year as Intel P5, 2 years before P6) was another early OoO exec CPU. But yes, P6 was an early example. Jun 7 at 12:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .