Main Content

Uncertain memory cleaning

The code clears information that might be sensitive from memory but compiler optimization might leave the information untouched

Since R2022a

Description

This defect occurs when you clean memory by writing 0 into it but the memory is not read after the cleaning operation. Because the memory is not read after the cleaning, a compiler might skip the cleaning operation when optimizing the code. For instance, consider this code:

void foo(){
	void* buffer = getSensitiveData();
	//...
	memset(buffer, 0, sizeof(buffer));
}
Here, buffer might contain sensitive data. The call to memset() is intended to scrub the data. Because buffer is not read after the scrubbing, the compiler optimization process might ignore the memset() command. The data in buffer might remain uncleaned. Polyspace® flags such uncertain memory cleaning. Polyspace does not raise this defect if either of these conditions are true:

  • The return value of the memory cleaning function is assigned to a variable.

  • The memory cleaning function scrubs a global object.

Risk

When a variable is written with no further read, compilers might consider it as a deadstore. To optimize the code, the compiler might remove any assignments to deadstore variables.

If such code optimization removes code that scrubs sensitive information from memory, then sensitive information might remain uncleaned in your system. An attacker can then access the sensitive information and use it to further erode the protection mechanisms in your code.

Fix

When scrubbing memory, use code that the compiler cannot remove. For instance, instead of memset, use secure functions, such as memset_s or fill_n. If you use an older version of C or C++ where these functions are unavailable, consider updating your code to a more recent version. Alternatively, you might implement your own secure memory-scrubbing function. When using your own implementation, review the compiled code to make sure that the memory-cleaning operations are untouched by the compiler.

Examples

expand all

#include <string.h>

extern int getSensitiveData(char*, size_t);
extern int writeDB(char*, char*);
char Gbuffer[64];
void Job(char *key) {
    char buffer[64];
    if (getSensitiveData(buffer, sizeof(buffer))) {
        if (writeDB(key, buffer)) {
            // Record data
        }
    }
    (void) memset(buffer, 0, sizeof(buffer)); // Defect
}

void manageGBuffer(char *key) {
    //...
    memset(Gbuffer, 0, sizeof(Gbuffer)); // No Defect
}

In this example, the command memset() is used in Job() to clean the memory in buffer. Because buffer is not read after the cleaning, the compiler might remove this code when optimizing the code. Polyspace flags the uncertain cleaning. In the function manage(), memset() is used to clean the global array Gbuffer. Polyspace does not flag this cleaning operation.

Correction — Use Secure Functions to Clean Sensitive Memory

To fix this defect, use secure functions, such as memset_s(), to clean uncertain memory.

#include <string.h>

extern int getSensitiveData(char*, size_t);
extern int writeDB(char*, char*);

void Job(char *key) {
    char buffer[64];
    if (getSensitiveData(buffer, sizeof(buffer))) {
        if (writeDB(key, buffer)) {
            // Record data
        }
    }
    memset_s(buffer, 0, sizeof(buffer)); // No Defect
}

Result Information

Group: Security
Language: C | C++
Default: Off
Command-Line Syntax: UNCERTAIN_MEMORY_CLEANING
Impact: Medium

Version History

Introduced in R2022a