Skip to content

Commit 8a8fb69

Browse files
committed
C++: Use a 'TaintTracking::Configuration' for 'cpp/uncontrolled-allocation-size'.
1 parent 2328898 commit 8a8fb69

File tree

2 files changed

+90
-153
lines changed

2 files changed

+90
-153
lines changed

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

Lines changed: 73 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,55 +15,89 @@
1515

1616
import cpp
1717
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
18-
import semmle.code.cpp.security.TaintTracking
19-
import TaintedWithPath
18+
import semmle.code.cpp.ir.dataflow.TaintTracking
19+
import semmle.code.cpp.ir.IR
20+
import semmle.code.cpp.controlflow.IRGuards
21+
import semmle.code.cpp.security.FlowSources
22+
import DataFlow::PathGraph
2023

2124
/**
2225
* Holds if `alloc` is an allocation, and `tainted` is a child of it that is a
2326
* taint sink.
2427
*/
25-
predicate allocSink(Expr alloc, Expr tainted) {
26-
isAllocationExpr(alloc) and
27-
tainted = alloc.getAChild() and
28-
tainted.getUnspecifiedType() instanceof IntegralType
28+
predicate allocSink(Expr alloc, DataFlow::Node sink) {
29+
exists(Expr e | e = sink.asConvertedExpr() |
30+
isAllocationExpr(alloc) and
31+
e = alloc.getAChild() and
32+
e.getUnspecifiedType() instanceof IntegralType
33+
)
34+
}
35+
36+
predicate readsVariable(LoadInstruction load, Variable var) {
37+
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
38+
}
39+
40+
predicate hasUpperBoundsCheck(Variable var) {
41+
exists(RelationalOperation oper, VariableAccess access |
42+
oper.getAnOperand() = access and
43+
access.getTarget() = var and
44+
// Comparing to 0 is not an upper bound check
45+
not oper.getAnOperand().getValue() = "0"
46+
)
47+
}
48+
49+
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
50+
readsVariable(node.asInstruction(), checkedVar) and
51+
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
2952
}
3053

31-
class TaintedAllocationSizeConfiguration extends TaintTrackingConfiguration {
32-
override predicate isSink(Element tainted) { allocSink(_, tainted) }
54+
predicate isFlowSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
55+
56+
class TaintedAllocationSizeConfiguration extends TaintTracking::Configuration {
57+
TaintedAllocationSizeConfiguration() { this = "TaintedAllocationSizeConfiguration" }
58+
59+
override predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
60+
61+
override predicate isSink(DataFlow::Node sink) { allocSink(_, sink) }
3362

34-
override predicate isBarrier(Expr e) {
35-
super.isBarrier(e)
63+
override predicate isSanitizer(DataFlow::Node node) {
64+
exists(Expr e | e = node.asExpr() |
65+
// There can be two separate reasons for `convertedExprMightOverflow` not holding:
66+
// 1. `e` really cannot overflow.
67+
// 2. `e` isn't analyzable.
68+
// If we didn't rule out case 2 we would place barriers on anything that isn't analyzable.
69+
(
70+
e instanceof UnaryArithmeticOperation or
71+
e instanceof BinaryArithmeticOperation or
72+
e instanceof AssignArithmeticOperation
73+
) and
74+
not convertedExprMightOverflow(e)
75+
or
76+
// Subtracting two pointers is either well-defined (and the result will likely be small), or
77+
// terribly undefined and dangerous. Here, we assume that the programmer has ensured that the
78+
// result is well-defined (i.e., the two pointers point to the same object), and thus the result
79+
// will likely be small.
80+
e = any(PointerDiffExpr diff).getAnOperand()
81+
)
3682
or
37-
// There can be two separate reasons for `convertedExprMightOverflow` not holding:
38-
// 1. `e` really cannot overflow.
39-
// 2. `e` isn't analyzable.
40-
// If we didn't rule out case 2 we would place barriers on anything that isn't analyzable.
41-
(
42-
e instanceof UnaryArithmeticOperation or
43-
e instanceof BinaryArithmeticOperation or
44-
e instanceof AssignArithmeticOperation
45-
) and
46-
not convertedExprMightOverflow(e)
83+
exists(Variable checkedVar |
84+
readsVariable(node.asInstruction(), checkedVar) and
85+
hasUpperBoundsCheck(checkedVar)
86+
)
4787
or
48-
// Subtracting two pointers is either well-defined (and the result will likely be small), or
49-
// terribly undefined and dangerous. Here, we assume that the programmer has ensured that the
50-
// result is well-defined (i.e., the two pointers point to the same object), and thus the result
51-
// will likely be small.
52-
e = any(PointerDiffExpr diff).getAnOperand()
88+
exists(Variable checkedVar, Operand access |
89+
readsVariable(access.getDef(), checkedVar) and
90+
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
91+
)
5392
}
5493
}
5594

56-
predicate taintedAllocSize(
57-
Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause
58-
) {
59-
isUserInput(source, taintCause) and
60-
exists(Expr tainted |
61-
allocSink(alloc, tainted) and
62-
taintedWithPath(source, tainted, sourceNode, sinkNode)
63-
)
64-
}
65-
66-
from Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause
67-
where taintedAllocSize(source, alloc, sourceNode, sinkNode, taintCause)
68-
select alloc, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow",
69-
source, "user input (" + taintCause + ")"
95+
from
96+
Expr alloc, DataFlow::PathNode source, DataFlow::PathNode sink, string taintCause,
97+
TaintedAllocationSizeConfiguration conf
98+
where
99+
isFlowSource(source.getNode(), taintCause) and
100+
conf.hasFlowPath(source, sink) and
101+
allocSink(alloc, sink.getNode())
102+
select alloc, source, sink, "This allocation size is derived from $@ and might overflow",
103+
source.getNode(), "user input (" + taintCause + ")"

0 commit comments

Comments
 (0)