Skip to content

Commit 078f223

Browse files
committed
C++: Rewrite 'cpp/cpp/integer-overflow-tainted' away from DefaultTaintTracking.
1 parent f100137 commit 078f223

File tree

1 file changed

+77
-10
lines changed

1 file changed

+77
-10
lines changed

cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515

1616
import cpp
1717
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
18-
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
18+
import semmle.code.cpp.dataflow.new.DataFlow
19+
import semmle.code.cpp.security.FlowSources as FS
20+
import semmle.code.cpp.dataflow.new.TaintTracking
21+
import semmle.code.cpp.ir.IR
22+
import semmle.code.cpp.controlflow.IRGuards as IRGuards
1923

2024
/** Holds if `expr` might overflow. */
2125
predicate outOfBoundsExpr(Expr expr, string kind) {
@@ -27,13 +31,76 @@ predicate outOfBoundsExpr(Expr expr, string kind) {
2731
else none()
2832
}
2933

30-
from Expr use, Expr origin, string kind
34+
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
35+
36+
predicate isSink(DataFlow::Node sink, string kind) {
37+
exists(Expr use |
38+
use = sink.asExpr() and
39+
not use.getUnspecifiedType() instanceof PointerType and
40+
outOfBoundsExpr(use, kind) and
41+
not inSystemMacroExpansion(use)
42+
)
43+
}
44+
45+
predicate hasUpperBoundsCheck(Variable var) {
46+
exists(RelationalOperation oper, VariableAccess access |
47+
oper.getAnOperand() = access and
48+
access.getTarget() = var and
49+
// Comparing to 0 is not an upper bound check
50+
not oper.getAnOperand().getValue() = "0"
51+
)
52+
}
53+
54+
predicate constantInstruction(Instruction instr) {
55+
instr instanceof ConstantInstruction or
56+
constantInstruction(instr.(UnaryInstruction).getUnary())
57+
}
58+
59+
predicate readsVariable(LoadInstruction load, Variable var) {
60+
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
61+
}
62+
63+
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
64+
exists(Instruction instr | instr = node.asInstruction() |
65+
readsVariable(instr, checkedVar) and
66+
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
67+
)
68+
}
69+
70+
module Config implements DataFlow::ConfigSig {
71+
predicate isSource(DataFlow::Node source) { isSource(source, _) }
72+
73+
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
74+
75+
predicate isBarrier(DataFlow::Node node) {
76+
// Block flow if there's an upper bound check of the variable anywhere in the program
77+
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
78+
readsVariable(instr, checkedVar) and
79+
hasUpperBoundsCheck(checkedVar)
80+
)
81+
or
82+
// Block flow if the node is guarded by an equality check
83+
exists(Variable checkedVar, Operand access |
84+
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
85+
readsVariable(access.getDef(), checkedVar)
86+
)
87+
or
88+
// Block flow to any binary instruction whose operands are both non-constants.
89+
exists(BinaryInstruction iTo |
90+
iTo = node.asInstruction() and
91+
not constantInstruction(iTo.getLeft()) and
92+
not constantInstruction(iTo.getRight()) and
93+
// propagate taint from either the pointer or the offset, regardless of constantness
94+
not iTo instanceof PointerArithmeticInstruction
95+
)
96+
}
97+
}
98+
99+
module Flow = TaintTracking::Global<Config>;
100+
101+
from DataFlow::Node source, DataFlow::Node sink, string kind, string sourceType
31102
where
32-
not use.getUnspecifiedType() instanceof PointerType and
33-
outOfBoundsExpr(use, kind) and
34-
tainted(origin, use) and
35-
origin != use and
36-
not inSystemMacroExpansion(use) and
37-
// Avoid double-counting: don't include all the conversions of `use`.
38-
not use instanceof Conversion
39-
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"
103+
Flow::flow(source, sink) and
104+
isSource(source, sourceType) and
105+
isSink(sink, kind)
106+
select sink, "$@ flows an expression which might " + kind + ".", source, sourceType

0 commit comments

Comments
 (0)