If a buffer contains sensitive data, such as passwords or access tokens, it is good practice to overwrite the buffer before releasing the memory.
This ensures that the sensitive data is not available when that memory is reallocated. The memset
function is commonly used for this
purpose.
Why is this an issue?
The C language specification allows the compiler to remove unnecessary code during the optimization phase. For example, when a memory buffer is
about to be destroyed, any writes to that buffer may be seen as unnecessary to the operation of the program. The compiler may choose to remove these
write operations.
When the memset
function is used to clear sensitive data from memory and that memory is destroyed immediately afterward, the compiler
may see the memset
call as unnecessary and remove it. The sensitive data will, therefore, remain in memory.
This rule raises an issue when a call to memset
is followed by the destruction of the buffer.
How to fix it
The function memset_s
behaves similarly to memset
. The
main difference is that it cannot be optimized away and the memory will be overwritten in all cases. You should use memset_s
to clear
security-sensitive data.
The memset_s
function is defined in annex K of C11 and is optional for C11 compilers. It will only be available if the macro
__STDC_LIB_EXT1__
is defined, and it must be enabled by defining the macro __STDC_WANT_LIB_EXT1__
before including
<string.h>
.
Other platform-specific functions can perform the same operation, such as SecureZeroMemory (Windows)
or explicit_bzero (FreeBSD).
Code examples
Noncompliant code example
#include <string>
void f(char *password, size_t bufferSize) {
char localToken[256];
init(localToken, password);
memset(password, 0, strlen(password)); // Noncompliant
memset(localToken, 0, strlen(localToken)); // Noncompliant
free(password);
}
The memset
calls may be optimized away because password
is about to be freed and localToken
is about to go
out of scope.
Compliant solution
#define __STDC_WANT_LIB_EXT1__
#include <string>
void f(char *password, size_t bufferSize) {
char localToken[256];
init(localToken, password);
memset_s(password, bufferSize, 0, strlen(password));
memset_s(localToken, sizeof(localToken), 0, strlen(localToken));
free(password);
}
Resources
Documentation
Standards