In order to mitigate against kernel or cross-process memory disclosure (the Spectre attack), the Linux kernel1 will be compiled with a new option, -mindirect-branch=thunk-extern introduced to gcc to perform indirect calls through a so-called retpoline.
This appears to be a newly invented term as a Google search turns up only very recent use (generally all in 2018).
What is a retpoline and how does it prevent the recent kernel information disclosure attacks?
1 It's not Linux specific, however - similar or identical construct seems to be used as part of the mitigation strategies on other OSes.
The article mentioned by sgbj in the comments written by Google's Paul Turner explains the following in much more detail, but I'll give it a shot:
As far as I can piece this together from the limited information at the moment, a retpoline is a return trampoline that uses an infinite loop that is never executed to prevent the CPU from speculating on the target of an indirect jump.
The basic approach can be seen in Andi Kleen's kernel branch addressing this issue:
It introduces the new
__x86.indirect_thunkcall that loads the call target whose memory address (which I'll callADDR) is stored on top of the stack and executes the jump using a theRETinstruction. The thunk itself is then called using the NOSPEC_JMP/CALL macro, which was used to replace many (if not all) indirect calls and jumps. The macro simply places the call target on the stack and sets the return address correctly, if necessary (note the non-linear control flow):The placement of
callin the end is necessary so that when the indirect call is finished, the control flow continues behind the use of theNOSPEC_CALLmacro, so it can be used in place of a regularcallThe thunk itself looks as follows:
The control flow can get a bit confusing here, so let me clarify:
callpushes the current instruction pointer (label 2) to the stack.leaadds 8 to the stack pointer, effectively discarding the most recently pushed quadword, which is the last return address (to label 2). After this, the top of the stack points at the real return address ADDR again.retjumps to*ADDRand resets the stack pointer to the beginning of the call stack.In the end, this whole behaviour is practically equivalent to jumping directly to
*ADDR. The one benefit we get is that the branch predictor used for return statements (Return Stack Buffer, RSB), when executing thecallinstruction, assumes that the correspondingretstatement will jump to the label 2.The part after the label 2 actually never gets executed, it's simply an infinite loop that would in theory fill the instruction pipeline with
JMPinstructions. By usingLFENCE,PAUSEor more generally an instruction causing the instruction pipeline to be stall stops the CPU from wasting any power and time on this speculative execution. This is because in case the call to retpoline_call_target would return normally, theLFENCEwould be the next instruction to be executed. This is also what the branch predictor will predict based on the original return address (the label 2)To quote from Intel's architecture manual:
Note however that the specification never mentions that LFENCE and PAUSE cause the pipeline to stall, so I'm reading a bit between the lines here.
Now back to your original question: The kernel memory information disclosure is possible because of the combination of two ideas:
Even though speculative execution should be side-effect free when the speculation was wrong, speculative execution still affects the cache hierarchy. This means that when a memory load is executed speculatively, it may still have caused a cache line to be evicted. This change in the cache hierarchy can be identified by carefully measuring the access time to memory that is mapped onto the same cache set.
You can even leak some bits of arbitrary memory when the source address of the memory read was itself read from kernel memory.
The indirect branch predictor of Intel CPUs only uses the lowermost 12 bits of the source instruction, thus it is easy to poison all 2^12 possible prediction histories with user-controlled memory addresses. These can then, when the indirect jump is predicted within the kernel, be speculatively executed with kernel privileges. Using the cache-timing side-channel, you can thus leak arbitrary kernel memory.
UPDATE: On the kernel mailing list, there is an ongoing discussion that leads me to believe retpolines don't fully mitigate the branch prediction issues, as when the Return Stack Buffer (RSB) runs empty, more recent Intel architectures (Skylake+) fall back to the vulnerable Branch Target Buffer (BTB):