Spectre
A processor guesses which way a branch will go and runs ahead on the guess. When it guesses wrong it throws the work away, and the architectural state, the registers and memory a program can see, is put back as if nothing happened. The microarchitectural state is not. The cache remembers what the abandoned instructions touched, and that memory can be read by timing. This page measures the timing channel on its own arrays, because that half is honest to run, and simulates the speculation, because a working version of that half is an exploit.
It ran the code before it was allowed to
1 The clock, measured, because everything the channel does lives inside what it can resolve
First, the clock. Everything on this page that measures lives inside what the clock can resolve, and after Spectre browsers made the clock deliberately blunt.
2 The cache timing channel, reading back a byte the page chose over its own arrays
The channel, measured on this machine
A byte the page chose is left in the cache, then read back by timing which cache line comes fast. No bounds check is bypassed and no memory outside this page's own arrays is touched. This is the readout half of Spectre without the speculation, which is the half that is honest to run.
3 A model of the misprediction: the shadow read runs, leaves a trace, and unwinds committing nothing
The speculation, as a model
A working version of this half reads memory it should not, which is an exploit and is not something this page builds. What follows is a model of a branch predictor, and it reads a byte the page chose rather than memory out of bounds. What it shows is real: the guess runs the shadow read and leaves a trace, then unwinds.
| The predictor | Its guess | The shadow | What committed |
|---|
4 Why the browser clock is blunt, which is where the False Sharing loop closes
Why the clock in your browser is blunt
The channel above is exactly why performance.now() had its precision cut, and why shared memory and its fine clock now come back only for a page that is cross-origin isolated. Those are Spectre mitigations. Google's own proof of concept leaked about one kilobyte a second on Chrome 88, with a timer of five-microsecond precision, and about sixty bytes a second with a timer of one millisecond or worse.
False Sharing, earlier in this group, had to satisfy that isolation to measure two threads contending for a cache line at all. The mitigation it worked around is this machine. That is the loop closing: the reason one page could barely measure is the attack this one explains.
These ran in this browser when the page loaded. Each claim, whether it held, and the number behind it.
| claim | held | measured |
|---|---|---|
| the channel has one cache line per byte value, so it can encode any byte | yes | 256 lines a stride of 256 apart |
| when the channel is confident, the byte it recovers is the one that was sent | yes | the channel was never confident on this machine, so there is nothing to be wrong about: a fact about this clock, not a pass earned |
| recovery reads the timing of a line, never the value stored in it | yes | the recovered index is the fastest line, decided by performance.now() |
| the clock's granularity is measured, because the channel lives inside it | yes | smallest step 0.1000 ms, blunted on purpose after Spectre |
| the modelled misprediction touches the cache but commits no register | yes | the shadow saw 0x99, and every committed read is an in-bounds one |
| without training the branch is predicted correctly and the shadow never runs | yes | an untrained predictor does not run the shadow path, so there is nothing to leak |
What is real here, and what is not
The channel is measured; the speculation is simulated. That line is the point
Spectre has two halves. Reading data out of the cache by timing is ordinary measurement of the page's own arrays, so this page does it for real. A processor speculating past a bounds check into memory it should not touch is a working exploit; Google published one, and a teaching page does not need it to teach the mechanism. So the speculation is a model, labelled as a model everywhere it appears, and it reads a byte the page chose rather than memory out of bounds. A visitor should leave knowing which half their own computer just did.
Nothing here reads memory it should not
Every array on this page is one the page allocated. The channel encodes and recovers a byte the page itself chose. The simulation's out-of-bounds read is modelled as returning that same chosen byte, not as reading real memory. There is no bounds check to bypass here because there is nothing behind it worth taking.
The channel may not work on your machine, and that is a real answer
Whether a cached read can be told from an uncached one depends on the clock, and the clock was blunted precisely to stop this. When the rounds do not agree the page says the channel was too noisy here rather than showing a byte it did not really read. That is the same honesty False Sharing uses about its own measurement.
The simulated predictor is a coin with a memory, not silicon
It counts how often the branch was taken and predicts the majority. Real branch predictors are far more elaborate, with history tables and pattern matching. None of that changes the one fact the model is for: a predictor trained on in-bounds accesses will speculate in-bounds on an out-of-bounds index, run the shadow read, and leave a trace before it unwinds.
Architectural state is restored; microarchitectural state is not
The precise names matter here. Architectural state is what a program can read: its registers and memory. Microarchitectural state is the machinery underneath, including which lines are in the cache. When a misprediction unwinds it restores the architectural state exactly, which is why the CPU is considered correct. It does not restore the cache, because the cache is supposed to be invisible to correctness. Spectre is the discovery that it is not invisible to timing.
Sound: no
Nothing here is a duration a person could hear.
Sources
- Paul Kocher and others, Spectre Attacks: Exploiting Speculative Execution, IEEE Symposium on Security and Privacy 2019 — the paper that named it.
- Google Security, A Spectre proof of concept for a Spectre-proof web, 2021 — the leak rates at each timer precision, and why the clock was blunted.
- Logical Art, the studio this belongs to.