A blog about the development of a general-purpose solution for mitigating cold-boot attacks on Full-Disk-Encryption solutions.

The concept

Cold boot attacks are a major risk for the protection that Full-Disk-Encryption solutions provide. Any powered-on computer is vulnerable to this attack and until now there has been no general-purpose solution to this problem.

This entry details my solution for mitigating cold boot attacks. Future posts will delve into additional details and describe what other ideas (and problems) were considered on the path to finding a general-purpose solution.

Why is this blog called "Frozen Cache"? Because we're proposing the use of the CPU cache for thwarting cold boot attacks (at least on most X86 systems). In contrast to most blogs, the entries of this blog will appear in normal chronological order on the website (for a more paper-like reading). Feeds however, will be sorted as expected (reverse chronological order).

The concept is easy: by switching the cache into a special mode one can force that data remains in the cache and is not written to the backing RAM locations. Thus, the encryption key can't be extracted from RAM. This technique is actually not new: LinuxBIOS/CoreBoot calls this Cache-as-RAM. They use it to allow "RAM access", even before the memory controller is initialized.

The following (simplified and technically not 100% correct/complete) steps load and maintain a 256 bit encryption key in the CPU cache. The demo assembly code assumes the encryption key is stored at linear address X in RAM on a page boundary for simplicity:
  1. Load the encryption key from RAM into some CPU registers (like the SSE registers)

    movq [X], %xmm0
    movq [X+8], %xmm1
    movq [X+16], %xmm2
    movq [X+24], %xmm3

  2. Overwrite the encryption key in RAM with a zero-value

    movq 0, [X]
    movq 0, [X+8]

    movq 0, [X+16]
    movq 0, [X+24]

  3. Flush the cache (thus truly overwriting the encryption key in RAM)


  4. Add the desired RAM region to the CPU's MTRR (the 4K segment containing the key)

    movl (X | MEMORY_TYPE_WRITEBACK), %eax
    xorl %edx, %edx
    movl 0x200, %ecx
    movl ( ~(1) | MTRR_VALID ), %eax
    movl 0x1, %edx
    movl 0x201, %ecx

  5. Disable/freeze the CPU's cache (CR0.CD=1)

    movl %cr0, %eax
    orl 0x40000000, %eax
    movl %eax, %cr0

  6. Write the encryption key from the CPU registers to RAM (data remains in the cache, doesn't get written to memory)

    movq %xmm0, [X]
    movq %xmm1, [X+8]
    movq %xmm2, [X+16]
    movq %xmm3, [X+24]
"Disabling/freezing" the CPU's cache severely degrades the performance. However, this seems acceptable if one considers that this special mode only needs to be set whenever the screen is locked (all efforts are pretty much worthless if an unlocked laptop is stolen). A very first proof-of-concept test on Linux shows that there's quite a bit of performance optimization necessary to make even just the act of unlocking the GUI an acceptable experience (from a performance/usability perspective).

Please note that this post only described the very basic concept, there are many aspects that haven't been covered. Upcoming posts will address things like multi-CPU/Core issues, performance considerations/optimizations and lots of other stuff.

No comments:

Post a Comment