RowHammer JS & BitFlipping

Based on the work completed by [1], following is my summary and review on the RowHammerJS & BitFlipping in general. I completed these notes as part of work in University of Oxford and towards GCHQ accreditation. All comments are my own.

A very brief introduction to DRAM, highlighting the main areas concerned in rowHammering.

Each cell has a capacitor and stores binary data based on a charge, a charged cell represents a binary value of 1, while a discharged cell represents a binary value of 0. DRAM is volatile memory and loses its charge over a period of time i.e. the retention rate, this means each cell needs to be frequently refreshed i.e. once every 64ms highlighted by [1] and defined by [4], if a cell is not refreshed data will be lost. DRAM implements cache via the row buffer. By-passing the row buffer is central to row hammering. Double sided row hammering as used by [2] is represented in the above diagram by accessing two aggressor rows either side of a victim row. A disturbance error / bit flip occurs in the victim row in at least one of the cells e.g. from the diagram one of the victim row circles (cells capacitor) value is flipped. Isolation of these cells is paramount to secure systems i.e. when accessing one cell neighboring cells should not be adversely affected, if isolation is vulnerable and the retention rate adversely affected it’s conceivable disturbances may occur, this means if a cell loses its charge prior to a refresh a cell can flip its bit. DRAM has scaled in recent years, this has led to an increase in cell density i.e. cells are packed closer together, as such isolation of cells could be adversely affected, this becomes a central theme for rowHammering.

Repeated (in the millions) access on a row has an effect on neighboring rows, this affect accelerates charge leakage on these nearby rows, as such if this leakage is faster than expected and before the refresh rate a disturbance can occur, i.e. a particular nearby cell loses its charge at an accelerated rate. As [4] DRAM specifications indicate a refresh rate of once every 64ms, as such if the leakage rate is greater than the expected leakage rate and the cell has not been refreshed within 64ms the cell will lose data.

This repeated access on a row is termed Row Hammering. For row hammering to be most effective two addresses (doublesided rowHammering) are required X and Y, both X and Y must represent two different rows, where these rows are in the same bank. It is important to note the victim are not the addresses accessed instead the victim is a close neighbor to X and Y. It is important to note [1] did not provide an exploit, instead they discussed an approach to an exploit. However further to [1] research, an exploit has been demonstrated by Google’s project zero team [2].

Each of the papers focused on different aspects.

[1] main focus was DRAM disturbance errors without directly accessing a victim row, instead neighboring rows are continually accessed (hammered), these cause disturbance errors in nearby rows i.e. the victim row. The net result of hammering is a disturbance error which is the equivalent of a bit flip, i.e. the binary cell value changes from binary 1 to binary 0 and vice versa. Central to these disturbance errors is flushing or purging cache i.e. purging the row buffer by using the native CLFLUSH command, this ensured DRAM addresses are accessed rather than the row buffer (i.e. the cache) since rowHammering is dependent on ensuring the addresses being hammered are within the same bank therefore purging the row buffer of a bank is paramount i.e. rowHammer requires the row Buffer to be by-passed. This paper [1] relied on native commands and required direct access to the host computer. A root exploit was not established, however, authors noted industry were aware of the row hammer concept since 2012. In this paper [1] selecting the physical addresses to hammer required knowledge of the underlining CPU memory management unit address mapping.

[2] However further to research completed by [1], an exploit has been demonstrated by Google’s project zero team [2], as part of this exploit address selection was reviewed i.e. how to determine X and Y without knowing the underlining CPU memory management unit address mapping. Google's team looked at both randomly selected addresses, and selecting addresses based on cache hits. Google's team found double sided row hammering (hammering rows either side of a victim row) to be most effective and implemented by "naively extrapolating" [2], (in my view intelligently guessing) addresses using

256k target address (first aggressor row)
256k victim address
256k target address (second aggressor row)

Google's team main contribution to the row hammering concept is they managed to present two exploits, and took up the challenge left by [1]. Exploit one by gaining root access to the kernel and a second by escaping a sandbox within the Chrome browser. As part of Google's write up, they mention possibilities for not using the native CLFLUSH command, and one in particular they suggest it might be possible to exploit row hammering via normal memory accesses and if this is possible a JavaScript implementation could be possible via typed arrays.

Both [1] and [2] rely on special instructions i.e. CLFLUSH and physical access to the hardware, and somewhat on knowledge of the underlining architecture. The high density (i.e. close proximity) of cells is a root cause of these disturbance errors. The rowhammer.js [3] exploit does not require physical access to the underlining hardware, special instructions such as CLFLUSH nor does it require prior knowledge of the address selection. Instead rowhammer.js is the first remote software invoked row hammer exploit independent of CPU. The authors have noted they have not provided a full root exploit, they have presented how rowHammer disturbance errors noted by [1] can be initiated via JavaScript, and it appears though not mentioned in the paper, they have taken up the challenge suggested by [2] related to JavaScript typed arrays.

