[GTALUG] Spectre type 2: Branch Target Injection

D. Hugh Redelmeier hugh at mimosa.com
Sat Jan 13 12:21:05 EST 2018


[background]

At the last meeting, I said that I hadn't yet understood the Spectre 
variant that uses the Branch Target Injection CVE-2017-5715.  I now
do.

Recall that Spectre and Meltdown use a side-channel for sneaking 
information past barriers.  Speculative execution of instructions are 
supposed to have no observable effect when the misprediction occurs. The 
side-channel is the CPU cache for memory: that can be affected by 
mispredicted speculation.

In the case of Meltdown, speculation is allowed to reference forbidden
memory.  An artifact of Intel's implementation.  It can be fixed over
by annoyingly expensive page table changes at the kernel / userland
boundary.  It can be fixed by an OS exploiting PCID feature added by
Intel with Haswell processors but that is made intricate by the PCID
field being too narrow.  This mitigation can be done once-and-for-all
in an OS.

Spectre comes in two forms: mispredicting a simple conditional branch
(one that can branch to a manifest location, or not) and mispredicting
an indirect branch.  To mitigate Spectre problem, each dangerous
conditional branch needs to have code added by the programmer (or
compiler).  This code is expensive so it isn't a great idea to add it
everywhere (which could be automatic).

The fix for dangerous conditional branches is easy: add an LFENCE
instruction.  Unfortuately that slows down processing quite a lot.
WebKit is using "index masking" instead, for speed.
<https://webkit.org/blog/8048/what-spectre-and-meltdown-mean-for-webkit/>

[foreground]

Now we get to Branch Target Injection, the second form of Spectre.

The indirect branch case is much trickier.  An indirect branch is
one where the target is not manifest in the instruction.  Instead, it
is somehow computed.  Think:

- call through a function pointer variable

- method call in an object oriented language (a call through a
  function pointer, at least in the general case)

- a return from a function

- a case statement

Fast processors nowadays predict where such a branch will lead.  The
heuristics used can be outsmarted by carefully crafted code and led
to speculate ANYWHERE in the address space.  This is awesomely scary.
You cannot add protective code on the target because there is no
single target.  This has similarities to the attack exploitation
method called "Return Oriented Programming": the attacker just has to
find a useful code fragment somewhere in your codebase and aim the
branch target prediction towards it.

Google researchers have devised a trick to prevent indirect branch
misprediction from doing a bad guy's bidding.  They constructed a
"retpoline" that essentially ties up misprediction in a harmless bit
of code.  See the "Construction (x86)" section of
<https://support.google.com/faqs/answer/7625886>
The cost is an ugly piece of code and no useful speculation.


More information about the talk mailing list