30

I saw that KeePass not only encrypts its password-database-file, it also can encrypt the passwords it holds in memory. This is just an example. I thinking of a new project dealing with sensitve / personal data and now I ask myself if I should encrypt the data hold in memory, too. This project would be implemented with Java SE and an additional android application. There will be no data stored in the cloud or on a server in this special case. Data from android will be imported by the Java SE Desktop application via cable connection.

But why is this necessary at all? Don't modern operating systems work with virtual memory management so that it is not possible for user-space / user-mode processes to access other processes memory?

Is it just another defense line if there is an OS vulnerability making foreign memory access possible? In that case I think it would be much easier to steal the data file and use a key-logger to catch the password the user enters instead of stealing the data through memory access.

Gilles 'SO- stop being evil'
  • 50,912
  • 13
  • 120
  • 179
user573215
  • 443
  • 1
  • 4
  • 5
  • 5
    The problem with encryption is that it only shifts the problem to where to store the key. – CodesInChaos Sep 18 '12 at 08:47
  • 3
    Data may be swapped out to the page file, and many OS do not clear the page file when shutting down. With physical access to the machine the page file can be easily accessed and searched (and there are ways to make it more likely that data of intrest is swapped out, and then one could pull the power cord to prevent the OS from shutting down...). Still, in memory encryption only makes it more work to access the encrypted data, since the code and key to decrypt it can be obtained by the same method... –  Sep 18 '12 at 11:21
  • 3
    "Don't modern operating systems work with virtual memory management so that it is not possible for user-space / user-mode processes to access other processes memory?" no, they don't. At least, not always. Windows lets you access the memory of any process run by the same user via an API. – Mints97 Mar 14 '15 at 14:52

7 Answers7

29

In a perfect world, you are right: there should be no point in keeping data encrypted in RAM. The OS should keep strong separation between processes, clear RAM when it is reallocated to another process, and, if the attack model allows for an attacker stealing the device afterwards and doing some harddisk analysis, encrypt the swap (or use no swap at all, which may make more sense for a device with Flash-based storage).

In a realistic world, where operating systems and system administration are human endeavours and thus inherently non-perfect, you might want to add some safeguards, including keeping data encrypted in RAM and instructing the OS not to write data in swap space (on Unix-like systems, this is done with mlock()). Still, this encrypt-in-RAM things is more a psychological ritual than a true defense; its main virtue is in making the developer feel better.

Don't bother with doing that in Java, anyway. The garbage collector will copy objects in RAM transparently (this is part of the most efficient GC algorithms and you cannot prevent it) so no level of encryption by your application will guarantee that no clear version of the keys exist in RAM at any time.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
10

Modern operating systems work with virtual memory management so that by default it is not possible for user-space / user-mode processes to directly access other processes memory.

