@@ -2,6 +2,7 @@ import python
22import semmle.python.security.TaintTracking
33private import semmle.python.objects.ObjectInternal
44private import semmle.python.pointsto.Filters as Filters
5+ private import semmle.python.dataflow.Presentation
56
67newtype TTaintTrackingContext =
78 TNoParam ( )
@@ -175,24 +176,6 @@ class TaintTrackingNode extends TTaintTrackingNode {
175176 result = this .getNode ( ) .getLocation ( )
176177 }
177178
178- TaintTrackingNode getASuccessor ( ) {
179- result = this .getASuccessor ( _)
180- }
181-
182- TaintTrackingNode getASuccessor ( string edgeLabel ) {
183- this .isVisible ( ) and
184- result = this .getAnUnlabeledSuccessor * ( ) .getALabeledSuccessor ( edgeLabel )
185- }
186-
187- private TaintTrackingNode getAnUnlabeledSuccessor ( ) {
188- this .getConfiguration ( ) .( TaintTrackingImplementation ) .flowStep ( this , result , "" )
189- }
190-
191- private TaintTrackingNode getALabeledSuccessor ( string label ) {
192- not label = "" and
193- this .getConfiguration ( ) .( TaintTrackingImplementation ) .flowStep ( this , result , label )
194- }
195-
196179 predicate isSource ( ) {
197180 this .getConfiguration ( ) .( TaintTrackingImplementation ) .isPathSource ( this )
198181 }
@@ -210,13 +193,21 @@ class TaintTrackingNode extends TTaintTrackingNode {
210193 result = this .getCfgNode ( ) .getNode ( )
211194 }
212195
213- /** Holds if this node should be presented to the user as part of a path */
214- predicate isVisible ( ) {
215- this .isSource ( ) or
216- exists ( string label |
217- not label = "" |
218- this .getConfiguration ( ) .( TaintTrackingImplementation ) .flowStep ( _, this , label )
219- )
196+ TaintTrackingNode getASuccessor ( string edgeLabel ) {
197+ result = this .unlabeledSuccessor * ( ) .labeledSuccessor ( edgeLabel )
198+ }
199+
200+ TaintTrackingNode getASuccessor ( ) {
201+ result = this .getASuccessor ( _)
202+ }
203+
204+ private TaintTrackingNode unlabeledSuccessor ( ) {
205+ this .getConfiguration ( ) .( TaintTrackingImplementation ) .flowStep ( this , result , "" )
206+ }
207+
208+ private TaintTrackingNode labeledSuccessor ( string label ) {
209+ not label = "" and
210+ this .getConfiguration ( ) .( TaintTrackingImplementation ) .flowStep ( this , result , label )
220211 }
221212
222213}
@@ -231,7 +222,7 @@ class TaintTrackingImplementation extends string {
231222 predicate hasFlowPath ( TaintTrackingNode source , TaintTrackingNode sink ) {
232223 this .isPathSource ( source ) and
233224 this .isPathSink ( sink ) and
234- sink = source . getASuccessor * ( )
225+ this . flowReaches ( source , sink )
235226 }
236227
237228 predicate flowSource ( DataFlow:: Node node , TaintTrackingContext context , AttributePath path , TaintKind kind ) {
@@ -282,6 +273,15 @@ class TaintTrackingImplementation extends string {
282273 )
283274 }
284275
276+ predicate flowReaches ( TaintTrackingNode src , TaintTrackingNode dest ) {
277+ this = src .getConfiguration ( ) and dest = src
278+ or
279+ exists ( TaintTrackingNode mid |
280+ this .flowReaches ( src , mid ) and
281+ this .flowStep ( mid , dest , _)
282+ )
283+ }
284+
285285 predicate flowBarrier ( DataFlow:: Node node , TaintKind kind ) {
286286 this .( TaintTracking:: Configuration ) .isBarrier ( node , kind )
287287 or
@@ -397,6 +397,8 @@ class TaintTrackingImplementation extends string {
397397 or
398398 this .returnFlowStep ( src , node , context , path , kind , edgeLabel )
399399 or
400+ this .callFlowStep ( src , node , context , path , kind , edgeLabel )
401+ or
400402 this .iterationStep ( src , node , context , path , kind , edgeLabel )
401403 or
402404 this .yieldStep ( src , node , context , path , kind , edgeLabel )
@@ -508,27 +510,39 @@ class TaintTrackingImplementation extends string {
508510 // // TO DO... named parameters
509511 //}
510512
513+ /* If the return value is tainted without context, then it always flows back to the caller */
511514 pragma [ noinline]
512515 predicate returnFlowStep ( TaintTrackingNode src , DataFlow:: Node node , TaintTrackingContext context , AttributePath path , TaintKind kind , string edgeLabel ) {
513- exists ( CallNode call , PythonFunctionObjectInternal pyfunc , TaintTrackingContext callee , DataFlow:: Node retval |
514- this .callContexts ( call , pyfunc , context , callee ) and
515- src = TTaintTrackingNode_ ( retval , callee , path , kind , this ) and
516+ exists ( CallNode call , PythonFunctionObjectInternal pyfunc , DataFlow:: Node retval |
517+ pyfunc .getACall ( ) = call and
518+ context = TNoParam ( ) and
519+ src = TTaintTrackingNode_ ( retval , TNoParam ( ) , path , kind , this ) and
516520 node .asCfgNode ( ) = call and
517521 retval .asCfgNode ( ) = any ( Return ret | ret .getScope ( ) = pyfunc .getScope ( ) ) .getValue ( ) .getAFlowNode ( )
518522 ) and
519523 edgeLabel = "return"
520524 }
521525
526+ /* Avoid taint flow from return value to caller as it can produce imprecise flow graphs
527+ * Step directly from tainted argument to call result.
528+ */
522529 pragma [ noinline]
523- predicate callContexts ( CallNode call , PythonFunctionObjectInternal pyfunc , TaintTrackingContext caller , TaintTrackingContext callee ) {
530+ predicate callFlowStep ( TaintTrackingNode src , DataFlow:: Node node , TaintTrackingContext context , AttributePath path , TaintKind kind , string edgeLabel ) {
531+ exists ( CallNode call , PythonFunctionObjectInternal pyfunc , TaintTrackingContext callee , DataFlow:: Node retval , TaintTrackingNode retnode |
532+ this .callContexts ( call , src , pyfunc , context , callee ) and
533+ retnode = TTaintTrackingNode_ ( retval , callee , path , kind , this ) and
534+ node .asCfgNode ( ) = call and
535+ retval .asCfgNode ( ) = any ( Return ret | ret .getScope ( ) = pyfunc .getScope ( ) ) .getValue ( ) .getAFlowNode ( )
536+ ) and
537+ edgeLabel = "call"
538+ }
539+
540+ pragma [ noinline]
541+ predicate callContexts ( CallNode call , TaintTrackingNode argnode , PythonFunctionObjectInternal pyfunc , TaintTrackingContext caller , TaintTrackingContext callee ) {
524542 exists ( int arg , TaintKind callerKind , AttributePath callerPath |
525- this .callWithTaintedArgument ( _ , call , caller , pyfunc , arg , callerPath , callerKind ) and
543+ this .callWithTaintedArgument ( argnode , call , caller , pyfunc , arg , callerPath , callerKind ) and
526544 callee = TParamContext ( callerKind , callerPath , arg )
527545 )
528- or
529- pyfunc .getACall ( ) = call and
530- callee = TNoParam ( ) and
531- caller = TNoParam ( )
532546 }
533547
534548 predicate callWithTaintedArgument ( TaintTrackingNode src , CallNode call , TaintTrackingContext caller , CallableValue pyfunc , int arg , AttributePath path , TaintKind kind ) {
@@ -633,6 +647,8 @@ class TaintTrackingImplementation extends string {
633647 this .taintedArgument ( src , defn , context , path , kind )
634648 or
635649 this .taintedExceptionCapture ( src , defn , context , path , kind )
650+ or
651+ this .taintedScopeEntryDefinition ( src , defn , context , path , kind )
636652 }
637653
638654 pragma [ noinline]
@@ -729,6 +745,14 @@ class TaintTrackingImplementation extends string {
729745 )
730746 }
731747
748+ pragma [ noinline]
749+ predicate taintedScopeEntryDefinition ( TaintTrackingNode src , ScopeEntryDefinition defn , TaintTrackingContext context , AttributePath path , TaintKind kind ) {
750+ exists ( EssaVariable var |
751+ BaseFlow:: scope_entry_value_transfer_from_earlier ( var , _, defn , _) and
752+ this .taintedDefinition ( src , var .getDefinition ( ) , context , path , kind )
753+ )
754+ }
755+
732756 predicate moduleAttributeTainted ( ModuleValue m , string name , TaintTrackingNode taint ) {
733757 exists ( DataFlow:: Node srcnode , EssaVariable var |
734758 taint = TTaintTrackingNode_ ( srcnode , TNoParam ( ) , _, _, this ) and
@@ -769,6 +793,12 @@ class TaintTrackingImplementation extends string {
769793 )
770794 }
771795
796+ predicate crossCallFlow ( TaintTrackingNode taintedArg , TaintTrackingNode call ) {
797+ this .parameterStep ( taintedArg , _, _, _, _, _) and
798+ this .flowReaches ( taintedArg , call ) and
799+ call .getNode ( ) .asCfgNode ( ) .( CallNode ) .getArg ( _) = taintedArg .getNode ( ) .asCfgNode ( )
800+ }
801+
772802}
773803
774804/* Backwards compatibility with config-less taint-tracking */
0 commit comments