Developers should take steps to prevent sensitive information such as passwords, cryptographic keys, and other secrets from being inadvertently leaked. This includes Preventive measures include attempting to prevent keep such data from being written to disk.
Two common mechanisms by which data is inadvertently written to disk are swapping and core dumps.
Many general-purpose operating systems implement a virtual memory–management -memory-management technique called paging (also called swapping) to transfer pages between main memory and an auxiliary store, such as a disk drive. This feature is typically implemented as a task running in the kernel of the operating system, and its operation is invisible to the running program.
A core dump is the recorded state of process memory written to disk for later examination by a debugger. Core dumps are typically generated when a program has terminated abnormally, either through an error resulting in a crash or by receiving a signal that causes such a termination.
The POSIX standard system call for controlling resource limits, setrlimit()
, can be used to disable the creation of core dumps. This , which prevents an attacker with the ability to halt the program from gaining access to sensitive data that might be contained in the dump.
...
In this noncompliant code example, sensitive information is supposedly stored in the dynamically allocated buffer, secret
, which is processed and eventually deallocated cleared by a call to freememset_s()
. The memory page containing secret
can be swapped out to disk. If the program crashes before the call to freememset_s()
completes, the information stored in secret
may be stored in the core dump.
Code Block | ||||
---|---|---|---|---|
| ||||
char *secret;
secret = (char *)malloc(size+1);
if (!secret) {
/* Handle error */
}
/* Perform operations using secret... */
memset_s(secret, '\0', size+1);
free(secret);
secret = NULL;
|
...
To prevent the information from being written to a core dump, the size of core dumps that the program will generate should be set to 0 using setrlimit()
.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <sys/resource.h>
/* ... */
struct rlimit limit;
limit.rlim_cur = 0;
limit.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &limit) != 0) {
/* Handle error */
}
char *secret;
secret = (char *)malloc(size+1);
if (!secret) {
/* Handle error */
}
/* Perform operations using secret... */
memset_s(secret, '\0', size+1);
free(secret);
secret = NULL;
|
...
Processes with elevated privileges can disable paging by locking memory in place using the POSIX mlock()
function [Open Group 2004IEEE Std 1003.1:2013]. This Disabling paging ensures that memory is never copied to the hard drive, where it may be retained indefinitely in nonvolatile storage.
This compliant solution not only disables the creation of core files but also ensures that the buffer is not swapped to hard disk.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <sys/resource.h> /* ... */ struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &limit) != 0) { /* Handle error */ } long pagesize = sysconf(_SC_PAGESIZE); if (pagesize == -1) { /* Handle error */ } char *secret_buf; char *secret; secret_buf = (char *)malloc(size+1+pagesize); if (!secret_buf) { /* Handle error */ } /* mlock() may require that the address be a multiple of PAGESIZE */ secret = (char *)((((intptr_t)secret_buf + pagesize - 1) / pagesize) * pagesize); if (mlock(secret, size+1) != 0) { /* Handle error */ } /* Perform operations using secret... */ if (munlock(secret, size+1) != 0) { /* Handle error */ } secret = NULL; memset_s(secret_buf, '\0', size+1+pagesize); free(secret_buf); secret_buf = NULL; |
Compliant Solution (
...
Windows)
Windows processes running with elevated privileges can disable paging by locking memory in place using VirtualLock()
(Windows) [MSDN]:
Code Block | ||||
---|---|---|---|---|
| ||||
char *secret; secret = (char *)mallocVirtualAlloc(0, size + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!secret) { /* Handle error */ } if (!VirtualLock(secret, size+1) != 0) { /* Handle error */ } /* Perform operations using secret... */ SecureZeroMemory(secret, size + 1); free(secretVirtualUnlock(secret, size + 1); VirtualFree(secret, 0, MEM_RELEASE); secret = NULL; |
Note that locking pages of memory on Windows may fail because the operating system allows the process to lock only a small number of pages. If an application requires additional locked pages, the SetProcessWorkingSetSize()
API can be used to increase the application's minimum working set size. Locking pages has severe performance consequences and should be used sparingly.
Risk Assessment
Writing sensitive data to disk preserves it for future retrieval by an attacker, who may even be able to bypass the access restrictions of the operating system by using a disk maintenance program.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MEM06-C |
Medium |
Unlikely |
High | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Polyspace Bug Finder |
| Checks for sensitive data printed out (rec. partially covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ |
Coding Standard | VOID MEM06-CPP. Ensure that sensitive data is not written out to disk |
ISO/IEC TR |
24772: |
2013 | Memory |
Locking [XZX] | |
MITRE CWE | CWE-591, Sensitive data storage in improperly locked memory CWE-528, Information leak through core dump files |
Bibliography
[ |
IEEE Std 1003.1:2013] |
mlock()
XSH, System Interface, mlock XSH, System Interface, setrlimit |
[Wheeler 2003] | Section 7.14 Section 11.4 |
...
...