The Spectre attack exposed processors to memory disclosure attacks. Manipulation of indirect kernel calls may allow side channel retrieval of memory content (Branch Target Injection).
The Linux kernel was subsequently enhanced to mitigate this Variant II attack using the retpoline feature.
Retpoline is a sequence of instructions that carries out execution path changes without allowing speculation at the same time. It is a generic concept, and not specific to Linux.
Indirect branches are targets that are computed at run time. Examples include polymorphic code, or virtual member functions in C++ that are overridden in a sub-class. If you’ve ever written some assembly code and used a register as the target address for a jmp, you’ve used an indirect branch.
The risk emerges when processors attempt to calculate the actual address for, say, an overridden virtual member function. Some processors attempt to predict the address, to avoid blocking, which is where a threat actor can manipulate the operation of the CPU.
The goal in RFI attack is to get the processor to guess incorrectly and target a gadget that has been planted in the processor’s address space by the attacker.
Ideally the gadget is able to access a channel through which to leak data, such as mapped shared memory allocation. (This may not be a realistic possibility in many attack scenarios.)
The processor will use prediction that is vulnerable to exploitation when indirect jmps are encountered, and applications are unable to influence this hardware-level behaviour.
The retpoline technique avoids the potential for external manipulation by, in essence, replacing an indirect call with a compatible sequence of code that removes the attack vector, by manipulating the stack and RSB entries.
Speculative execution is not avoided entirely in retpoline, but any that does occur is benign. The technique is applied in both branching and calls, and it is possible to get efficiencies by avoiding duplication in some cases (so-called trampoline technique).
Using retpoline requires recompilation of code. This is unavoidable, but fortunately support is present within GCC and it’s a case of enabling it. This is achieved by recompiling the Linux kernel with the GCC option -mindirect-branch=thunk-extern. The kernel maintainers have also reviewed assembler code in the kernel to introduce the same protection.
But what about libraries and executables? Retpoline support will have to be applied during recompilation. Assuming retpoline in the kernel will fix all ills across the entire system is incorrect – if you have sensitive binaries and libraries on a Linux system that could be exposed to Variant 2, I strongly recommend you recompile them with “thunk-extern”.
Retpoline is a solid fix for Variant 2, that can alternatively be corrected using microcode and OS updates. It has the advantage of avoiding any changes to CPU microcode, and the downtime/risk that entails.
So my advice is to ensure you are using Linux kernels with the retpoline feature as a first step. You should then ensure security-relevant applications and code are updated to take advantage of retpoline protection. This should follow naturally if you are using a Linux distribution that is in support (if you roll your own Linux build, it’s a different situation).
“More details about mitigations for the CPU Speculative Execution issue”, Google Inc., January 4, 2018. URL: https://security.googleblog.com/2018/01/more-details-about-mitigations-for-cpu_4.html