How to prevent other applications from scraping my program's memory?


#1

Hello,
Developing an application that has a public and private key and it is critical that other programs, such as viruses, can’t access that private key. I can use encryption when storing to users drive but at some point, I have to store it in RAM to use it. I hear that is vulnerable to RAM scraping, is it possible to protect this memory and prevent other programs from accessing it?

I believe it should be? Just not sure if possible with Rust, or if it requires a C library rust links into.

Thank you!!


#2

As I understand, if RAM scraper is running on your system, you are already lost, and there is no defense. This is not specific to Rust and it applies equally to programs written in C.


#3

There are some defences but there really hard to get right and not very effective.


#4

You should probably look at Hardware Security Modules if the security of the key material is so vital. Software alone is unlikely to cut it.


#5

So something like this will probably work for you:

use std::boxed::Box;
use std::mem;

struct Protected {
    val : u64,
    data : [u32;256]
}

fn main() {
    let safe = Box::new(Protected { val : 57575757, data: [ 64646464; 256] });
    
    let ptr = Box::into_raw(safe); 
    let raw : *mut u8 = unsafe { mem::transmute(ptr) };
 
    for i in 0..mem::size_of::<Protected>() as isize
    {
        unsafe {
            *raw.offset(i) = 0;
        }
    }
}

Standard disclaimer applies, when dealing with security it’s usually better to use an existing library that has been reviewed for security and safety.


#6

What is this supposed to do? Just zero the memory after it’s been dropped? I doubt that’s enough. It won’t zero any owned heap allocations like Vec or String, one of which is probably storing OP’s key.

Once the machine has been breached the only safe thing to assume is that the attacker has access to everything on it.

And anyways, you’re doing it the hard way. Just convert it to a raw pointer and call std::ptr::write_bytes(ptr, 0, 1) to memset() the memory area with zeroes.


#7

I believe you’d need to use the volatile intrinsics to ensure that the compiler doesn’t eliminate the memset.


#8

I think memory protection is usually implemented by an operating system to isolate processes from each other, not by individual processes themselves. If your program is trying to use a key, and something already has the privileges in the operating system to be able to access other processes’ memory in the first place, I don’t think there’s anything you can do about it at that point.

If a process needs to work with the data of a key, it’s either never in the computer to begin with (in an HSM) or it’s going to have to be somewhere in memory, right? Any data being worked with, no matter what media it might originally have been stored in, will be brought into memory by the OS in order to become available to the process at all. Right?


#9

I just wanted to give the OP some code to do what he asked, everyone else seemed to be more interested in telling him that it’s a pointless requirement.

I’ve often had to implement pointless requirements for customers, and when googling, finding articles about why what I need to do is pointless isn’t helping me do it.

Thank you for providing a faster method.


#10

After some other poking around I believe riddochc is correct and that the operating system should automatically handle this. Finding conflicting info on whether or not malware can get around this whIle the application is running… though I’m sure it could always grab the encrypted file and keystrokes. So basically malware will always finds a way.

Thank you pixel and DroidLogic for providing solutions to at least wipe the memory one done with it. Which maybe is enough if the memory is later reallocated, definitely seems like a good idea.


#11

There are a few useful things you can do to help against certain attacks:

Heartbleed-style memory disclosure attacks are often prevented by Rust’s regular safety guarantees, but an additional countermeasure against such an exploit is to use libc::mprotect to mark a page of memory as unreadable, and only mark it readable in your accessor method. You may also want guard pages on either side so a blind memory scan would segfault on those pages, even when the page is readable during a crypto operation. An attacker with full execution can get around that, but it helps against some less-powerful attacks. I wouldn’t be as worried about them in Rust, since memory safety helps you here a lot, but it could still be worthwhile.

A drop impl that’s guaranteed to zero your data is also useful, and is what pixel seems to have been alluding to before. This hopefully prevents reading data after it’s no longer needed. One could imagine an application that only needs a private key to initiate a session, but no later. An exploit in the session would only lead to the session key being in memory, so other later uses of the private key may not be entirely toast.

Of course, all of this is skating on a knife edge and trying to mitigate damage in the event everything has already gone horribly wrong. Using an HSM (or maybe a privileged, out-of-process software simulation) provides much better guarantees, at the disadvantage of having requirements for special hardware, which may have all sorts of problems of its own. I also don’t believe there’s a good way to use an HSM from inside Rust at the moment either. While it’s a sad and bad API, PKCS#11 is the normal thing to use.