[PATCH 0/5] x86: CVE-2017-5715, aka Spectre

Alan Modra amodra@gmail.com
Mon Jan 8 14:36:00 GMT 2018


On Sun, Jan 07, 2018 at 04:36:20PM -0700, Jeff Law wrote:
> On 01/07/2018 03:58 PM, H.J. Lu wrote:
> > This set of patches for GCC 8 mitigates variant #2 of the speculative execution
> > vulnerabilities on x86 processors identified by CVE-2017-5715, aka Spectre.
[snip]
> My fundamental problem with this patchkit is that it is 100% x86/x86_64
> specific.

It's possible that x86 needs spectre variant 2 mitigation that isn't
necessary on other modern processors like ARM and PowerPC, so let's
not rush into general solutions designed around x86..

Here's a quick overview of Spectre.  For more, see
https://spectreattack.com/spectre.pdf
https://googleprojectzero.blogspot.com.au/2018/01/reading-privileged-memory-with-side.html
https://developer.arm.com/-/media/Files/pdf/Cache_Speculation_Side-channels.pdf

The simplest example of ideal "gadget" code that can be exploited by
an attacker who can control the value of x, perhaps as a parameter to
some service provided by the victim is:

	char *array1, *array2;
	y = array2[array1[x] * cache_line_size];

The idea being that with the appropriate x, array1[x] can load any
byte of interest in the victim, with the array2 load evicting a cache
line detectable by the attacker.  The value of the byte of interest
can then be inferred by which cache line was affected.

Typical code of course checks user input.

	if (x < array1_size)
	  y = array2[array1[x] * cache_line_size];

Spectre variant 1 preloads the branch predictor to make the condition
predict as true.  Then when the out-of-range value of x is given,
speculative execution runs the gadget code affecting the cache.  Even
though this speculative execution is rolled back, the cache remains
affected..

Spectre variant 2 preloads the branch target predictor for indirect
branches so that some indirect branch in the victim, eg. a PLT call,
speculatively executes gadget code found somewhere in the victim.


So, to mitigate Spectre variant 1, ensure that speculative execution
doesn't get as far as the array2 load.  You could do that by modifying
the above code to

	if (x < array1_size)
          {
	    /* speculation barrier goes here */
	    y = array2[array1[x] * cache_line_size];
	  }

But you could also do

	if (x < array1_size)
          {
	    tmp = array1[x] * cache_line_size;
	    /* speculation barrier goes here */
	    y = array2[tmp];
	  }

This has the advantage of killing variant 2 attacks for this gadget
too.  If you ensure there are no gadgets anywhere, then variant 2
attacks are not possible.  Besides compiler changes to prevent gadgets
being emitted you also need compiler and linker changes to not emit
read-only data in executable segments, because data might just happen
to be a gadget when executed.

However, x86 has the additional problem of variable length
instructions.  Gadgets might be hiding in code when executed at an
offset from the start of the "real" instructions.  Which is why x86 is
more at risk from this attack than other processors, and why x86 needs
something like the posted variant 2 mitigation, slowing down all
indirect branches.

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Gcc-patches mailing list