Developers should take steps to prevent sensitive information such as passwords, cryptographic keys, and other secrets from being inadvertently written out to disk or other auxiliary storage.
Two common mechanisms by which data can inadvertently be written to disk are swapping and core dumps.
Paging/Swapping
Many general-purpose operating systems implement a virtual memory management technique called paging (also referred to as 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 it's operation is invisible to the running program.
Core dumps
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 prevents an attacker with the ability to halt the program from gaining access to sensitive data that may be contained in the dump.
Non-Compliant Code Example
In this example, sensitive information generated by create_secret()
is stored in the dynamically allocated buffer, secret
, which is processed and eventually deallocated by a call to free()
. The memory page containing secret
could be swapped out to disk. If the program crashes before the call to free()
the information stored in secret
may be stored in the core dump.
/* ... */ char *secret; secret = malloc(size+1); if (!secret) { /* Handle Error */ } secret = create_secret(); /* Perform operations using secret... */ free(secret); /* ... */
Compliant Solution
To prevent the information being written to a core dump, the size of core dumps that the program will generate should be set to 0. This can accomplished by using setrlimit()
.
#include <resource.h> /* ... */ struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; if(!setrlimit(RLIMIT_CORE, &limit)) { /* Handle Error */ } /* ... */ char *secret; size_t size = strlen(input); if (size == SIZE_MAX) { /* Handle Error */ } secret = malloc(size+1); if (!secret) { /* Handle Error */ } strcpy(secret, input); /* Perform operations using secret... */ free(secret); /* ... */
Exceptions
Risk Assessment
Program stacks are frequently used for convenient temporary storage, because allocated memory is automatically freed when the function returns. Generally, the operating system will grow the stack as needed. However, growing the stack can fail due to a lack of memory or collision with other allocated areas of the address space (depending on the architecture). When the stack is exhausted, the operating system may terminate the program abnormally. This behavior can be exploited by an attacker to cause a denial-of-service attack in situations where the attacker can control or influence the amount of stack memory allocated.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
MEM06-A |
1 (low) |
1 (unlikely) |
2 (medium) |
P2 |
L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
MEM05-A. Avoid large stack allocations 08. Memory Management (MEM) MEM07-A. Ensure that size arguments to calloc() do not result in an integer overflow