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

Skip to content

Commit da6a669

Browse files
committed
Python taint-tracking. Further improvements to new taint-tracking.
1 parent 74f1dd3 commit da6a669

3 files changed

Lines changed: 182 additions & 30 deletions

File tree

python/ql/src/semmle/python/dataflow/Configuration.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ module TaintTracking {
8686

8787
/* Old query API */
8888

89-
deprecated predicate hasFlow(Source source, Sink sink) {
89+
/* deprecated */
90+
predicate hasFlow(Source source, Sink sink) {
9091
exists(PathSource psource, PathSink psink |
9192
this.hasFlowPath(psource, psink) and
9293
source = psource.getNode().asCfgNode() and

python/ql/src/semmle/python/dataflow/Implementation.qll

Lines changed: 149 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import python
22
import semmle.python.security.TaintTracking
33
private import semmle.python.objects.ObjectInternal
4+
private import semmle.python.pointsto.Filters as Filters
45

56
newtype TTaintTrackingContext =
67
TNoParam()
@@ -85,21 +86,14 @@ class NoAttribute extends TNoAttribute, AttributePath {
8586

8687
newtype TTaintTrackingNode =
8788
TTaintTrackingNode_(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, TaintTracking::Configuration config) {
88-
config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind)
89-
or
90-
config.isSource(node, kind) and context = TNoParam() and path = TNoAttribute()
89+
config.(TaintTrackingImplementation).flowSource(node, context, path, kind)
9190
or
92-
exists(TaintSource source |
93-
config.isSource(source) and
94-
node.asCfgNode() = source and
95-
source.isSourceOf(kind)
96-
) and
97-
context = TNoParam() and path = TNoAttribute()
91+
config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind)
9892
}
9993

10094
class TaintTrackingNode extends TTaintTrackingNode {
10195

102-
string toString() { result = this.getTaintKind() + " at " + this.getNode().getLocation() }
96+
string toString() { result = this.getTaintKind().repr() }
10397

10498
DataFlow::Node getNode() {
10599
this = TTaintTrackingNode_(result, _, _, _, _)
@@ -151,17 +145,39 @@ class TaintTrackingImplementation extends string {
151145
sink = source.getASuccessor*()
152146
}
153147

148+
predicate flowSource(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
149+
this.(TaintTracking::Configuration).isSource(node, kind) and context = TNoParam() and path = TNoAttribute()
150+
or
151+
exists(TaintSource source |
152+
this.(TaintTracking::Configuration).isSource(source) and
153+
node.asCfgNode() = source and
154+
source.isSourceOf(kind)
155+
) and
156+
context = TNoParam() and path = TNoAttribute()
157+
}
158+
159+
160+
predicate flowSink(DataFlow::Node node, AttributePath path, TaintKind kind) {
161+
this.(TaintTracking::Configuration).isSink(node, kind) and path = TNoAttribute()
162+
or
163+
exists(TaintSink sink |
164+
this.(TaintTracking::Configuration).isSink(sink) and
165+
node.asCfgNode() = sink and
166+
sink.sinks(kind)
167+
) and path = TNoAttribute()
168+
}
169+
154170
predicate isPathSource(TaintTrackingNode source) {
155-
exists(DataFlow::Node srcnode, TaintKind kind |
156-
source = TTaintTrackingNode_(srcnode, TNoParam(), TNoAttribute(), kind, this) and
157-
this.(TaintTracking::Configuration).isSource(srcnode, kind)
171+
exists(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind |
172+
source = TTaintTrackingNode_(node, context, path, kind, this) and
173+
this.flowSource(node, context, path, kind)
158174
)
159175
}
160176

161177
predicate isPathSink(TaintTrackingNode sink) {
162-
exists(DataFlow::Node sinknode, TaintKind kind |
163-
sink = TTaintTrackingNode_(sinknode, _, TNoAttribute(), kind, this) and
164-
this.(TaintTracking::Configuration).isSink(sinknode, kind)
178+
exists(DataFlow::Node node, AttributePath path, TaintKind kind |
179+
sink = TTaintTrackingNode_(node, _, path, kind, this) and
180+
this.flowSink(node, path, kind)
165181
)
166182
}
167183

@@ -172,19 +188,92 @@ class TaintTrackingImplementation extends string {
172188
)
173189
}
174190

191+
predicate flowBarrier(DataFlow::Node node, TaintKind kind) {
192+
this.(TaintTracking::Configuration).isBarrier(node, kind)
193+
or
194+
exists(Sanitizer sanitizer |
195+
this.(TaintTracking::Configuration).isSanitizer(sanitizer)
196+
|
197+
sanitizer.sanitizingNode(kind, node.asCfgNode())
198+
or
199+
sanitizer.sanitizingDefinition(kind, node.asVariable().getDefinition())
200+
or
201+
exists(MethodCallsiteRefinement call, FunctionObject callee |
202+
call = node.asVariable().getDefinition() and
203+
callee.getACall() = call.getCall() and
204+
sanitizer.sanitizingCall(kind, callee)
205+
)
206+
or
207+
sanitizer.sanitizingEdge(kind, node.asVariable().getDefinition())
208+
or
209+
sanitizer.sanitizingSingleEdge(kind, node.asVariable().getDefinition())
210+
or
211+
exists(PyEdgeRefinement test |
212+
test = node.asVariable().getDefinition()
213+
|
214+
exists(ControlFlowNode c, ClassValue cls |
215+
Filters::isinstance(test.getTest(), c, test.getInput().getSourceVariable().getAUse()) and
216+
c.pointsTo(cls)
217+
|
218+
test.getSense() = true and not exists(kind.getClass())
219+
or
220+
test.getSense() = true and kind.getType().getASuperType() = cls
221+
or
222+
test.getSense() = false and not kind.getType().getASuperType() = cls
223+
)
224+
or
225+
test.getSense() = test_evaluates(test.getTest(), test.getInput().getSourceVariable().getAUse(), kind)
226+
)
227+
)
228+
}
229+
230+
/** Gets the boolean value that `test` evaluates to when `use` is tainted with `kind`
231+
* and `test` and `use` are part of a test in a branch.
232+
*/
233+
private boolean test_evaluates(ControlFlowNode test, ControlFlowNode use, TaintKind kind) {
234+
boolean_filter(_, use) and
235+
kind.taints(use) and
236+
test = use and result = kind.booleanValue()
237+
or
238+
result = test_evaluates(not_operand(test), use, kind).booleanNot()
239+
}
240+
241+
/** Gets the operand of a unary `not` expression. */
242+
private ControlFlowNode not_operand(ControlFlowNode expr) {
243+
expr.(UnaryExprNode).getNode().getOp() instanceof Not and
244+
result = expr.(UnaryExprNode).getOperand()
245+
}
246+
247+
/** Holds if `test` is the test in a branch and `use` is that test
248+
* with all the `not` prefixes removed.
249+
*/
250+
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
251+
any(PyEdgeRefinement ref).getTest() = test and
252+
(
253+
use = test
254+
or
255+
exists(ControlFlowNode notuse |
256+
boolean_filter(test, notuse) and
257+
use = not_operand(notuse)
258+
)
259+
)
260+
}
261+
175262
TaintTrackingImplementation() { this instanceof TaintTracking::Configuration }
176263

177264
predicate flowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
178265
this.unprunedStep(src, node, context, path, kind) and
179-
node.getBasicBlock().likelyReachable()
266+
node.getBasicBlock().likelyReachable() and
267+
not this.(TaintTracking::Configuration).isBarrier(node) and
268+
not this.flowBarrier(node, kind) and path = TNoAttribute()
180269
}
181270

182271
predicate unprunedStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
183272
this.importStep(src, node, context, path, kind)
184273
or
185274
this.fromImportStep(src, node, context, path, kind)
186-
//or
187-
//this.attributeLoadStep(src, node, context, path, kind)
275+
or
276+
this.attributeLoadStep(src, node, context, path, kind)
188277
//or
189278
//this.getattrStep(src, node, context, path, kind)
190279
or
@@ -193,17 +282,19 @@ class TaintTrackingImplementation extends string {
193282
this.callTaintStep(src, node, context, path, kind)
194283
or
195284
this.returnFlowStep(src, node, context, path, kind)
196-
//or
197-
//this.iterationStep(src, node, context, path, kind)
285+
or
286+
this.iterationStep(src, node, context, path, kind)
198287
//or
199288
//this.yieldStep(src, node, context, path, kind)
200289
//or
201290
//this.subscriptStep(src, node, context, path, kind)
202-
//or
203-
//this.ifExprStep(src, node, context, path, kind)
291+
or
292+
this.ifExpStep(src, node, context, path, kind)
204293
or
205294
this.essaFlowStep(src, node, context, path, kind)
206295
or
296+
this.legacyExtensionStep(src, node, context, path, kind)
297+
or
207298
exists(DataFlow::Node srcnode, TaintKind srckind |
208299
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and
209300
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
@@ -217,9 +308,12 @@ class TaintTrackingImplementation extends string {
217308
)
218309
or
219310
exists(DataFlow::Node srcnode, TaintKind srckind |
220-
kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode()) and
221-
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
311+
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
222312
path.noAttribute()
313+
|
314+
kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode())
315+
or
316+
kind.isResultOfStep(srckind, srcnode.asCfgNode(), node.asCfgNode())
223317
)
224318
}
225319

@@ -239,9 +333,15 @@ class TaintTrackingImplementation extends string {
239333
predicate attributeLoadStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
240334
exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname |
241335
src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and
242-
node.asCfgNode() = srcnode.asCfgNode().(AttrNode).getObject(attrname) and
336+
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
243337
path = srcpath.fromAttribute(attrname)
244338
)
339+
or
340+
exists(DataFlow::Node srcnode, TaintKind srckind, string attrname |
341+
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
342+
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
343+
kind = srckind.getTaintOfAttribute(attrname)
344+
)
245345
}
246346

247347
pragma [noinline]
@@ -342,7 +442,7 @@ class TaintTrackingImplementation extends string {
342442
}
343443

344444
pragma [noinline]
345-
predicate ifExprStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
445+
predicate ifExpStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
346446
exists(DataFlow::Node srcnode |
347447
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
348448
srcnode.asCfgNode() = node.asCfgNode().(IfExprNode).getAnOperand()
@@ -354,6 +454,21 @@ class TaintTrackingImplementation extends string {
354454
this.taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind)
355455
}
356456

457+
pragma [noinline]
458+
predicate legacyExtensionStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
459+
exists(TaintTracking::Extension extension, DataFlow::Node srcnode, TaintKind srckind |
460+
this.(TaintTracking::Configuration).isExtension(extension) and
461+
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
462+
srcnode.asCfgNode() = extension
463+
|
464+
extension.getASuccessorNode() = node.asCfgNode() and kind = srckind
465+
or
466+
extension.getASuccessorNode(srckind, kind) = node.asCfgNode()
467+
or
468+
extension.getASuccessorVariable() = node.asVariable() and kind = srckind
469+
)
470+
}
471+
357472
pragma [noinline]
358473
predicate taintedDefinition(TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
359474
this.taintedPhi(src, defn, context, path, kind)
@@ -409,6 +524,12 @@ class TaintTrackingImplementation extends string {
409524
defn.getDefiningNode() = pyfunc.getParameter(arg) and
410525
context = TParamContext(kind, path, arg)
411526
)
527+
or
528+
/* Tainted parameter (usually user-defined) */
529+
exists(DataFlow::Node srcnode |
530+
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
531+
srcnode.asCfgNode() = defn.getDefiningNode()
532+
)
412533
}
413534

414535
pragma [noinline]
@@ -440,7 +561,7 @@ class TaintTrackingImplementation extends string {
440561
}
441562

442563
pragma [noinline]
443-
predicate taintedPiNode(TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
564+
predicate taintedPiNode(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
444565
exists(DataFlow::Node srcnode |
445566
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
446567
srcnode.asVariable() = defn.getInput() and

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ abstract class TaintKind extends string {
120120
*/
121121
TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { none() }
122122

123+
predicate isResultOfStep(TaintKind fromkind, ControlFlowNode fromnode, ControlFlowNode tonode) { none() }
124+
123125
/** DEPRECATED -- Use `TaintFlow.additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind)` instead.
124126
*
125127
* Holds if this kind of taint passes from variable `fromvar` to variable `tovar`
@@ -215,6 +217,8 @@ class SequenceKind extends CollectionKind {
215217
result = this.getItem() and
216218
result.getType() = ObjectInternal::builtin("str")
217219
)
220+
or
221+
result = this.getItem() and SequenceKind::itemFlowStep(fromnode, tonode)
218222
}
219223

220224
override TaintKind getTaintOfMethodResult(string name) {
@@ -229,6 +233,12 @@ class SequenceKind extends CollectionKind {
229233
result = itemKind
230234
}
231235

236+
override predicate isResultOfStep(TaintKind fromkind, ControlFlowNode fromnode, ControlFlowNode tonode) {
237+
SequenceKind::flowStep(fromnode, tonode) and this = fromkind
238+
or
239+
sequence_construct(fromnode, tonode) and this.getItem() = fromkind
240+
}
241+
232242
}
233243

234244

@@ -294,6 +304,12 @@ class DictKind extends CollectionKind {
294304
result = "dict of " + valueKind
295305
}
296306

307+
override predicate isResultOfStep(TaintKind fromkind, ControlFlowNode fromnode, ControlFlowNode tonode) {
308+
DictKind::flowStep(fromnode, tonode) and this = fromkind
309+
or
310+
dict_construct(fromnode, tonode) and this.getValue() = fromkind
311+
}
312+
297313
}
298314

299315

@@ -762,6 +778,9 @@ class TaintedPathSource extends TaintTrackingNode {
762778
this.getASuccessor*() = sink
763779
}
764780

781+
DataFlow::Node getSource() {
782+
result = this.getNode()
783+
}
765784

766785
}
767786

@@ -774,6 +793,7 @@ class TaintedPathSink extends TaintTrackingNode {
774793
DataFlow::Node getSink() {
775794
result = this.getNode()
776795
}
796+
777797
}
778798

779799
/** This module contains the implementation of taint-flow.
@@ -1680,7 +1700,17 @@ module DataFlow {
16801700
}
16811701

16821702
override string toString() {
1683-
result = this.asCfgNode().toString()
1703+
exists(ControlFlowNode n |
1704+
n = this.asCfgNode()
1705+
|
1706+
result = n.(TaintSource).toString()
1707+
or
1708+
result = n.(TaintSink).toString()
1709+
or
1710+
not n instanceof TaintSource and
1711+
not n instanceof TaintSink and
1712+
result = n.toString()
1713+
)
16841714
}
16851715

16861716
override Scope getScope() {

0 commit comments

Comments
 (0)