A Return Trampoline is a mitigation for the Spectre class of attacks (also called Branch target injection). Modern CPU will attempt to read ahead of the current instruction and load/execute instructions ahead of time, this is called speculation. Speculative execution could run into a direct branch (jmp with a fixed address) and load it. It can also run into an Indirect Branch jmp %rax. Not having the address where the jump, our CPU will speculate to where we should go. This speculation can be hijacked and shouldn't be use.
The Retpoline replaces jmp %rax and provides for a safe substitute by trapping speculative execution into a loop (jumping in place (; ), preventing it from jumping to a possible dangerous destination.
It works by tricking another predictor, the Return Stack Buffer (RSB). The RSB stores the return address of the function the speculator is currently in.
An important thing, the CPU doesn't use the RSB to return while actually executing the code, it only does so while in speculative execution. For the real execution, the CPU will use the address written in the stack instead. Lets look at some assembly:
call .a
.trap:
pause; lfence
jmp .trap
a:
mov rax, (rsp)
ret
Lets read this as a non-speculative CPU:
call .a: is a direct branch to a:.mov rax, (rsp): Moves the value from the rax register (where we want to jump to) to the stack return value.ret: returns (jumps) to the value we just placed in the stack.
Now lets read this as the speculator:
call .a: is a direct branch to a:, this isn't an issue as it is a direct branch.mov rax, (rsp): our predictor will ignore.ret: Will return at the value stored in the RSB (the instruction right after call .a )pause; lfence: does nothing.jmp .trap: Send us back in an infinite loop, essentially disabling speculation.BIG PROPS TO SOURCE[5]
A branch predictor is a digital circuit that tries to guess which way a branch (e.g., an if–then–else structure) will go before this is known definitively. Without branch prediction, the processor would have to wait until the conditional jump instruction has passed the execute stage before the next instruction can enter the fetch stage in the pipeline. The branch predictor attempts to avoid this waste of time by trying to guess whether the conditional jump is most likely to be taken or not taken. Very good image - Branch predictor - Wikipedia" class="internal-link" target="_self" rel="noopener nofollow">BTB[3]
The BTB stores the tag and target used by the BPU
Also known as stack buffer overflow, the goal is to overflow the stack to affect its memory (the mem that would normally be out of range/not changeable like a return address). This was rendered mostly useless (at least in its basic form) because we can now declare the buffer as non-executable and avoid the whole fiasco. [1]
#Stack Smashing Big brother, the goal is now to use that buffer to trick the process into returning data by using one of the process/library own instruction.[2]
Inspired by #Spectre-V2 containing a malicious payload and then using specific user history in order to get the kernel to run that payload. [4]
RFDS is a microarchitectural vulnerability, which, in some situations, may allow an attacker to infer data values previously used(left behind) in floating point registers, vector registers, or integer registers. RFDS only affects Intel Atom® processors. (BTW the E Cores on Raptor Lake and Alder Lake are included)