Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5cea452

Browse files
authored
Merge pull request #2491 from rdmarsh2/rdmarsh/cpp/ir-taintedIncludingGlobalVars
C++: handle global vars in DefaultTaintTracking
2 parents 648c199 + 18e7eff commit 5cea452

1 file changed

Lines changed: 113 additions & 43 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 113 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cpp
22
import semmle.code.cpp.security.Security
33
private import semmle.code.cpp.ir.dataflow.DataFlow
4+
private import semmle.code.cpp.ir.dataflow.DataFlow2
45
private import semmle.code.cpp.ir.IR
56
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
67

@@ -29,20 +30,60 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
2930
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
3031
}
3132

32-
override predicate isBarrier(DataFlow::Node node) {
33-
exists(Variable checkedVar |
34-
accessesVariable(node.asInstruction(), checkedVar) and
35-
hasUpperBoundsCheck(checkedVar)
33+
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
34+
}
35+
36+
private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
37+
ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" }
38+
39+
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
40+
41+
override predicate isSink(DataFlow::Node sink) {
42+
exists(GlobalOrNamespaceVariable gv | writesVariable(sink.asInstruction(), gv))
43+
}
44+
45+
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
46+
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
47+
or
48+
exists(StoreInstruction i1, LoadInstruction i2, GlobalOrNamespaceVariable gv |
49+
writesVariable(i1, gv) and
50+
readsVariable(i2, gv) and
51+
i1 = n1.asInstruction() and
52+
i2 = n2.asInstruction()
3653
)
3754
}
55+
56+
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
3857
}
3958

40-
private predicate accessesVariable(CopyInstruction copy, Variable var) {
41-
exists(VariableAddressInstruction va | va.getASTVariable() = var |
42-
copy.(StoreInstruction).getDestinationAddress() = va
43-
or
44-
copy.(LoadInstruction).getSourceAddress() = va
45-
)
59+
private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
60+
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
61+
62+
override predicate isSource(DataFlow::Node source) {
63+
exists(
64+
ToGlobalVarTaintTrackingCfg other, DataFlow::Node prevSink, GlobalOrNamespaceVariable gv
65+
|
66+
other.hasFlowTo(prevSink) and
67+
writesVariable(prevSink.asInstruction(), gv) and
68+
readsVariable(source.asInstruction(), gv)
69+
)
70+
}
71+
72+
override predicate isSink(DataFlow::Node sink) { any() }
73+
74+
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
75+
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
76+
}
77+
78+
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
79+
}
80+
81+
private predicate readsVariable(LoadInstruction load, Variable var) {
82+
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
83+
}
84+
85+
private predicate writesVariable(StoreInstruction store, Variable var) {
86+
store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() = var
4687
}
4788

4889
/**
@@ -62,6 +103,13 @@ private predicate hasUpperBoundsCheck(Variable var) {
62103
)
63104
}
64105

106+
private predicate nodeIsBarrier(DataFlow::Node node) {
107+
exists(Variable checkedVar |
108+
readsVariable(node.asInstruction(), checkedVar) and
109+
hasUpperBoundsCheck(checkedVar)
110+
)
111+
}
112+
65113
private predicate instructionTaintStep(Instruction i1, Instruction i2) {
66114
// Expressions computed from tainted data are also tainted
67115
i2 = any(CallInstruction call |
@@ -99,51 +147,73 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
99147
// addition expression.
100148
}
101149

150+
private Element adjustedSink(DataFlow::Node sink) {
151+
// TODO: is it more appropriate to use asConvertedExpr here and avoid
152+
// `getConversion*`? Or will that cause us to miss some cases where there's
153+
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
154+
// pretend there was flow to the converted `Expr` for the sake of
155+
// compatibility.
156+
sink.asExpr().getConversion*() = result
157+
or
158+
// For compatibility, send flow from arguments to parameters, even for
159+
// functions with no body.
160+
exists(FunctionCall call, int i |
161+
sink.asExpr() = call.getArgument(i) and
162+
result = resolveCall(call).getParameter(i)
163+
)
164+
or
165+
// For compatibility, send flow into a `Variable` if there is flow to any
166+
// Load or Store of that variable.
167+
exists(CopyInstruction copy |
168+
copy.getSourceValue() = sink.asInstruction() and
169+
(
170+
readsVariable(copy, result) or
171+
writesVariable(copy, result)
172+
) and
173+
not hasUpperBoundsCheck(result)
174+
)
175+
or
176+
// For compatibility, send flow into a `NotExpr` even if it's part of a
177+
// short-circuiting condition and thus might get skipped.
178+
result.(NotExpr).getOperand() = sink.asExpr()
179+
}
180+
102181
predicate tainted(Expr source, Element tainted) {
103182
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
104183
cfg.hasFlow(DataFlow::exprNode(source), sink)
105184
|
106-
// TODO: is it more appropriate to use asConvertedExpr here and avoid
107-
// `getConversion*`? Or will that cause us to miss some cases where there's
108-
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
109-
// pretend there was flow to the converted `Expr` for the sake of
110-
// compatibility.
111-
sink.asExpr().getConversion*() = tainted
112-
or
113-
// For compatibility, send flow from arguments to parameters, even for
114-
// functions with no body.
115-
exists(FunctionCall call, int i |
116-
sink.asExpr() = call.getArgument(i) and
117-
tainted = resolveCall(call).getParameter(i)
118-
)
119-
or
120-
// For compatibility, send flow into a `Variable` if there is flow to any
121-
// Load or Store of that variable.
122-
exists(CopyInstruction copy |
123-
copy.getSourceValue() = sink.asInstruction() and
124-
accessesVariable(copy, tainted) and
125-
not hasUpperBoundsCheck(tainted)
126-
)
127-
or
128-
// For compatibility, send flow into a `NotExpr` even if it's part of a
129-
// short-circuiting condition and thus might get skipped.
130-
tainted.(NotExpr).getOperand() = sink.asExpr()
185+
tainted = adjustedSink(sink)
131186
)
132187
}
133188

134189
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
135190
tainted(source, tainted) and
136-
// TODO: Find a way to emulate how `security.TaintTracking` reports the last
137-
// global variable that taint has passed through. Also make sure we emulate
138-
// its behavior for interprocedural flow through globals.
139191
globalVar = ""
192+
or
193+
exists(
194+
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg, DataFlow::Node store,
195+
GlobalOrNamespaceVariable global, DataFlow::Node load, DataFlow::Node sink
196+
|
197+
toCfg.hasFlow(DataFlow::exprNode(source), store) and
198+
store
199+
.asInstruction()
200+
.(StoreInstruction)
201+
.getDestinationAddress()
202+
.(VariableAddressInstruction)
203+
.getASTVariable() = global and
204+
load
205+
.asInstruction()
206+
.(LoadInstruction)
207+
.getSourceAddress()
208+
.(VariableAddressInstruction)
209+
.getASTVariable() = global and
210+
fromCfg.hasFlow(load, sink) and
211+
tainted = adjustedSink(sink) and
212+
global = globalVarFromId(globalVar)
213+
)
140214
}
141215

142-
GlobalOrNamespaceVariable globalVarFromId(string id) {
143-
// TODO: Implement this when `taintedIncludingGlobalVars` has support for
144-
// global variables.
145-
none()
146-
}
216+
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
147217

148218
Function resolveCall(Call call) {
149219
exists(CallInstruction callInstruction |

0 commit comments

Comments
 (0)