But in Windows (don't know if this apply to Linux, too) there are interfaces that allow standard users to access the process memory of other processes running with the same credentials.

There are many programs that use this interface. A very simple example is HxD - a freeware hex editor that allows to view and even edit the process memory of other processes.

Additionally there are known attacks like Spectr or RowHammer that can make it possible to get access or corrupt memory of other processes without the help of the OS.

Robert
  • 1,373
  • 2
  • 12
  • 13
  • 5
    But encryption doesn't help here, since you can use the same API to read the key. These memory APIs are also restricted, so only sufficiently privileged processes can read the memory of another process, by default they need to run on the same user, or be an admin. – CodesInChaos Sep 18 '12 at 13:40
  • You are right, in that case it is only for obfuscation purposes. – Robert Sep 18 '12 at 14:06
  • 2
    In Linux you can do this by [reading `/proc/$pid/mem`](http://unix.stackexchange.com/questions/6301/how-do-i-read-from-proc-pid-mem-under-linux) (as the process you want to read, or root). – Brendan Long Sep 18 '12 at 15:58
  • 1
    @CodesInChaos, doesn't this only apply to keys stored in ram? If a generated key is used, for which only some sort of initialization vector exist in memory it would not be easily visible. But this still tend to be obfuscation only. I agree – Samuel Aug 20 '14 at 13:16
  • RowHammer allows flipping bits in rows adjacent to those that you are accessing. This can allow for privilege escalation, but I don't think it directly allows for reading other processes memory. [Spectre](https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)) on the other hand does allow leaking memory from other processes. – nobody Jun 08 '21 at 10:08
8

Memory can become visible to other processes by:

  1. being available once the original process using it has returned it to the OS. Memory isn't cleared and a successive process could perform a malloc() and retrieve info belonging to a previously running process (note chapter 8 of Linux Device Drivers - particularly the footnote on the first page)
  2. pages being swapped out to disk by the OS. These can then become available to a process watching the disk/storage.

Consequently unencrypted memory can become visible to other processes.

This is a very interesting link, and note this quote:

This volatility depends greatly on the computer in question, however - for when a computer isn't doing anything anonymous memory can persist for long periods of time. For instance in some computers passwords and other precalculated data were easily recovered days many after being typed or loaded into memory

Brian Agnew
  • 197
  • 2
  • 3
    Can you name a modern OS that has property 1? Windows NT does clear the memory before handing it out again. Property 2 requires admin privs, so you should not worry about other processes doing this, but about data remaining on the disk after the program terminates or the system restarts. – CodesInChaos Sep 18 '12 at 08:40
  • I don't know about Windows NT, but I wouldn't expect Linux to return you a cleared memory block from malloc() or sbrk() –  Sep 18 '12 at 08:41
  • 1
    I know attributes of Java objects are cleaned / initialized at instantiation time. But what after memory release / JVM termination. Will there be a cleanup? –  Sep 18 '12 at 08:53
  • 1
    @user573215 - I don't believe so. No. –  Sep 18 '12 at 09:27
  • 3
    `malloc` might reuse memory used *by the same process* earlier without clearing it. But an OS reusing uncleared memory across processes seems very dumb. – CodesInChaos Sep 18 '12 at 10:02
  • Downvoted why ? –  Sep 18 '12 at 11:11
  • @CodesInChaos - note the link I've given above –  Sep 18 '12 at 11:14
  • 3
    The link talks about kernel memory. Memory allocations of usermode processes are something different entirely. – CodesInChaos Sep 18 '12 at 11:17
  • @CodesInChaos - I think it's still relevant –  Sep 18 '12 at 11:24
  • @CodesInChaos: for the historical note, "very dumb" is also spelled "Windows 98". – Thomas Pornin Sep 18 '12 at 12:43
  • @ThomasPornin I think even Win9x returned zero initialized memory in `VirtualAlloc` (at least that's Win32.hlp indicates). But of course that doesn't really matter, since Win9x made no attempt of process isolation. – CodesInChaos Sep 18 '12 at 14:13
  • You should really clarify in point (1) that your link is talking about kernel programming, which is nothing like user space programming. The kernel always zeroes memory before giving it to a new process. Not to mention that if an attacker's code is executing in kernel-mode, then you have more serious problems than access to uninitialized memory. – Brendan Long Sep 18 '12 at 15:54
2

There are some issues that are specific to the Java world that you have to consider. It is a normal practice that one makes heap dumps of the JVM if a technical issue rises. I'm dealing with an app that even has a dedicated UI for that. This might be incredibly valuable e.g. for finding memory leaks. And sure - yeah - the sensitive information goes into the dump. So if someone breaks in the app (e.g. bypasses the login with an SQL Injection :) )... :X. Or if the administrative user is a curious person ... :X

I know that this should not happen in the "ideal world".

Also you may configure the JVM to make a dump on out of memory exceptions. Since Java 1.4 this might look like this:

-XX:-HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=<path to dump file>

An attacker may find an exploit that makes the app crash with out of memory and may find another exploit (e.g. file path traversal bug) to steal your dump!

The other thing that you should think about is that some sensitive data will have to make its way into your app somehow. So in certain moments you'll have it in memory. There is little or nothing you can do about it. But what you can do is to clean it faster. For example take a user password. If you store it in a String instance then you do not have much control on when it will be garbage collected. Thus usually nice API-s do process such data in character arrays (char[]) that can be zeroed after usage.

Lachezar Balev
  • 537
  • 1
  • 3
  • 10
  • Can you tell me the Java language specification part where it is said that writing to a char[] actually performs the writes in-place? – user1050755 Mar 19 '14 at 10:58
  • 1
    @user1050755: Writing to an element of a `char[]` causes every reference that had identified the array instance before the change to identify a the same changed instance. While nothing specifies that updates are preformed in-place, there is no other means by which array writes could generally be performed while upholding Java's guaranteed semantics and yielding reasonable performance. It should be noted, however, that a concurrent garbage collector might benefit from using double-indirected references [such that all references to an object identify a single pointer to that object]... – supercat Jan 13 '16 at 18:35
  • ...allowing objects to be relocated without having to track down all extant references, and that with the right kind of hardware support things like copy-on-write might be advantageous in some cases (sometimes code which makes copies of arrays never expects those copies to be altered, but merely wants to prevent the copies from being influenced by changes to the original; if the original is never modified, a double-indirect system could have both arrays be separate handles to the same object in memory, with a requirement that any change to *either* handle would require copying it first). – supercat Jan 13 '16 at 18:40
1

Google has an exploit called RowHammer which allows a user to read the contents of RAM that is adjacent to the data being written to. Encrypting the RAM would make this exploit much more difficult.

“Rowhammer” is a problem with some recent DRAM devices in which repeatedly accessing a row of memory can cause bit flips in adjacent rows. We tested a selection of laptops and found that a subset of them exhibited the problem. We built two working privilege escalation exploits that use this effect. One exploit uses rowhammer-induced bit flips to gain kernel privileges on x86-64 Linux when run as an unprivileged userland process. When run on a machine vulnerable to the rowhammer problem, the process was able to induce bit flips in page table entries (PTEs). It was able to use this to gain write access to its own page table, and hence gain read-write access to all of physical memory.

We don’t know for sure how many machines are vulnerable to this attack, or how many existing vulnerable machines are fixable. Our exploit uses the x86 CLFLUSH instruction to generate many accesses to the underlying DRAM, but other techniques might work on non-x86 systems too.

We expect our PTE-based exploit could be made to work on other operating systems; it is not inherently Linux-specific. Causing bit flips in PTEs is just one avenue of exploitation; other avenues for exploiting bit flips can be practical too. Our other exploit demonstrates this by escaping from the Native Client sandbox.

makerofthings7
  • 50,090
  • 54
  • 250
  • 536
  • 2
    It doesn't allow the user to read RAM adjacent to the data being written, but rather allows one to increase the probability of data corruption on RAM adjacent to the data being written. – supercat Sep 09 '15 at 21:35
0

KeePass specifically has a chrome extension, so other Chrome extensions could read the same memory that KeePass is using. The OS memory protections are not going to help in that case. Hence the encryption.

Another family of reasons for memory encryption, in general, is because there are hardware attacks where someone can access memory:

  • Cold boot attacks allow an attacker to reboot the machine while keeping the memory in tact. They then boot to an alternative OS with no memory protection and perform a scan.
  • Freezing the RAM chips causes them to preserve their contents even after power loss. So a hacker with physical access could remove the RAM and place it in a liquid nitrogen storage container, and move the RAM to another location and reinstall it, and scan it.
  • Various hardware buses such as PCI and Firewire support DMA which allows the device to access memory directly. So a hacker could insert a device into the machine that reads RAM.

Side note: Intel and AMD both offer RAM encryption as a feature now.

Moby Disk
  • 117
  • 6
0

The reason why it sounds like a good idea is that you will want to protect the data from being stolen while resident in memory. This is under the assumption that the data in the actual database is encrypted (as all PII should be) but sits un-encrypted in memory as it is processed. This would be quite difficult to do for a variety of reasons outlined by other commentators and would introduce a great deal of complexity in terms of how the applications will work with the encrypted data in memory.

What is a better and more feasible solution is to ensure proper access control to the Database / system and also ensure that the DBMS runs under a "normal" user account and not an elevated account such as SYSTEM etc. There is also additional detective controls you can put in place such as a DBMS monitoring tool that you can configure to look at large selects on sensitive tables etc and report back on anything that is out of the ordinary. This way you can see if there is some select or process trying to get large amounts of data out.

Michael
  • 19
  • 1