The AMD Branch (Mis)predictor Part 2: Where No CPU has Gone Before [CVE-2021-26341]

We discussed this vulnerability as part of our weekly podcast on 16 March 2022

Yet another branch predictor bug was discovered by grsecurity when testing a performance optimization for Reuse Attack Protector (RAP) return hash sequences. RAP sequences have an unconditional jump, followed by a movabs instruction and some int3 instructions for debugging purposes. In a normal application, these instructions should never be executed and the unconditional indirect jump should be taken. Unfortunately for Zen 1 and Zen 2 AMD CPUs, there’s a window where these instructions could be executed speculatively due to straight-line speculation (SLS). This attack was detailed on ARM some years ago, though unfortunately there doesn’t seem to be many details on what the root cause is.

In the original ARM attack, SLS only occurred with indirect unconditional control flow changes. Unlike ARM though, in vulnerable AMD x86 CPUs, SLS can occur on both indirect and direct control flow changes. This is because on x86, the branch predictor has to predict both the condition and the target. The target is a weakpoint, as the predictor has to rely on the Branch Target Buffer (BTB) to start fetching instructions. If the BTB is flushed and no entry is present, it defaults to predicting the branch is not taken, when then allows for speculative execution of the following instructions.

This speculation, depending on the gadgets available, can leave behind secrets in the cache. To demonstrate a real world application of this bug, the authors deployed a custom eBPF filter which could setup a gadget that would do a cache load, which could be probed for the access times to leak bits of a kernel pointer and defeat kASLR.