...
Non-Compliant Code Example (memset())
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if (GetPassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
memset(pwd, 0, sizeof(pwd));
}
|
...
This non-compliant code example accesses the buffer again after the call to memset(). This prevents some compilers from optimizing out the call to memset() but does not work for all implementaitons. Check compiler documentation to guarantee this behavior for a specific platform.
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if (GetPassword(pwd, sizeof(pwd))) {
/*checking of password, secure operations, etc */
}
memset(pwd, 0, sizeof(pwd));
*(volatile char*)pwd= *(volatile char*)pwd;
}
|
...
This compliant solution uses a ZeroMemory() function provided by many versions of the Microsoft Visual Studio compiler.
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if (GetPassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
ZeroMemory(pwd, sizeof(pwd));
}
|
...
This compliant solution uses a SecureZeroMemory() function provided by many versions of the Microsoft Visual Studio compiler. The documentation for the SecureZeroMemory() function guarantees that the compiler will not optimize out this call when zeroing memory.
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if(GetPassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
SecureZeroMemory(pwd, sizeof(pwd));
}
|
...
The #pragma directives here instructs the compiler to avoid optimizing the enclosed code. This #pragma directive is supported on some versions of Microsoft Visual Studio, and may be supported on other compilers. Check compiler documentation to ensure its availability and its optimization guarantees.
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if(GetPassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
#pragma optimize("", off)
memset(pwd, 0, sizeof(pwd));
#pragma optimize("", on)
}
|
...
This compliant solution guarantees, via the volatile type qualifier, that memory is actually overwritten and the compiler will not optimize out the call to the memset_s() function. Unfortunately, this compliant solution may not be as efficient as possible due to the nature of the volatile type qualifier preventing the compiler from optimizing the code at all. Typically, some compilers are smart enough to replace calls to memset() with equivalent assembly instructions which are much more efficient then the memset() implementation. Implementing a memset_s() function as below may prevent the compiler from using the optimal assembly instructions and may result in less efficient code. Check compiler documentation and the assembly output from the compiler.
| Code Block | ||
|---|---|---|
| ||
void *memset_s(void \*v, int c, size_t n) {
volatile char *p = v;
while(n--)
*p++ = c;
return v;
}
void getPassword() {
char pwd\[64\];
if(GetPassword(pwd, sizeof(pwd))) {
/*checking of password, secure operations, etc \*/
}
pwd = memset_s(pwd, 0, sizeof(pwd));
}
|
Risk Assessment
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
DRAFT | 2 (Medium) | 2 (Probable) | 2 (Medium) | P8 | L2 |
...