Some key elements from this paper [3]

  • An optimized cache replacement policy agnostic to CPU, leading to not having a need for CLFLUSH command
  • A native code implementation without the special instruction
  • A JavaScript translation tool converting array indices into physical addresses
  • A JavaScript implementation to scan for vulnerable addresses
  • Some countermeasures are discussed

It should be noted this paper is not exploiting vulnerabilities in JavaScript or the web browser hosting the JavaScript engine. Its important to note the rows being hammered / accessed are not affected, instead neighboring rows demonstrate disturbance errors i.e. the bit flip.

The main approach implemented by [3] is to use standard memory accesses to produce an eviction (googles team mentioned this might possible(2) ), and in order to achieve this implement standard cache attack techniques by measuring timing i.e. a cache hit or a cache miss.

In order to implement row hammer in JavaScript and independent of native code instructions and to be architecture agnostic, an efficient cache eviction strategy needs to be designed as well as an ability to find sufficient information on physical addresses. In comparison to papers [1] and [2]; where [1] used knowledge of the underlining management unit, while [2] used 'intelligent guesses' i.e. 256k address space in addition both relied on the CLFLUSH command, paper [3] focuses on determining these row addresses agnostic to architecture, and furthermore removes the reliance on the CLFLUSH command.

One of the main objectives is to optimize the cache eviction process, this requires determining an access pattern. The idea is to obtain near 100% cache eviction and then reduce the addresses without reducing the eviction rate. On haswell CPU this eviction strategy produced an eviction rate more than 99.97%. In order to determine how effective their new eviction strategy; on haswell CPU authors compared their adaptive eviction strategy with LRU and the CLFLUSH instruction. The net result demonstrated the CLFLUSH command as one would expect all memory accesses are DRAM memory i.e. not cached, while the LRU eviction policy had 648 times more cache hits than the adaptive eviction policy. Central to this new eviction strategy is a timing attack, the authors use timing to determine if an address is cached or not. A cache hit will have a faster access time than a cache miss, therefore comparing the timing helps determine if a memory address has been accessed directly or accessed via cache.

Using the new eviction strategy the authors developed an implementation both in native code and in JavaScript without the special CLFLUSH. They concluded if a machine is vulnerable to their native code implementation, it is with a high probability the same machine is vulnerable to the JavaScript equivalent implementation. However, they also note a disturbance error has a higher probability when implementing native code and the CLFLUSH command.
This new eviction exploit was implemented in JavaScript, though the authors have highlighted the exploit is independent of programming language and JavaScript was selected due to its widespread adoption and use within web browsers. The paper has indicated JavaScript allows for the exploit to be implemented due to its near native code performance and is very well optimized in most modern web browsers. Firefox on Linux platform was chosen because the JavaScript engine makes it possible to identify parts of the physical address.

One of the countermeasures the authors mentioned was identified by [1], this countermeasure indicates increasing the refresh rate, it was highlighted a number of manufacturers have doubled this refresh rate to reduce the probability of attack, as such this is a mitigation strategy rather than a preventative one. According to [1] in order to prevent such disturbance errors the refresh rate would need to be increased 8 times, as such DRAM would spend close to 35% of its time refreshing. Authors found several guides on how to decrease refresh rates in an effort to increase performance as such would increase probability of a successful attack on such customized systems.

The authors suggest web browser manufacturers should introduce measures to prevent rowHammering attacks from JavaScript either by using hardware performance counters or determining if the system is vulnerable to rowHammering via CLFLUSH and therefore make a decision on slowing down JavaScript on these vulnerable machines. Authors note as part of this research all tests are conducted on Intel, further research work is required to evaluate various other CPU manufactures e.g. ARM and AMD, while also noting smartphones also have fast DRAM and should also be investigated for potential security vulnerabilities.

The fact row hammering can be initiated without the CLFLUSH command, and demonstrated via JavaScript, this presents a very significant security treat not only via modern web browsers but also to the significant number of server side JavaScript implementations e.g. nodeJS. Particularly those reliant on central package managers e.g. NPM, as this presents a central point of deployment.

[1] Yoongu Kim Ross Daly Jeremie Kim Chris Fallin Ji Hye Lee Donghyuk Lee Chris Wilkerson Konrad Lai Onur Mutlu, Carnegie Mellon & Intel Labs
Flipping Bits in Memory Without Accessing Them: An Experimental Study of DRAM Disturbance Errors

[2] Seaborn & Dullien

[3] Daniel Gruss, Clementine Maurice, Stefan Mangard
Rowhammer.js: A Remote Software-Induced Fault Attack in JavaScript

[4] JEDEC Standards DDR3 SDRAM