Skip to content

Commit 9439ed4

Browse files
committed
Merge branch 'main' into better-path-explanation-for-this-indirection
2 parents 55da16c + 2c4ba56 commit 9439ed4

File tree

92 files changed

+3640
-2004
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3640
-2004
lines changed

.github/workflows/docs-review.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ jobs:
2626
PR_NUMBER: ${{ github.event.pull_request.number }}
2727
run: |
2828
gh pr comment "$PR_NUMBER" --repo "github/codeql" \
29-
--body "Hello @github/docs-content-codeql: this PR is ready for docs review."
29+
--body "Hello @github/docs-content-codeql - this PR is ready for docs review."

.github/workflows/generate-query-help-docs.yml

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

cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,39 @@ predicate isNonEscapingArgument(Expr escaped) {
3838
)
3939
}
4040

41+
pragma[noinline]
42+
predicate callToMemsetWithRelevantVariable(
43+
LocalVariable v, VariableAccess acc, FunctionCall call, MemsetFunction memset
44+
) {
45+
not v.isStatic() and
46+
// Reference-typed variables get special treatment in `variableAddressEscapesTree` so we leave them
47+
// out of this query.
48+
not v.getUnspecifiedType() instanceof ReferenceType and
49+
call.getTarget() = memset and
50+
acc = v.getAnAccess() and
51+
// `v` escapes as the argument to `memset`
52+
variableAddressEscapesTree(acc, call.getArgument(0).getFullyConverted())
53+
}
54+
55+
pragma[noinline]
56+
predicate relevantVariable(LocalVariable v, FunctionCall call, MemsetFunction memset) {
57+
exists(VariableAccess acc, VariableAccess anotherAcc |
58+
callToMemsetWithRelevantVariable(v, acc, call, memset) and
59+
// `v` is not only just used in the call to `memset`.
60+
anotherAcc = v.getAnAccess() and
61+
acc != anotherAcc and
62+
not anotherAcc.isUnevaluated()
63+
)
64+
}
65+
4166
from FunctionCall call, LocalVariable v, MemsetFunction memset
4267
where
43-
call.getTarget() = memset and
68+
relevantVariable(v, call, memset) and
4469
not isFromMacroDefinition(call) and
45-
// `v` escapes as the argument to `memset`
46-
variableAddressEscapesTree(v.getAnAccess(), call.getArgument(0).getFullyConverted()) and
47-
// ... and `v` doesn't escape anywhere else.
70+
// `v` doesn't escape anywhere else.
4871
forall(Expr escape | variableAddressEscapesTree(v.getAnAccess(), escape) |
4972
isNonEscapingArgument(escape)
5073
) and
51-
not v.isStatic() and
52-
// Reference-typed variables get special treatment in `variableAddressEscapesTree` so we leave them
53-
// out of this query.
54-
not v.getUnspecifiedType() instanceof ReferenceType and
55-
// `v` is not only just used in the call to `memset`.
56-
exists(Access acc |
57-
acc = v.getAnAccess() and not call.getArgument(0).getAChild*() = acc and not acc.isUnevaluated()
58-
) and
5974
// There is no later use of `v`.
6075
not v.getAnAccess() = call.getASuccessor*() and
6176
// Not using the `-fno-builtin-memset` flag
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
if(len<0) return 1;
2+
memset(dest, source, len); // GOOD: variable `len` checked before call
3+
4+
...
5+
6+
memset(dest, source, len); // BAD: variable `len` checked after call
7+
if(len<0) return 1;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Checking the function argument after calling the function itself. This situation looks suspicious and requires the attention of the developer. It may be necessary to add validation before calling the function</p>
7+
8+
9+
</overview>
10+
<recommendation>
11+
12+
<p>We recommend checking before calling the function.</p>
13+
14+
</recommendation>
15+
<example>
16+
<p>The following example demonstrates an erroneous and fixed use of function argument validation.</p>
17+
<sample src="LateCheckOfFunctionArgument.c" />
18+
19+
</example>
20+
<references>
21+
22+
<li>
23+
CWE Common Weakness Enumeration:
24+
<a href="https://cwe.mitre.org/data/definitions/20.html"> CWE-20: Improper Input Validation</a>.
25+
</li>
26+
27+
</references>
28+
</qhelp>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @name Late Check Of Function Argument
3+
* @description --Checking the function argument after calling the function itself.
4+
* --This situation looks suspicious and requires the attention of the developer.
5+
* --It may be necessary to add validation before calling the function.
6+
* @kind problem
7+
* @id cpp/late-check-of-function-argument
8+
* @problem.severity warning
9+
* @precision medium
10+
* @tags correctness
11+
* security
12+
* external/cwe/cwe-20
13+
*/
14+
15+
import cpp
16+
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
17+
18+
/** Holds for a function `f` that has an argument at index `apos` used for positioning in a buffer. */
19+
predicate numberArgument(Function f, int apos) {
20+
f.hasGlobalOrStdName("write") and apos = 2
21+
or
22+
f.hasGlobalOrStdName("read") and apos = 2
23+
or
24+
f.hasGlobalOrStdName("lseek") and apos = 1
25+
or
26+
f.hasGlobalOrStdName("memmove") and apos = 2
27+
or
28+
f.hasGlobalOrStdName("memset") and apos = 2
29+
or
30+
f.hasGlobalOrStdName("memcpy") and apos = 2
31+
or
32+
f.hasGlobalOrStdName("memcmp") and apos = 2
33+
or
34+
f.hasGlobalOrStdName("strncat") and apos = 2
35+
or
36+
f.hasGlobalOrStdName("strncpy") and apos = 2
37+
or
38+
f.hasGlobalOrStdName("strncmp") and apos = 2
39+
or
40+
f.hasGlobalOrStdName("snprintf") and apos = 1
41+
or
42+
f.hasGlobalOrStdName("strndup") and apos = 2
43+
}
44+
45+
class IfCompareWithZero extends IfStmt {
46+
IfCompareWithZero() { this.getCondition().(RelationalOperation).getAChild().getValue() = "0" }
47+
48+
Expr noZerroOperand() {
49+
if this.getCondition().(RelationalOperation).getGreaterOperand().getValue() = "0"
50+
then result = this.getCondition().(RelationalOperation).getLesserOperand()
51+
else result = this.getCondition().(RelationalOperation).getGreaterOperand()
52+
}
53+
}
54+
55+
from FunctionCall fc, IfCompareWithZero ifc, int na
56+
where
57+
numberArgument(fc.getTarget(), na) and
58+
globalValueNumber(fc.getArgument(na)) = globalValueNumber(ifc.noZerroOperand()) and
59+
dominates(fc, ifc) and
60+
not exists(IfStmt ifc1 |
61+
dominates(ifc1, fc) and
62+
globalValueNumber(fc.getArgument(na)) = globalValueNumber(ifc1.getCondition().getAChild*())
63+
)
64+
select fc,
65+
"The value of argument '$@' appears to be checked after the call, rather than before it.",
66+
fc.getArgument(na), fc.getArgument(na).toString()

0 commit comments

Comments
 (0)