Skip to content

Commit c9bd9e9

Browse files
committed
C++: Modernize the 'cpp/unclear-array-index-validation' query by getting rid of the DefaultTaintTracking barriers and replacing them with a 'BarrierGuard' instantiation.
1 parent 9bfd461 commit c9bd9e9

File tree

1 file changed

+21
-79
lines changed

1 file changed

+21
-79
lines changed

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

Lines changed: 21 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -14,102 +14,44 @@
1414

1515
import cpp
1616
import semmle.code.cpp.controlflow.IRGuards
17-
import semmle.code.cpp.security.FlowSources
18-
import semmle.code.cpp.ir.dataflow.TaintTracking
17+
import semmle.code.cpp.security.FlowSources as FS
18+
import semmle.code.cpp.dataflow.new.TaintTracking
1919
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
2020
import ImproperArrayIndexValidation::PathGraph
21-
import semmle.code.cpp.security.Security
2221

23-
predicate hasUpperBound(VariableAccess offsetExpr) {
24-
exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
25-
controlled.contains(offsetExpr) and
26-
linearBoundControls(controlled, def, offsetVar) and
27-
offsetExpr = def.getAUse(offsetVar)
28-
)
29-
}
30-
31-
pragma[noinline]
32-
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) {
33-
exists(GuardCondition guard, boolean branch |
34-
guard.controls(controlled, branch) and
35-
cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch)
36-
)
37-
}
38-
39-
predicate readsVariable(LoadInstruction load, Variable var) {
40-
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
22+
predicate isFlowSource(FS::FlowSource source, string sourceType) {
23+
sourceType = source.getSourceType()
4124
}
4225

43-
predicate hasUpperBoundsCheck(Variable var) {
44-
exists(RelationalOperation oper, VariableAccess access |
45-
oper.getAnOperand() = access and
46-
access.getTarget() = var and
47-
// Comparing to 0 is not an upper bound check
48-
not oper.getAnOperand().getValue() = "0"
26+
predicate guardChecks(IRGuardCondition g, Expr e, boolean branch) {
27+
exists(Operand op | op.getDef().getConvertedResultExpression() = e |
28+
// op < k
29+
g.comparesLt(op, _, true, any(BooleanValue bv | bv.getValue() = branch))
30+
or
31+
// op < _ + k
32+
g.comparesLt(op, _, _, true, branch)
33+
or
34+
// op == k
35+
g.comparesEq(op, _, true, any(BooleanValue bv | bv.getValue() = branch))
36+
or
37+
// op == _ + k
38+
g.comparesEq(op, _, _, true, branch)
4939
)
5040
}
5141

52-
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
53-
readsVariable(node.asInstruction(), checkedVar) and
54-
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
55-
}
56-
57-
predicate isFlowSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
58-
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-
6842
module ImproperArrayIndexValidationConfig implements DataFlow::ConfigSig {
6943
predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
7044

7145
predicate isBarrier(DataFlow::Node node) {
72-
hasUpperBound(node.asExpr())
73-
or
74-
// These barriers are ported from `DefaultTaintTracking` because this query is quite noisy
75-
// otherwise.
76-
exists(Variable checkedVar |
77-
readsVariable(node.asInstruction(), checkedVar) and
78-
hasUpperBoundsCheck(checkedVar)
79-
)
80-
or
81-
exists(Variable checkedVar, Operand access |
82-
readsVariable(access.getDef(), checkedVar) and
83-
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
84-
)
85-
or
86-
// Don't use dataflow into binary instructions if both operands are unpredictable
87-
exists(BinaryInstruction iTo |
88-
iTo = node.asInstruction() and
89-
not predictableInstruction(iTo.getLeft()) and
90-
not predictableInstruction(iTo.getRight()) and
91-
// propagate taint from either the pointer or the offset, regardless of predictability
92-
not iTo instanceof PointerArithmeticInstruction
93-
)
94-
or
95-
// don't use dataflow through calls to pure functions if two or more operands
96-
// are unpredictable
97-
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
98-
iTo = node.asInstruction() and
99-
isPureFunction(iTo.getStaticCallTarget().getName()) and
100-
iFrom1 = iTo.getAnArgument() and
101-
iFrom2 = iTo.getAnArgument() and
102-
not predictableInstruction(iFrom1) and
103-
not predictableInstruction(iFrom2) and
104-
iFrom1 != iFrom2
105-
)
46+
node = DataFlow::BarrierGuard<guardChecks/3>::getABarrierNode()
10647
}
10748

49+
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
50+
10851
predicate isSink(DataFlow::Node sink) {
10952
exists(ArrayExpr arrayExpr, VariableAccess offsetExpr |
11053
offsetExpr = arrayExpr.getArrayOffset() and
111-
sink.asExpr() = offsetExpr and
112-
not hasUpperBound(offsetExpr)
54+
sink.asExpr() = offsetExpr
11355
)
11456
}
11557
}

0 commit comments

Comments
 (0)