Question

I want to create an allocator which provides memory with the following attributes:

  • cannot be paged to disk.
  • is incredibly hard to access through an attached debugger

The idea is that this will contain sensitive information (like licence information) which should be inaccessible to the user. I have done the usual research online and asked a few other people about this, but I cannot find a good place start on this problem.

Updates

Josh mentions using VirtualAlloc to set protection on the memory space. I have created a custom allocator ( shown below ) I have found the using the VirtualLock function it limits the amount of memory I can allocate. This seems to be by design though. Since I am using it for small objects this is not a problem.

//
template<class _Ty>
class LockedVirtualMemAllocator : public std::allocator<_Ty>
{
public:
    template<class _Other>
    LockedVirtualMemAllocator<_Ty>& operator=(const LockedVirtualMemAllocator<_Other>&)
    {   // assign from a related LockedVirtualMemAllocator (do nothing)
        return (*this);
    }

    template<class Other>
    struct rebind {
        typedef LockedVirtualMemAllocator<Other> other;
    };

    pointer allocate( size_type _n )
    {
        SIZE_T  allocLen = (_n * sizeof(_Ty));
        DWORD   allocType = MEM_COMMIT;
        DWORD   allocProtect = PAGE_READWRITE;
        LPVOID pMem = ::VirtualAlloc( NULL, allocLen, allocType, allocProtect );
        if ( pMem != NULL ) {
            ::VirtualLock( pMem, allocLen );
        }
        return reinterpret_cast<pointer>( pMem );
    }
    pointer allocate( size_type _n, const void* )
    {
        return allocate( _n );
    }

    void deallocate(void* _pPtr, size_type _n )
    {
        if ( _pPtr != NULL ) {
            SIZE_T  allocLen = (_n * sizeof(_Ty));
            ::SecureZeroMemory( _pPtr, allocLen );
            ::VirtualUnlock( _pPtr, allocLen );
            ::VirtualFree( _pPtr, 0, MEM_RELEASE );
        }
    }
};

and is used

 //a memory safe std::string
 typedef std::basic_string<char, std::char_traits<char>, 
                           LockedVirtualMemAllocato<char> > modulestring_t;

Ted Percival mentions mlock, but I have no implementation of that yet.

I found Practical Cryptography by Neil Furguson and Bruce Schneier quite helpful as well.

Was it helpful?

Solution

You can't really protect against memory access. You can probably prevent paging if you are running as an admin or as the system, but you cannot prevent the admin or system from reading your memory. Even if you could somehow completely block other processes from reading your memory (which you can't), another process could still actually inject a new thread into your process and read the memory that way.

Even if you could somehow completely lock down your process and guarantee that the OS would never allow anyone else to access your process, you still don't have full protection. The entire OS could be running in a virtual machine, which could be paused and inspected at any time.

You cannot protect memory contents from the owner of the system. Hollywood and the music industry have been aching for this for years. If it were possible, they'd already be doing it.

OTHER TIPS

On Unix systems you can use mlock(2) to lock memory pages into RAM, preventing them being paged.

mlock() and mlockall() respectively lock part or all of the calling process’s virtual address space into RAM, preventing that memory from being paged to the swap area.

There is a limit to how much memory each process can lock, it can be shown with ulimit -l and is measured in kilobytes. On my system, the default limit is 32 kiB per process.

If you're developing for Windows, there are ways you can restrict access to memory, but absolutely blocking out others is not doable. If you're hoping to keep a secret secret, read Writing Secure Code - which addresses this problem at some length, but be aware that you have no way of knowing if your code is running on a real machine or a virtual machine. There's a bunch of Win32 API stuff to deal with crypto that handles this kind of thing, including safe storage of secrets - the book talks about that. You can look at the online Microsoft CyproAPI for details; the OS designers recognise this very problem and the need to keep the cleartext secure (again, read Writing Secure Code).

The Win32 API function VirtualAlloc is the OS level memory allocator. It allows you to set access protection; what you could do is set access to PAGE_GUARD or PAGE_NOACCESS, and flip the access to something friendlier while your program reads, and reset it afterward, but that's merely a speed hump if someone is trying really hard to peek at your secret.

In summary, look at the crypto APIs on your platform, they'll address the problem better than something you hack up yourself.

Let's take this a bit at a time:

I want to create an allocator which provides memory with the following attributes:

That's fair enough.

* cannot be paged to disk.

That's going to be hard. As far as I am aware, you cannot disable Virtual Paging as it is handled by the OS. If there is a way, then you'll be spelunking in the bowels of the OS.

* is incredibly hard to access through an attached debugger

You could run it through PGP and store it encrypted in memory and unencrypt it as needed. Massive performance hit.

The idea is that this will contain sensitive information (like licence information) which should be inaccessible to the user. I have done the usual research online and asked a few other people about this, but I cannot find a good place start on this problem.

Keep all sensitive information off the machine. Seriously. Don't store sensitive information in memory. Write a custom delete routine that will automatically remove all data from any allocations you perform. Never allow general access to a machine with sensitive material on it. If you perform db access, make sure all access is sanitized before firing. Only people with specific log-ins are allowed to access. No general group access.

