Skip to content

Commit c44fbaa

Browse files
committed
C++: Promote memset query out of experimental.
1 parent 6213c20 commit c44fbaa

File tree

7 files changed

+98
-193
lines changed

7 files changed

+98
-193
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
char * password = malloc(PASSWORD_SIZE);
2+
// ... read and check password
3+
memset(password, 0, PASSWORD_SIZE);
4+
free(password);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
char * password = malloc(PASSWORD_SIZE);
2+
// ... read and check password
3+
memset_s(password, PASSWORD_SIZE, 0, PASSWORD_SIZE);
4+
free(password);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Calling <code>memset</code> or <code>bzero</code> on a buffer to clear its contents may get optimized
7+
away by the compiler if the buffer is not subsequently used. This is not desirable behavior if the buffer
8+
contains sensitive data that could somehow be retrieved by an attacker.</p>
9+
10+
</overview>
11+
<recommendation>
12+
13+
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
14+
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
15+
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
16+
also prevents the optimization. Finally, the public-domain <code>secure_memzero</code> function (see
17+
below) can be used. This function, however, is not guaranteed to work on all platforms and compilers.</p>
18+
19+
</recommendation>
20+
<example>
21+
<p>The following program fragment uses <code>memset</code> to erase sensitive information after it is no
22+
longer needed:</p>
23+
<sample src="MemsetMayBeDeleted-bad.c" />
24+
<p>Because of dead store elimination, the call to <code>memset</code> may be removed by the compiler
25+
(since the buffer is not subsequently used), resulting in potentially sensitive data remaining in memory.
26+
</p>
27+
28+
<p>The best solution to this problem is to use the <code>memset_s</code> function instead of
29+
<code>memset</code>:</p>
30+
<sample src="MemsetMayBeDeleted-good.c" />
31+
32+
</example>
33+
<references>
34+
35+
<li>
36+
CERT C Coding Standard:
37+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations">MSC06-C. Beware of compiler optimizations</a>.
38+
</li>
39+
40+
</references>
41+
</qhelp>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @name Call to `memset` may be deleted
3+
* @description Using <code>memset</code> the function to clear private data in a variable that has no subsequent use
4+
* is potentially dangerous because the compiler can remove the call.
5+
* @kind problem
6+
* @id cpp/memset-may-be-deleted
7+
* @problem.severity warning
8+
* @precision high
9+
* @tags security
10+
* external/cwe/cwe-14
11+
*/
12+
13+
import cpp
14+
import semmle.code.cpp.dataflow.EscapesTree
15+
import semmle.code.cpp.commons.Exclusions
16+
17+
class MemsetFunction extends Function {
18+
MemsetFunction() {
19+
this.hasGlobalOrStdOrBslName("memset")
20+
or
21+
this.hasGlobalOrStdName("wmemset")
22+
or
23+
this.hasGlobalName(["bzero", "__builtin_memset"])
24+
}
25+
}
26+
27+
from FunctionCall call, LocalVariable v, MemsetFunction memset
28+
where
29+
call.getTarget() = memset and
30+
not isFromMacroDefinition(call) and
31+
// `v` only escapes as the argument to `memset`.
32+
forall(Expr escape | variableAddressEscapesTree(v.getAnAccess(), escape) |
33+
call.getArgument(0) = escape.getUnconverted()
34+
) and
35+
// `v` is a stack-allocated array or a struct.
36+
(
37+
v.getUnspecifiedType() instanceof ArrayType and call.getArgument(0) = v.getAnAccess()
38+
or
39+
v.getUnspecifiedType() instanceof Struct and
40+
call.getArgument(0).(AddressOfExpr).getAddressable() = v
41+
) and
42+
// There is no later use of `v`.
43+
not v.getAnAccess() = call.getASuccessor*() and
44+
// Not using the `-fno-builtin-memset` flag
45+
exists(Compilation c |
46+
c.getAFileCompiled() = call.getFile() and
47+
not c.getAnArgument() = "-fno-builtin-memset"
48+
)
49+
select call, "Call to " + memset.getName() + " may be deleted by the compiler."

cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c

Lines changed: 0 additions & 35 deletions
This file was deleted.

cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp

Lines changed: 0 additions & 31 deletions
This file was deleted.

cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql

Lines changed: 0 additions & 127 deletions
This file was deleted.

0 commit comments

Comments
 (0)