...
Some compiler optimization modes may remove code sections if the optimizer determines that doing so will not alter the behavior of the program. In this example, this can cause the call to memset() (which the programmer had hoped would clear sensitive memory) to be removed because after the store to pwd, pwd is never accessed again. Check compiler documentation for information about this compiler specific behavior and which optimization levels can cause this behavior to occur.
For all of the below listed compliant code examples, it is strongly recommended that the programmer inspect the generated assembly code to ensure that memory is actually zeroed and none of the function calls were optimized out.
...
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if (GetPasswordretrievePassword(pwd, sizeof(pwd))) {
/*checking of password, secure operations, etc */
}
memset(pwd, 0, sizeof(pwd));
*(volatile char*)pwd= *(volatile char*)pwd;
}
|
...
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if (GetPasswordretrievePassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
ZeroMemory(pwd, sizeof(pwd));
}
|
...
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if(GetPasswordretrievePassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
SecureZeroMemory(pwd, sizeof(pwd));
}
|
...
| Code Block | ||
|---|---|---|
| ||
void getPassword() {
char pwd[64];
if(GetPasswordretrievePassword(pwd, sizeof(pwd))) {
/* checking of password, secure operations, etc */
}
#pragma optimize("", off)
memset(pwd, 0, sizeof(pwd));
#pragma optimize("", on)
}
|
Compliant Solution
...
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 | ||
|---|---|---|
| ||
// memset_s.c void *memset_s(void \*v, int c, size_t n) { volatile char *p = v; while(n--) *p++ = c; return v; } // getPassword.c extern void *memset_s(void *v, int c, size_t n); void getPassword() { char pwd\[64\]; if(GetPasswordretrievePassword(pwd, sizeof(pwd))) { /*checking of password, secure operations, etc \*/ } pwd = memset_s(pwd, 0, sizeof(pwd)); } |
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
DRAFT | 2 (Medium) | 2 (Probable) | 2 (Medium) | P8 | L2 |
References
| Wiki Markup |
|---|
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.7.3, "Type qualifiers" \[[US-CERT|https://buildsecurityin.us-cert.gov/daisy/bsi-rules/home/g1/771.html]\], "MEMSET" \[[MSDN|http://msdn2.microsoft.com/en-us/library/aa366877.aspx]\], "SecureZeroMemory" \[[MSDN|http://msdn2.microsoft.com/en-us/library/chh3fb0k(VS.80).aspx]\], "Optimize (C/C++)" \[[Wheeler|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html]\], "Secure Programming for Linux and Unix HOWTO". Section 11.4. |