내 연구 노트들 싹 취합해서 만들어진 ai-written post임
동아리에 연구자료 하나 내야하는데 적합한거 찾아쓰기 귀찮아서 진행중인걸로 넣었음
DRAM Interposer - Dram Page Cache Manipulate
The idea I’d sketched out — and had been researching a bit — was this: sit between the DIMM and the memory controller, watch write activity on the bus, and whenever data matching a page-cache pattern appears on the bus, remember that address; then, when a read to that bus address is detected, cut the DIMM module off from the bus and respond in its place.
It started from a somewhat contrarian question. Nobody suspects RAM in a computer. Write to it and it’s stored; read it back and out comes the same thing — we just believe that. The CPU, the OS, and applications all verify each other so diligently, yet the assumption that the memory module itself might lie sits outside the threat model. So what if a DIMM tampered with somewhere in the supply chain is itself the attacker? How safe is today’s computer, really? That was the starting point.
The malicious DRAM here isn’t just faulty RAM. The assumption is that the DIMM contains active circuitry watching bus traffic and able to choose what response to emit when it wants to.
CPU
│
▼
Memory Controller
│
│ DDR Memory Bus
▼
┌──────────────────────────────┐
│ Malicious DIMM │
│ │
│ Traffic observation │
│ Pattern / address learning │
│ Response selection │
└──────────────┬───────────────┘
│
▼
DRAM chipsTwo stages, as above: sniffing the commands and data crossing the bus, and substitution — emitting a different value instead of the real memory response under specific conditions. What makes this model attractive is that it needs no driver planted and never has to expose itself as a PCIe device. From the system’s point of view it must look like the most ordinary RAM possible.
Linux
The first thing I looked into after the idea struck was Linux’s memory structure. Fine, say you can tamper with the memory bus — you still need data worth tampering with.
First I considered tampering with memory like each process’s variables or code segments, but that means manhandling essentially all of memory and the complexity at the high level gets far too great, so: rejected.
What I thought of next was tampering with the page cache, because it was a relatively simple(?) vector to manipulate.
I then dug a bit into the Linux kernel’s mm, confirmed the page cache’s structure, and came up with a way to detect and tamper with the folio struct.
In Linux, ordinary file read/write and mmap all ultimately go through the page cache. The kernel docs describe the page cache as the main layer where users and the filesystem meet.
File
│
▼
Linux Page Cache
│
▼
Folio / physical memory
│
▼
Memory Controller
│
▼
DRAMThat made the page cache a pretty interesting observation target. I figured that if I could just get file contents to land in memory repeatedly, I might see that data’s patterns and positional relationships on the bus. Besides file contents, structurally distinctive byte patterns like filesystem metadata were candidates too.
But the snag was that even if you find a pattern, identifying the object is hard… I hit a wall. Consider the following:
- The same byte sequence can appear again in completely unrelated data.
- Requests from multiple cores are interleaved, and scrambling means you can’t read the bus as a contiguous file stream keyed on address.
- There are paths that bypass the page cache entirely, like
O_DIRECT.
So the page cache is a likely path for file data to appear in memory, not an all-purpose window that explains every file access. Nor does being in the cache mean the data is immediately visible on the DRAM bus.
At this point the question shifted from “can’t I just find the header and read the bytes after it?” to “how do I verify the relationship between the data I observed and the system’s memory objects?“
cache
If you want to see the bus, requests have to actually reach the DIMM. If the data is still in CPU cache, re-reading the same value however many times never invokes the memory controller or DRAM at all.
CPU
│
├─ L1 hit ───────────────┐
├─ L2 hit ───────────────┤ handled inside the CPU
├─ LLC hit ───────────────┘
│
└─ LLC miss
│
▼
Memory Controller
│
▼
DRAMIn other words, however well you build the interposer, if the request never reaches the DIMM you can neither see it nor change it. Membuster, a study of off-chip memory bus attacks, lays this down as a core premise too. A DRAM request only becomes visible on the bus after an LLC miss.
Hence the cache eviction problem follows. You can pressure the LLC with large memory accesses and then measure whether LLC misses on the target data increase. But these two must be clearly distinguished.
| What you can observe | What you must not claim |
|---|---|
| The LLC miss rate changes | You evicted a specific cache line at exactly the moment you wanted |
| DRAM requests occur more often | Those requests are requests for the file you want |
| Bus traffic increases | You reliably recovered the meaning of that traffic |
Pressuring the whole cache and pushing one specific piece of data all the way to DRAM are problems of entirely different difficulty.
Physical address != DRAM address
And the physical address the OS uses doesn’t map to one location on the DIMM as-is. The memory controller chops the address up and scatters it for performance and parallelism.
Physical address
│
▼
Memory Controller
│
├─ Channel
├─ DIMM / rank
├─ Bank
├─ Row
└─ Column
│
▼
Actual DRAM locationThe real mapping involves interleaving and address-bit combinations, and it differs per platform. DRAMA is the landmark prior work analyzing what this mapping means at the channel/rank/bank level.
So a naive assumption like this simply doesn’t hold.
physical address 0x1234
==
DRAM location 0x1234For the interposer to tie an observation to specific data, it also has to know the relationship between the address the CPU sees and the DRAM commands. This isn’t a byte-search problem; it’s a systems problem tying together the cache hierarchy + memory controller + address mapping.
Why I started from old DDR3 of all things
Early on I looked at an old Xeon E5-class + DDR3 environment. Starting from a modern platform mixes “is plaintext even visible on the bus?” and “can memory encryption be beaten?” into one question.
Establishing a simple unencrypted baseline first and then layering defenses on top one at a time makes separating the questions far easier. Picking old hardware doesn’t mean I’m out to break modern systems — it’s an experimental design for looking separately at the threat model’s basic preconditions and at what changes once encryption is in play.
Obviously this baseline is not equivalent to the security level of a real production environment. Generalizing these results to modern servers would require separately examining per-generation memory controllers, encryption features, boot configuration, and DIMM structure.
Memory encryption changes the game
With memory encryption on, data leaving the CPU isn’t plaintext. Intel’s TME documentation states flatly that only ciphertext exists on the external memory bus and in DRAM, and plaintext exists only inside the processor.
CPU ───── meaningful plaintext ─────> DRAMCPU ─────────── ciphertext ──────────> DRAMThat kills nearly all of the content-based detection described earlier. A model that infers meaning from file strings or kernel struct patterns doesn’t work the same way anymore.
But don’t confuse encryption with integrity here. The same Intel document states that TME does not itself prevent memory modification. Making something unreadable, and making it unmodifiable / unable to be replayed with an old value, are separate security properties.
| Protection | Plaintext bus observation | Arbitrary modification | Replay/substitution |
|---|---|---|---|
| Plaintext DRAM | Possible | Potentially vulnerable | Potentially vulnerable |
| Memory encryption | Heavily limited | Needs separate review | Needs separate review |
| Encryption + integrity + freshness | Heavily limited | Detectable/rejectable | Strongly limited |
Freshness here sits a level above merely “is the format valid?” To block a replay that returns a previously valid block verbatim, you have to design state such as versions or counters together with integrity verification.
The trust boundary a hash tree draws
Drawn very simply, a memory-block integrity verification structure looks like this.
Trusted root
/ \
Hash Hash
/ \ / \
Block Block Block BlockThe root and verification state live in the trusted region inside the CPU, and if a block read from external memory fails to satisfy that relationship, the system must not accept the value as legitimate data. A real design doesn’t end at the hash tree — storage location, caches, counters, and boot-time keys and state all have to be considered together.
In summary, defense rests on these three axes.
Memory confidentiality
+
Memory integrity and freshness
+
Trusted boot-time enforcementIf you’ve decided not to trust DRAM outside the CPU, you have to carry confidentiality and integrity together. You can’t claim memory encryption alone solves the tampering problem too.
Building it in hardware is another story
Conceptually it sounds like you just slot one circuit in the middle of the DIMM. But the DDR interface has to honor fixed response latencies and burst behavior, and the moment you insert something in the middle you introduce signal-integrity issues and extra delay.
Read command
│
│ fixed protocol timing
▼
Data burstWhat the intermediate circuit has to do every single time is no small task.
- Decode the command and address.
- Compare against the state observed so far.
- Decide whether to let the real DRAM response through.
- If needed, produce a different response within the fixed timing budget.
I don’t intend to spell out signal-level implementation procedures in this post. And I think the more research-relevant question is closer to “what is the minimum observation/intervention capability this threat model actually needs?” than “can you control all of DDR in real time?”
A design that just lets most traffic flow down the normal path and only makes decisions under limited conditions seems the more plausible candidate in practical terms. Of course, that too is a hypothesis that would need verifying on real hardware.
For reference
If you want more background on DRAM address mapping and memory attacks, start with the DRAMA and Membuster papers.
The repository below is not an implementation of this research — it’s a public tool for DRAM fault and Rowhammer-family experiments. I’m linking it purely as a reference for understanding memory systems experimentally.
Touching the same DRAM doesn’t make it the same attack model. Rowhammer induces physical faults in cells; what I was looking at is active hardware inserted via the supply chain observing traffic or interposing on responses.
What I confirmed
Structural facts confirmed:
- The page cache is an important path by which ordinary file access reaches physical memory.
- If data remains in CPU cache, you can’t see that access on the DRAM bus.
- There is a platform-specific mapping between physical address and actual DRAM location.
- Memory encryption makes plaintext bus observation substantially harder.
- Encryption, integrity, and replay prevention are distinct goals.
Ultimately a trust boundary problem
Normally the CPU, OS, firmware, and memory are treated as one lump of trusted territory. But the moment you decide not to trust DRAM, the boundary gets redrawn.
┌────────────── TRUSTED ──────────────┐
│ CPU │
│ Memory controller │
│ Key / integrity state │
└────────────────────────────────────┘
│
│ encrypted + authenticated
▼
┌───────────── UNTRUSTED ─────────────┐
│ Mainboard traces │
│ DIMM │
│ DRAM chips │
└────────────────────────────────────┘If you’re actually auditing defenses, these questions matter more.
- Does it support memory encryption?
- Is that actually enabled?
- Is there integrity and freshness verification?
- Is the protection state verified at boot and enforced by policy?
- Can you verify DIMM provenance and change history in the supply chain?
Wrapping up
I’m screwed.
Maybe I’ll take this idea straight over to SSDs and research something like automating malware implantation into old Excel files.
