SMASH is a new JavaScript-based attack that gives the attacker an arbitrary read and write primitive in the browser. It does not rely on software vulnerabilities or bugs, but instead takes advantage of the much harder to mitigate Rowhammer bug in hardware to initiate the exploit chain.
However, exploiting the Rowhammer bug to trigger bit flips is not an easy task. Modern memory modules come equipped with a dedicated in-memory defense against Rowhammer, called Target Row Refresh (TRR). Although previous work has shown that TRR is vulnerable to more advanced access patterns than ordinary double-sided Rowhammer, constructing such patterns from inside high-level JavaScript is difficult.
SMASH demonstrates, however, that it is not impossible to build fast, Rowhammer-inducing, and TRR-evading access patterns through cache eviction, without relying on low-level flushing instructions such as CLFLUSH. In addition, our research yielded a new insight about TRR. We were able to synchronize memory requests with the refresh commands sent to DRAM by the memory controller, allowing for very fine-grained control of when and which addresses are exposed to TRR—and therefore also when and which addresses are not.
Our work confirms that the Rowhammer bug continues to threaten Web users. Worse still, our insights on synchronization show that the attacker has more control than previously thought, and will make it even harder to build the proper Rowhammer defense we need as long as the bug itself persists.
Please find below a quick demo of our ability to trigger bit flips on TRR-enabled DDR4, through JavaScript.
To trigger TRR-bypassing Rowhammer bit flips from the browser we thought we needed to overcome two main challenges.
- Memory Management. Since patterns like 18-sided Rowhammer span over large contiguous allocations we needed to figure out a way to overcome the limitations imposed by the browser memory allocator.
- Efficient cache eviction. We need to generate such large access patterns that can circumvent the in-DRAM TRR mitigation while efficiently evicting our (too many) aggressors from the caches.
Dealing with these two challenges was already quite something. But eventually we did manage (see below link to section). Now try to imagine our reaction when after achieving this we still saw no flips? š
Well, it turns out there was more to it than we thought (sigh).
We discovered that batching together a bunch of CLFLUSH instructions in our native implementation gave the memory controller enough time to synchronize our many-sided patterns with the execution of REFRESH commands. And this allowed us to generate self-synchronizing access patterns. This changed when moving to JavaScript where we had to get rid of CLFLUSH.
In simpler terms, no CLFLUSH == no synchronization. ā we now need to time our access pattern just right.
To trigger TRR-bypassing Rowhammer bit flips from the browser we thought we needed to overcome two main challenges.
Self-eviction
The main difference between classic Rowhammer access patterns and the ones proved to bypass in-DRAM mitigations is in the number of aggressor rows. Indeed, the many-sided Rowhammer may require up to 19 aggressor rows in some cases.
Common eviction strategies do not apply anymore because they generated too many cache misses for each aggressor row eviction, slowing down the hammering loop and preventing bit flips occurrence.
Therefore our key goal is to accelerate the eviction reducing the number of cache misses. For this purpose we designed a novel self-evicting hammering pattern.
Carefully picking aggressor rows from two different cache sets, we crafted an access pattern in which cache misses are not useless but they occur only when one aggressor row is evicted to make room for another aggressor row. Each cache miss results in one memory request which is part of the hammering.
To achieve a self-evicting hammering pattern, the access sequence must be narrowly arranged. The first parameter to set is the number of aggressor rows that will simultaneously reside into the same cache set.
For instance, in a 18-sided hammering pattern each cache set will contain three aggressor rows at any point in time. Then, the access pattern will looks like:
While the baseline (native TRRespass) pattern looks like:
Here the aggressors get accessed sequentially and then evicted with the CLFLUSH instruction.
The self-evicting pattern is 30% faster than the baseline one. However it fails in triggering bit flips. You may wonder why. Well, we did so too. Just keep on reading…
Synchronization – A survey into synchronized hammering patterns
So next we tried to get the timing just right.
In a first experiment we started inserting NOPs right after each iteration of the self-evicting pattern to act as padding:
In this way we slowed down the hammering loop and we achieved the same execution time of the baseline pattern. Surprisingly the bit flips were back. So we just played around with the number of NOPs while looking for bit flips.
We observed that too many NOPs didnāt trigger any bit flips āā too slow. And that too few NOPs didnāt trigger bit flips either āā too fast? š¤. This didnāt make too much sense to us.
Plotting the data of the previous experiment we discovered a dependency between the REFRESH command and the in-DRAM mitigations. In fact, it seems that when synchronizing our pattern properly with the REFRESH command we could avoid our aggressor rows from being sampled triggering bit flips once again.
Now, letās try to explain this graphically
In the original native implementation we batch all the CLFLUSH together (Fig a). Here the REFRESH operation will always be scheduled in parallel to the CLFLUSH, automatically synchronizing our pattern to it and therefore to the in-DRAM sampler.
In our initial self-evicting pattern we interleaved DRAM accesses with cache hits that generated time gaps large enough to schedule a REFRESH command. This desynchronizes the pattern getting our aggressors sampled (Fig b).
The varying NOPs experiment is represented in Fig C-D. Here, too few NOPs (Fig C) allow the REFRESH to be desynchronized (no flips š¢), while padding with more NOPs (Fig D) allow you to perfectly synchronize (i.e., yay flips š). So now the question becomes: where is the sweet spot?
We discovered the sweet spot after a bunch of iterations and experiments. And it is given by minimizing as much as we can the number of consecutive cache hits while finding a large enough number of NOPs so that the REFRESH will be scheduled by the memory controller while the CPU core execute the NOPs.
Yeah… we know⦠kind of a mess. But it trigger bit flips š
Show me the Code!
You can grab the code for SMASH at https://github.com/vusec/smash.
Demo
Papers
FAQs
What are the differences compared to previous Rowhammer attacks?
Rowhammer exploits in the browser are no news. Rowhammer.js, Dedup est Machina, and GLitch already show the possibility of exploiting the Rowhammer vulnerability from the browser.
So whatās the news? As it turns out, modern DDR4 chips embed in-DRAM Rowhammer mitigations. . In fact, in TRRespass we show how well-known Rowhammer access patterns no longer generate bit flips and how more aggressor rows are now required to fool the in-DRAM Target Row Refresh (TRR) mitigations. In SMASH, we tackle these issues (which normally prevent you from exploiting Rowhammer in the browser) and show that it is still possible to trigger bit flips from JavaScript. In addition, we show one can weaponize these bit flips (akin to GLitch) to obtain a bug-less (at least in software) arbitrary r/w primitive in the latest version of the Firefox browser in less than 15 minutes.
How can SMASH be mitigated?
SMASH relies on THP for crafting self-evicting patterns and on pointer corruption for pivoting to a counterfeit object. Disabling THP or ensuring pointers integrity would stop the current version of the attack. However, while disabling THP would lead to performance loss, protecting integrity of pointers can be done in software or in hardware. However, these solutions only stop the current instance of SMASH. We believe that bit flips are still exploitable and new attack vectors may be discovered.
Am I in danger?
First off, you should check if your system is affected by the Rowhammer bug. Then, if the THP interface is enabled in your system, then there is a good probability that your system is exploitable from the browser.
Acknowledgements
We thank our shepherd Vasileios Kemerlis and the anonymous reviewers for their valuable feedback. This work was supported by the European Unionās Horizon 2020 research and innovation programme under grant agreements No. 786669 (ReAct) and No. 825377 (UNICORE), by Intel Corporation through the Side Channel Vulnerability ISRA, by the Netherlands Organisation for Scientific Research through grants NWO 639.021.753 VENI āPantaRheiā, and NWO 016.Veni.192.262. This paper reflects only the authorsā view. The funding agencies are not responsible for any use that may be made of the information it contains.