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

Skip to content

Commit d99a90b

Browse files
author
Robert Marsh
committed
C++: handle global vars in DefaultTaintTracking
1 parent 57917be commit d99a90b

1 file changed

Lines changed: 99 additions & 28 deletions

File tree

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

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,61 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
3737
}
3838
}
3939

40+
private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
41+
ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" }
42+
43+
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
44+
45+
override predicate isSink(DataFlow::Node sink) {
46+
exists(GlobalOrNamespaceVariable gv |
47+
accessesVariable(sink.asInstruction(), gv) and
48+
sink.asInstruction() instanceof StoreInstruction
49+
)
50+
}
51+
52+
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
53+
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
54+
or
55+
exists(StoreInstruction i1, LoadInstruction i2, GlobalOrNamespaceVariable gv |
56+
accessesVariable(i1, gv) and
57+
accessesVariable(i2, gv) and
58+
i1 = n1.asInstruction() and
59+
i2 = n2.asInstruction()
60+
)
61+
}
62+
63+
override predicate isBarrier(DataFlow::Node node) {
64+
exists(Variable checkedVar |
65+
accessesVariable(node.asInstruction(), checkedVar) and
66+
hasUpperBoundsCheck(checkedVar)
67+
)
68+
}
69+
}
70+
71+
private class FromGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
72+
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
73+
74+
override predicate isSource(DataFlow::Node source) {
75+
exists(GlobalOrNamespaceVariable gv |
76+
accessesVariable(source.asInstruction(), gv) and
77+
source.asInstruction() instanceof LoadInstruction
78+
)
79+
}
80+
81+
override predicate isSink(DataFlow::Node sink) { any() }
82+
83+
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
84+
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
85+
}
86+
87+
override predicate isBarrier(DataFlow::Node node) {
88+
exists(Variable checkedVar |
89+
accessesVariable(node.asInstruction(), checkedVar) and
90+
hasUpperBoundsCheck(checkedVar)
91+
)
92+
}
93+
}
94+
4095
private predicate accessesVariable(CopyInstruction copy, Variable var) {
4196
exists(VariableAddressInstruction va | va.getASTVariable() = var |
4297
copy.(StoreInstruction).getDestinationAddress() = va
@@ -99,35 +154,39 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
99154
// addition expression.
100155
}
101156

157+
private Element adjustedSink(DataFlow::Node sink) {
158+
// TODO: is it more appropriate to use asConvertedExpr here and avoid
159+
// `getConversion*`? Or will that cause us to miss some cases where there's
160+
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
161+
// pretend there was flow to the converted `Expr` for the sake of
162+
// compatibility.
163+
sink.asExpr().getConversion*() = result
164+
or
165+
// For compatibility, send flow from arguments to parameters, even for
166+
// functions with no body.
167+
exists(FunctionCall call, int i |
168+
sink.asExpr() = call.getArgument(i) and
169+
result = resolveCall(call).getParameter(i)
170+
)
171+
or
172+
// For compatibility, send flow into a `Variable` if there is flow to any
173+
// Load or Store of that variable.
174+
exists(CopyInstruction copy |
175+
copy.getSourceValue() = sink.asInstruction() and
176+
accessesVariable(copy, result) and
177+
not hasUpperBoundsCheck(result)
178+
)
179+
or
180+
// For compatibility, send flow into a `NotExpr` even if it's part of a
181+
// short-circuiting condition and thus might get skipped.
182+
result.(NotExpr).getOperand() = sink.asExpr()
183+
}
184+
102185
predicate tainted(Expr source, Element tainted) {
103186
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
104187
cfg.hasFlow(DataFlow::exprNode(source), sink)
105188
|
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()
189+
tainted = adjustedSink(sink)
131190
)
132191
}
133192

@@ -137,12 +196,24 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
137196
// global variable that taint has passed through. Also make sure we emulate
138197
// its behavior for interprocedural flow through globals.
139198
globalVar = ""
199+
or
200+
exists(
201+
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg, DataFlow::Node store,
202+
GlobalOrNamespaceVariable global, DataFlow::Node load, DataFlow::Node sink
203+
|
204+
toCfg.hasFlow(DataFlow::exprNode(source), store) and
205+
accessesVariable(store.asInstruction(), global) and
206+
accessesVariable(load.asInstruction(), global) and
207+
fromCfg.hasFlow(load, sink) and
208+
tainted = adjustedSink(sink) and
209+
globalVar = global.toString()
210+
)
140211
}
141212

142213
GlobalOrNamespaceVariable globalVarFromId(string id) {
143-
// TODO: Implement this when `taintedIncludingGlobalVars` has support for
144-
// global variables.
145-
none()
214+
if result instanceof NamespaceVariable
215+
then id = result.getNamespace() + "::" + result.getName()
216+
else id = result.getName()
146217
}
147218

148219
Function resolveCall(Call call) {

0 commit comments

Comments
 (0)