Skip to content

Commit 50b7776

Browse files
committed
C++: Port the 'predictable' barrier from 'DefaultTaintTracking' to 'cpp/unclear-array-index-validation' to prevent an explosion of new results.
1 parent 0da5d91 commit 50b7776

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import semmle.code.cpp.security.FlowSources
1818
import semmle.code.cpp.ir.dataflow.TaintTracking
1919
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
2020
import DataFlow::PathGraph
21+
import semmle.code.cpp.security.Security
2122

2223
predicate hasUpperBound(VariableAccess offsetExpr) {
2324
exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
@@ -55,6 +56,15 @@ predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Va
5556

5657
predicate isFlowSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
5758

59+
predicate predictableInstruction(Instruction instr) {
60+
instr instanceof ConstantInstruction
61+
or
62+
instr instanceof StringConstantInstruction
63+
or
64+
// This could be a conversion on a string literal
65+
predictableInstruction(instr.(UnaryInstruction).getUnary())
66+
}
67+
5868
class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
5969
ImproperArrayIndexValidationConfig() { this = "ImproperArrayIndexValidationConfig" }
6070

@@ -63,6 +73,8 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
6373
override predicate isSanitizer(DataFlow::Node node) {
6474
hasUpperBound(node.asExpr())
6575
or
76+
// These barriers are ported from `DefaultTaintTracking` because this query is quite noisy
77+
// otherwise.
6678
exists(Variable checkedVar |
6779
readsVariable(node.asInstruction(), checkedVar) and
6880
hasUpperBoundsCheck(checkedVar)
@@ -72,6 +84,27 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
7284
readsVariable(access.getDef(), checkedVar) and
7385
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
7486
)
87+
or
88+
// Don't use dataflow into binary instructions if both operands are unpredictable
89+
exists(BinaryInstruction iTo |
90+
iTo = node.asInstruction() and
91+
not predictableInstruction(iTo.getLeft()) and
92+
not predictableInstruction(iTo.getRight()) and
93+
// propagate taint from either the pointer or the offset, regardless of predictability
94+
not iTo instanceof PointerArithmeticInstruction
95+
)
96+
or
97+
// don't use dataflow through calls to pure functions if two or more operands
98+
// are unpredictable
99+
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
100+
iTo = node.asInstruction() and
101+
isPureFunction(iTo.getStaticCallTarget().getName()) and
102+
iFrom1 = iTo.getAnArgument() and
103+
iFrom2 = iTo.getAnArgument() and
104+
not predictableInstruction(iFrom1) and
105+
not predictableInstruction(iFrom2) and
106+
iFrom1 != iFrom2
107+
)
75108
}
76109

77110
override predicate isSink(DataFlow::Node sink) {

0 commit comments

Comments
 (0)