4
votes

In the spectre paper, there is an example which exploits an out of bound array access (Section 1.2). The code is

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

The process is to train the correct path with some valid x values. Then an invalid value of x is given and the same time assume arra1_size is uncached. Since the branch predictor thinks the condition is true, it will speculatively fetches array2's offset.

Now, here is the question. In the speculative execution, it has to fetch array1[x] where x is malicious and it is out of bound. So, array1[x] is actually invalid! Then what is the attack?! no valid data is fetched!

Can anyone explain that for me? What is misunderstood here?

3
I think your answer in that topic is not directly related to my question. What I wonder is the out of bound exception. Lets say an array has 10 items, so the range is 0..9. Now the cpu speculatively fetch some items from index 8. Those are 9, 10, 11, 12. array1[10] is not valid and it should throw an exception prior to the attach that will take place. Isn't that?mahmood
Made an answer below. (Here is more explanatory on speculative attack). The speculative executed code does not give an exception (otherwise a code like, in C, if (arr[x] != NULL) *arr[x] = 3;, where *arr[x] = 3 can be speculatively run when x is NULL, would trigger an exception which the user shouldn't get, because the branch condition will eventually evaluate to false and the speculative run code is not retired.Breaking not so bad

3 Answers

4
votes

So, array1[x] is actually invalid! Then what is the attack?! no valid data is fetched!

That is the main point of the attack. The index (i.e. x) might be so big, so we are able to access the data we should not be able to access.

For example, if our code is in JavaScript sandbox or Java Virtual Machine, we will be able to access data outside the sandbox/virtual machine.

Even more, the speculative execution might access kernel pages, i.e. pages we have no privilege to access to. That is Meltdown.

Here is my Spectre-Based Meltdown proof of concept in just 99 lines you might find easier to understand:

https://github.com/berestovskyy/spectre-meltdown

1
votes

Spectre (unlike Metldown) works thanks to how the CPU handles branches prediction. From the same paper you refer to

[2.3] Speculative execution requires that the processor make guesses as to the likely outcome of branch instructions. Better predictions improve performance by increasing the number of speculatively executed operations that can be successfully committed.
(...)
To predict whether a conditional branch is taken or not, the processor maintains a record of recent branches outcomes.

Then

[4] The code fragment begins with a bounds check on x which is essential for security. In particular, this check prevents the processor from reading sensitive memory outside of array1. Otherwise, an out-of-bounds input x could trigger an exception or could cause the processor to access sensitive memory by supplying x = (address of a secret byte to read)−(base address of array1).

But the paper goes on and explains why this might work anyway, not triggering an exception:

Unfortunately, during speculative execution, the conditional branch for the bounds check can follow the incorrect path. For example, suppose an adversary causes the code to run such that:

• the value of x is maliciously chosen (and out-ofbounds) such that array1[x] resolves to a secret byte k somewhere in the victim’s memory;

array1 size and array2 are not present in the processor’s cache, but k is cached; and

• previous operations received values of x that were valid, leading the branch predictor to assume the if will likely be true.

Finally the CPU, after the x value is evaluated to be too high, will effectively bypass the if body and will not retire the retrieved y value. However the cache status has changed, and this is where the attack takes place:

The processor realizes that its speculative execution was erroneous, and rewinds its register state. However, on actual processors, the speculative read from array2 affects the cache state in an address-specific manner, where the address depends on k

The unauthorized access to array1[x] is made during the speculative code execution, and thus does not raise an exception because the CPU "knows" that the outcome of that speculative execution will not be retired if the condition from the branch that precedes happens to be false.

(Unlike Meltdown which triggers an exception when the executed user code does access an unauthorized area - Meltdown exploits a race condition between the time taken to retire the exception and the few out of order instructions that follow that access which are pre-executed (and that will not be retired)).

0
votes

My understanding (simplified) (could be wrong):

When the x is higher then the bounds the processor will load data that is stoard somewhere else. (a bit like an bufferoverflow)

For example when the Data is Saved like this:

1 <- Start Array

2

3 <- Start Secret Data

4

With an x greater that the bounds it can read for example the 3 (in the paper this could be everything and its named k). Then the 3 gets cached

The 3 is used to load the data in the second array. The Processor realize the mistake and remove it(3/ k) from the cache.

Then the Attaker can revocer this 3 (or in the paper k) with different methods. For example try a number and and measure loading time then repeat everything from the begining

(sry for bad english)