Skip to content

Commit 52d8ca0

Browse files
authored
Merge pull request github#1169 from markshannon/python-speedup-flow-step
Python: Speed up taint-tracking
2 parents 23eed30 + 1e1903b commit 52d8ca0

File tree

1 file changed

+63
-39
lines changed

1 file changed

+63
-39
lines changed

python/ql/src/semmle/python/security/TaintTracking.qll

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -189,25 +189,13 @@ class SequenceKind extends CollectionKind {
189189
}
190190

191191
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
192-
sequence_subscript_taint(tonode, fromnode, this, result)
193-
or
194-
result = this and
195-
(
196-
slice(fromnode, tonode) or
197-
tonode.(BinaryExprNode).getAnOperand() = fromnode
198-
)
199-
or
200-
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
201-
or
202192
exists(BinaryExprNode mod |
203193
mod = tonode and
204194
mod.getOp() instanceof Mod and
205195
mod.getAnOperand() = fromnode and
206196
result = this.getItem() and
207197
result.getClass() = theStrType()
208198
)
209-
or
210-
result = this and sequence_call(fromnode, tonode)
211199
}
212200

213201
override TaintKind getTaintOfMethodResult(string name) {
@@ -220,26 +208,42 @@ class SequenceKind extends CollectionKind {
220208

221209
}
222210

223-
/* Helper for getTaintForStep() */
211+
212+
module SequenceKind {
213+
214+
predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
215+
tonode.(BinaryExprNode).getAnOperand() = fromnode
216+
or
217+
TaintFlowImplementation::copyCall(fromnode, tonode)
218+
or
219+
sequence_call(fromnode, tonode)
220+
or
221+
sequence_subscript_slice(fromnode, tonode)
222+
}
223+
224+
predicate itemFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
225+
sequence_subscript_index(fromnode, tonode)
226+
}
227+
228+
}
229+
230+
231+
/* Helper for sequence flow steps */
224232
pragma [noinline]
225-
private predicate sequence_subscript_taint(SubscriptNode sub, ControlFlowNode obj, SequenceKind seq, TaintKind key) {
233+
private predicate sequence_subscript_index(ControlFlowNode obj, SubscriptNode sub) {
226234
sub.isLoad() and
227235
sub.getValue() = obj and
228-
if sub.getNode().getIndex() instanceof Slice then
229-
seq = key
230-
else
231-
key = seq.getItem()
236+
not sub.getNode().getIndex() instanceof Slice
232237
}
233238

234-
/* tonode = fromnode[:] */
235-
private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
236-
exists(Slice all |
237-
all = tonode.getIndex().getNode() and
238-
not exists(all.getStart()) and not exists(all.getStop()) and
239-
tonode.getValue() = fromnode
240-
)
239+
pragma [noinline]
240+
private predicate sequence_subscript_slice(ControlFlowNode obj, SubscriptNode sub) {
241+
sub.isLoad() and
242+
sub.getValue() = obj and
243+
sub.getNode().getIndex() instanceof Slice
241244
}
242245

246+
243247
/** A taint kind representing a mapping of objects to kinds.
244248
* Typically a dict, but can include other mappings.
245249
*/
@@ -255,20 +259,6 @@ class DictKind extends CollectionKind {
255259
result = valueKind
256260
}
257261

258-
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
259-
result = valueKind and
260-
tonode.(SubscriptNode).getValue() = fromnode and tonode.isLoad()
261-
or
262-
result = valueKind and
263-
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode
264-
or
265-
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
266-
or
267-
result = this and
268-
tonode.(CallNode).getFunction().refersTo(theDictType()) and
269-
tonode.(CallNode).getArg(0) = fromnode
270-
}
271-
272262
override TaintKind getTaintOfMethodResult(string name) {
273263
name = "get" and result = valueKind
274264
or
@@ -284,6 +274,24 @@ class DictKind extends CollectionKind {
284274
}
285275

286276

277+
module DictKind {
278+
279+
predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
280+
TaintFlowImplementation::copyCall(fromnode, tonode)
281+
or
282+
tonode.(CallNode).getFunction().refersTo(theDictType()) and
283+
tonode.(CallNode).getArg(0) = fromnode
284+
}
285+
286+
predicate valueFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
287+
tonode.(SubscriptNode).getValue() = fromnode and tonode.isLoad()
288+
or
289+
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode
290+
}
291+
292+
}
293+
294+
287295
/** A type of sanitizer of untrusted data.
288296
* Examples include sanitizers for http responses, for DB access or for shell commands.
289297
* Usually a sanitizer can only sanitize data for one particular use.
@@ -890,6 +898,22 @@ library module TaintFlowImplementation {
890898
tocontext = fromnode.getContext()
891899
)
892900
or
901+
exists(SequenceKind fromkind |
902+
fromkind = fromnode.getTaintKind() and
903+
tocontext = fromnode.getContext() |
904+
totaint = fromnode.getTrackedValue() and SequenceKind::flowStep(fromnode.getNode(), tonode)
905+
or
906+
totaint = fromnode.getTrackedValue().toKind(fromkind.getItem()) and SequenceKind::itemFlowStep(fromnode.getNode(), tonode)
907+
)
908+
or
909+
exists(DictKind fromkind |
910+
fromkind = fromnode.getTaintKind() and
911+
tocontext = fromnode.getContext() |
912+
totaint = fromnode.getTrackedValue() and DictKind::flowStep(fromnode.getNode(), tonode)
913+
or
914+
totaint = fromnode.getTrackedValue().toKind(fromkind.getValue()) and DictKind::valueFlowStep(fromnode.getNode(), tonode)
915+
)
916+
or
893917
exists(TaintFlow flow, TaintKind tokind |
894918
flow.additionalFlowStep(fromnode.getNode(), fromnode.getTaintKind(), tonode, tokind) and
895919
totaint = fromnode.getTrackedValue().toKind(tokind) and

0 commit comments

Comments
 (0)