Module: Speculative Execution
Spectre
Robert Wasinger
Arizona State University
Spectre
Leverages speculative execution by training the
CPU branch predictor to speculate incorrectly
Past results may indicate future performance
The CPU branch predictor uses past execution to make predictions
By repeatedly branching in one direction, the predictor can be biased
CPU Branch Predictors
mov rdi, [rdi]
mov rax, [rax]
cmp rax, rdi
jz
1
0
010110
Branch History
CPU Branch Predictors
Branch Predictor
mov rdi, [rdi]
mov rax, [rax]
cmp rax, rdi
jz
State Machine 1
State Machine 2
State Machine 3
State Machine 4
State Machine 5
1
0
010110
Branch History
Prediction:Jump!
CPU Branch Predictors - 2-bit counter
Consistently
Taken
Probably
Taken
Probably
Not Taken
Consistently
Not Taken
Not Taken
Taken
Not Taken
Taken
Not Taken
Taken
How to Train Your Branch Predictor
Training is physical core specific
In many cases, training does not take many runs to start showing results!
Spectre Attacks
Two variants: V1 and V2
V1: Takes advantage of conditional branches
V2: Takes advantage of indirect branches
Unlike meltdown,
the spectre exploit occurs inside the victim process.
Spectre V1
if (x < array1_size) {
y = array2[array1[x] * 4096];
}
This block of code never executes if x > array1_size.
Spectre V1 relies on the fact the CPU can speculate it does.
Spectre V1 - Training
if (x < array1_size) {
y = array2[array1[x] * 4096];
}
Repeatedly passing the check trains the branch predictor to enter this block
array1_size = 10
x = 1
In Memory
array1[0] = 0
array1[1] = 1
array1[2] = 2
.
.
.
private_var: “secret value”
Spectre V1 - Exploiting
if (x < array1_size) {
y = array2[array1[x] * 4096];
}
Speculatively, array1 will be indexed out of bounds by a transient instruction. This allows arbitrary memory access while speculating.
array1_size = 10
x = 1000
In Memory
array1[0] = 0
array1[1] = 1
array1[2] = 2
.
.
.
private_var: “secret value”
Spectre V1 - Exploiting
if (x < array1_size) {
y = array2[“s” * 4096];
}
Speculatively, array1 will be indexed out of bounds by a transient instruction. This allows arbitrary memory access while speculating.
array1_size = 10
x = 1000
In Memory
array1[0] = 0
array1[1] = 1
array1[2] = 2
.
.
.
private_var: “secret value”
Spectre V1
if (x < array1_size) {
y = array2[array1[x] * 4096];
}
If array1_size takes a long time to access, the CPU can speculate:
Spectre V1
We’ve seen the pattern inside the conditional block before…
It leaks information via the cache that can be read via flush & reload!
y = array2[array1[x] * 4096];
DEMO
Spectre Attacks
Two variants: V1 and V2
V1: Takes advantage of conditional branches
V2: Takes advantage of indirect branches
Spectre V2
This example jumps to an address defined in memory at 0xdeadbeef �
mov rdi, [rdi]
mov rsi, 0xdeadbeef
call QWORD PTR [rsi]
The CPU will attempt to predict where to jump and continue execution.
Training this predictor can cause arbitrary instructions to be executed as transient instructions!
Could be any “slow” instruction that encourages speculation
Spectre V2
The attacker influences branch predictor by calling:
Executing again in a different context may trigger jumping to a spectre gadget
Spectre Gadgets
Instructions that when speculatively executed, influence microarchitecture state
Spectre Gadget
y = array2[array1[x] * 4096];
Influencing rbx or rdx changes what address will be speculatively accessed
Here, the data at rbx+rdx can be leaked via a cache side-channel
mov rdi, [rbx+rdx]
mov dl,byte ptr [rdi]
Spectre Variations and Beyond
Many other variations have been theorized or confirmed
All follow a similar pattern