11import python
22import semmle.python.security.TaintTracking
33private import semmle.python.objects.ObjectInternal
4+ private import semmle.python.pointsto.Filters as Filters
45
56newtype TTaintTrackingContext =
67 TNoParam ( )
@@ -85,21 +86,14 @@ class NoAttribute extends TNoAttribute, AttributePath {
8586
8687newtype 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
10094class 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
0 commit comments