On a side note, what other methods are there of accessing the memory of a process other than attaching a debugger?

Taking a dump of the memory.

install Libsodium, use allocation mechanisms by #including <sodium.h>

Guarded heap allocations

Slower than malloc() and friends, they require 3 or 4 extra pages of virtual memory.

void *sodium_malloc(size_t size);

Allocate memory to store sensitive data using sodium_malloc() and sodium_allocarray(). You'll need to first call sodium_init() before using these heap guards.

void *sodium_allocarray(size_t count, size_t size);

The sodium_allocarray() function returns a pointer from which count objects that are size bytes of memory each can be accessed. It provides the same guarantees as sodium_malloc() but also protects against arithmetic overflows when count * size exceeds SIZE_MAX.

These functions add guard pages around the protected data to make it less likely to be accessible in a heartbleed-like scenario.

In addition, the protection for memory regions allocated that way can be changed using the locking memory operations: sodium_mprotect_noaccess(), sodium_mprotect_readonly() and sodium_mprotect_readwrite().

After sodium_malloc you can use sodium_free() to unlock and deallocate memory. At this point in your implementation consider zeroing the memory after use.

zero the memory after use

void sodium_memzero(void * const pnt, const size_t len);

After use, sensitive data should be overwritten, but memset() and hand-written code can be silently stripped out by an optimizing compiler or by the linker.

The sodium_memzero() function tries to effectively zero len bytes starting at pnt, even if optimizations are being applied to the code.

locking the memory allocation

int sodium_mlock(void * const addr, const size_t len);

The sodium_mlock() function locks at least len bytes of memory starting at addr. This can help avoid swapping sensitive data to disk.

int sodium_mprotect_noaccess(void *ptr);

The sodium_mprotect_noaccess() function makes a region allocated using sodium_malloc() or sodium_allocarray() inaccessible. It cannot be read or written, but the data are preserved. This function can be used to make confidential data inaccessible except when actually needed for a specific operation.

int sodium_mprotect_readonly(void *ptr);

The sodium_mprotect_readonly() function marks a region allocated using sodium_malloc() or sodium_allocarray() as read-only. Attempting to modify the data will cause the process to terminate.

int sodium_mprotect_readwrite(void *ptr);

The sodium_mprotect_readwrite() function marks a region allocated using sodium_malloc() or sodium_allocarray() as readable and writable, after having been protected using sodium_mprotect_readonly() or sodium_mprotect_noaccess().

What you are asking for is handled at the OS level. Once the data is in your program, it is liable to be paged out.

For accessing the memory, a motivated individual can attach a hardware debugger.

@graham

You could run it through PGP and store it encrypted in memory and unencrypt it as needed. Massive performance hit.

Then you'd have to hold the key in memory. That would make it a little harder, but definitely not impossible. Anyone motivated will still manage to get the data from memory.

Your best bet is to implement something similar to .NET's SecureString class, and be very careful to zero out any plaintext copies of your data as soon as you are done (don't forget to cleanup even when exceptions are thrown). A good way to do this with std::string and such is to use a custom allocator.

On Windows, if you use CryptProtectMemory (or RtlEncryptMemory for older systems), the encryption password is stored in non-pageable (kernel?) memory. In my testing, these functions are pretty darn fast, esp. taking into account the protection they are giving you.

On other systems, I like to use Blowfish since it's a good mix between speed and strength. In the latter case, you will have to randomly generate your own password (16+ bytes of entropy for Blowfish) at program startup. Unfortunately, there's not a whole lot you can do to protect that password without OS support, although you might use general obfuscation techniques to embed a hard-coded salt value into your executable that you can combine with the password (every little bit helps).

Overall, this strategy is only one part of a broader defense-in-depth approach. Also keep in mind that simple bugs such as buffer overflows and not sanitizing program input remain by far the most common attack vectors.

You cannot protect memory contents from the owner of the system. Hollywood and the music industry have been aching for this for years. If it were possible, they'd already be doing it.

Have you had a look at Vista (and above) Protected Processes (direct .doc download). I believe the operating system-enforced protection is courtesy of the entertainment industry.

@Derek: Oh, but with trusted computing, you can use memory curtaining! :-P</devils-advocate>

@roo

I was really hoping that is was possible, and that I just hadn't found it yet. Your example just made me realise that that is exactly what we are trying to do - only allow access to files in the context of our program and so preserve the IP.

I guess I have to accept that there is no truly secure way to store someone’s files on another computer, especially if at some point access is allowed to that file by the owner.

That's definitely the problem. You can store something securely so long as you never grant access, but as soon as you grant access, your control is gone. You can make it a little bit more difficult, but that's all.

@Chris

Oh, but with trusted computing, you can use memory curtaining! :-P

But then you have to actually be willing to pay for a computer someone else owns. :p

@Derek Park

He only said harder, not impossible. PGP would make it harder, not impossible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top