Main Content

CWE Rule 14

Compiler Removal of Code to Clear Buffers

Since R2023a

Description

Rule Description

Sensitive memory is cleared according to the source code, but compiler optimizations leave the memory untouched when it is not read from again, aka "dead store removal."

Polyspace Implementation

The rule checker checks for Uncertain memory cleaning.

Examples

expand all

Issue

This issue 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.

Example — Avoid Uncertainty in Cleaning Sensitive Memory
#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 //Noncompliant
}

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
}

Check Information

Category: Others

Version History

Introduced in R2023a