Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4cee67d
Add files via upload
ihsinme Jan 13, 2021
3ad45f2
Add files via upload
ihsinme Jan 13, 2021
1c4610c
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
b26a90e
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
9e3b288
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
4631658
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
76b768f
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
4ba4de3
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
0d0ea0c
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
3e715ff
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
7f5e5fc
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
cd0d2a5
Update cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfC…
ihsinme Jan 14, 2021
10ab1d9
Update CompilerRemovalOfCodeToClearBuffers.ql
ihsinme Jan 14, 2021
8053529
Update CompilerRemovalOfCodeToClearBuffers.ql
ihsinme Jan 14, 2021
dcbae8b
Fix code tag.
MathiasVP Jan 15, 2021
4c9de45
Update CompilerRemovalOfCodeToClearBuffers.ql
ihsinme Jan 20, 2021
9c53e39
Update CompilerRemovalOfCodeToClearBuffers.ql
ihsinme Jan 21, 2021
416aa49
C++: Capitalize alert message.
MathiasVP Jan 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// BAD: the memset call will probably be removed.
void getPassword(void) {
char pwd[64];
if (GetPassword(pwd, sizeof(pwd))) {
/* Checking of password, secure operations, etc. */
}
memset(pwd, 0, sizeof(pwd));
}
// GOOD: in this case the memset will not be removed.
void getPassword(void) {
char pwd[64];

if (retrievePassword(pwd, sizeof(pwd))) {
/* Checking of password, secure operations, etc. */
}
memset_s(pwd, 0, sizeof(pwd));
}
// GOOD: in this case the memset will not be removed.
void getPassword(void) {
char pwd[64];
if (retrievePassword(pwd, sizeof(pwd))) {
/* Checking of password, secure operations, etc. */
}
SecureZeroMemory(pwd, sizeof(pwd));
}
// GOOD: in this case the memset will not be removed.
void getPassword(void) {
char pwd[64];
if (retrievePassword(pwd, sizeof(pwd))) {
/* Checking of password, secure operations, etc. */
}
#pragma optimize("", off)
memset(pwd, 0, sizeof(pwd));
#pragma optimize("", on)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Compiler optimization will exclude the cleaning of private information.
Using the <code>memset</code> function to clear private data in a variable that has no subsequent use is potentially dangerous, since the compiler can remove the call.
For some compilers, optimization is also possible when using calls to free memory after the <code>memset</code> function.</p>

<p>It is possible to miss detection of vulnerabilities if used to clear fields of structures or parts of a buffer.</p>

</overview>
<recommendation>

<p>We recommend to use the <code>RtlSecureZeroMemory</code> or <code>memset_s</code> functions, or compilation flags that exclude optimization of <code>memset</code> calls (e.g. -fno-builtin-memset).</p>

</recommendation>
<example>
<p>The following example demonstrates an erroneous and corrected use of the <code>memset</code> function.</p>
<sample src="CompilerRemovalOfCodeToClearBuffers.c" />

</example>
<references>

<li>
CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations">MSC06-C. Beware of compiler optimizations</a>.
</li>

</references>
</qhelp>
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* @name Compiler Removal Of Code To Clear Buffers
* @description Using <code>memset</code> the function to clear private data in a variable that has no subsequent use
* is potentially dangerous because the compiler can remove the call.
* @kind problem
* @id cpp/compiler-removal-of-code-to-clear-buffers
* @problem.severity warning
* @precision medium
* @tags security
* external/cwe/cwe-14
*/

import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.dataflow.StackAddress

/**
* A call to `memset` of the form `memset(ptr, value, num)`, for some local variable `ptr`.
*/
class CompilerRemovaMemset extends FunctionCall {
CompilerRemovaMemset() {
this.getTarget().hasGlobalOrStdName("memset") and
exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Expr exp |
DataFlow::localFlow(source, sink) and
this.getArgument(0) = isv.getAnAccess() and
(
source.asExpr() = exp
or
// handle the case where exp is defined by an address being passed into some function.
source.asDefiningArgument() = exp
) and
exp.getLocation().getEndLine() < this.getArgument(0).getLocation().getStartLine() and
sink.asExpr() = this.getArgument(0)
)
}

predicate isExistsAllocForThisVariable() {
exists(AllocationExpr alloc, Variable v |
alloc = v.getAnAssignedValue() and
this.getArgument(0) = v.getAnAccess() and
alloc.getASuccessor+() = this
)
or
not stackPointerFlowsToUse(this.getArgument(0), _, _, _)
}

predicate isExistsFreeForThisVariable() {
exists(DeallocationExpr free, Variable v |
this.getArgument(0) = v.getAnAccess() and
free.getFreedExpr() = v.getAnAccess() and
this.getASuccessor+() = free
)
}

predicate isExistsCallWithThisVariableExcludingDeallocationCalls() {
exists(FunctionCall fc, Variable v |
not fc instanceof DeallocationExpr and
this.getArgument(0) = v.getAnAccess() and
fc.getAnArgument() = v.getAnAccess() and
this.getASuccessor+() = fc
)
}

predicate isVariableUseAfterMemsetExcludingCalls() {
exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Expr exp |
DataFlow::localFlow(source, sink) and
this.getArgument(0) = isv.getAnAccess() and
source.asExpr() = isv.getAnAccess() and
exp.getLocation().getStartLine() > this.getArgument(2).getLocation().getEndLine() and
not exp.getParent() instanceof FunctionCall and
sink.asExpr() = exp
)
}

predicate isVariableUseBoundWithArgumentFunction() {
exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Parameter p, Expr exp |
DataFlow::localFlow(source, sink) and
this.getArgument(0) = isv.getAnAccess() and
this.getEnclosingFunction().getAParameter() = p and
exp.getAChild*() = p.getAnAccess() and
source.asExpr() = exp and
sink.asExpr() = isv.getAnAccess()
)
}

predicate isVariableUseBoundWithGlobalVariable() {
exists(
DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, GlobalVariable gv, Expr exp
|
DataFlow::localFlow(source, sink) and
this.getArgument(0) = isv.getAnAccess() and
exp.getAChild*() = gv.getAnAccess() and
source.asExpr() = exp and
sink.asExpr() = isv.getAnAccess()
)
}

predicate isExistsCompilationFlagsBlockingRemoval() {
exists(Compilation c |
c.getAFileCompiled() = this.getFile() and
c.getAnArgument() = "-fno-builtin-memset"
)
}

predicate isUseVCCompilation() {
exists(Compilation c |
c.getAFileCompiled() = this.getFile() and
(
c.getArgument(2).matches("%gcc%") or
c.getArgument(2).matches("%g++%") or
c.getArgument(2).matches("%clang%") or
c.getArgument(2) = "--force-recompute"
)
)
}
}

from CompilerRemovaMemset fc
where
not (fc.isExistsAllocForThisVariable() and not fc.isExistsFreeForThisVariable()) and
not (fc.isExistsFreeForThisVariable() and not fc.isUseVCCompilation()) and
not fc.isVariableUseAfterMemsetExcludingCalls() and
not fc.isExistsCallWithThisVariableExcludingDeallocationCalls() and
not fc.isVariableUseBoundWithArgumentFunction() and
not fc.isVariableUseBoundWithGlobalVariable() and
not fc.isExistsCompilationFlagsBlockingRemoval()
select fc.getArgument(0), "This variable will not be cleared."
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
| test.c:13:9:13:13 | buff1 | This variable will not be cleared. |
| test.c:35:9:35:13 | buff1 | This variable will not be cleared. |
| test.c:43:9:43:13 | buff1 | This variable will not be cleared. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql
Loading