Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

GhostWrite Memory Interaction (Section 6.1.1)

We recommend to compile the experiments in this directory on the machine itself.

Experiment Group 1 (Cache conditions)

conditions.c implements the first experiment. We execute GhostWrite on a cache line with specific states such as dirty or non-dirty. Compile and run with:

make && sudo ./conditions

Expected output:

Virtual address:        3fdd3b2000
Physical address:         8a8a5000

[!] Initial memory cache state is uncached
===================================================

[+] Maccess (non-dirty) *before* + evict *after*
        -> 10000/10000

[+] Maccess (non-dirty) *before* + flush *after*
        -> 10000/10000

[+] Maccess (non-dirty) *before* + nothing *after*
        -> 0/10000

===================================================

[+] Maccess (dirty) *before* + evict *after*
        -> 0/10000

[+] Maccess (dirty) *before* + flush *after*
        -> 0/10000

[+] Maccess (dirty) *before* + nothing *after*
        -> 0/10000

===================================================

[+] Fence *before* and *after*
        -> 0/10000

[+] Fence *before* and flush *after*
        -> 10000/10000

===================================================

[+] Maccess + Flush *before* and M+F *after*
        -> 10000/10000

[+] Maccess + IFlush *before*
        -> 0/10000

This behavior undermines the hypothesis that GhostWrite interacts directly with physical memory and that the write does not travel through the CPU's cache hierarchy. For all experiments, we ensure that the attacked memory address is initially cached. The first 3 experiments show that after a GhostWrite write, the changed value is only observed when the attacked memory address is removed from the cache and thus served from main memory. The next 3 experiments show that when a dirty cache line is flushed or evicted and thus rewritten to main memory, it also overwrites the value injected by GhostWrite again. The next 2 experiments aim to show that the previous observations are not due to fencing behavior. The last 2 experiments show that the behavior requires an actual data flush and not an instruction flush.

Experiment Group 2 (Performance Counters)

perf.c implements the second experiment, querying performance counters. Compile and run with:

make && sudo ./perf

Expected output:

Virtual address:        3fc167f000
Physical address:         8e6f5000

 ===== L1d Misses =====
baseline: 0.007000
exploit: 0.000000
 ===== L2d Misses =====
baseline: 0.000000
exploit: 0.000000
 ===== dTLB Misses =====
baseline: 1.000000 (sum: 10000)
exploit: 1.000000 (sum: 10000)

This group of experiments aims to further strenghen the previous hypothesis. We analyze the performance counters for L1d and L2d misses together with the counters for dTLB misses. For none of these counters, we observe an increase when the GhostWrite primitive is executed. Thus, further hinting towards writes that completely skip the cache hierachy. As not even the dTLB is queried, which would be required for accesses to a virtual address, it hints that the GhostWrite primitive directly interacts with physical memory addresses.

The hypothesis of a memory write that directly interacts with physical memory addresses would not only explain why the cache hierachy is skipped but also why all virtual memory isolation are skipped as well.

Experiment Group 3 (Duplicate Mappings)

make && sudo ./duplicate_mapping

Expected output:

Mapping1:       3ff7ad2000
Mapping2:       3ff7ad1000
Physical address (mapping1):        130bd5000

Physical address (mapping2):        130bd5000

Reading from uncached mapping
	cache misses: 1.000300

	-> 10000/10000

Reading from cached mapping
	cache misses: 0.000100

	-> 0/10000

This experiment further strenghens the hypothesis. Two virtual address mappings point to the same physical address. This physical address is then updated using the GhostWrite primitive and only the uncached mapping observes the new value. The cached mapping, which is still served from the cache and not from main memory, still reads the original value.