@@ -14,6 +14,7 @@ private import semmle.python.frameworks.Stdlib
1414private import semmle.python.regex
1515private import semmle.python.frameworks.internal.PoorMansFunctionResolution
1616private import semmle.python.frameworks.internal.SelfRefMixin
17+ private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
1718
1819/**
1920 * Provides models for the `django` PyPI package.
@@ -340,19 +341,30 @@ private module Django {
340341 /**
341342 * Taint propagation for `django.utils.datastructures.MultiValueDict`.
342343 */
344+ private class InstanceTaintSteps extends InstanceTaintStepsHelper {
345+ InstanceTaintSteps ( ) { this = "django.utils.datastructures.MultiValueDict" }
346+
347+ override DataFlow:: Node getInstance ( ) { result = instance ( ) }
348+
349+ override string getAttributeName ( ) { none ( ) }
350+
351+ override string getMethodName ( ) {
352+ result in [ "getlist" , "lists" , "popitem" , "dict" , "urlencode" ]
353+ }
354+
355+ override string getAsyncMethodName ( ) { none ( ) }
356+ }
357+
358+ /**
359+ * Extra taint propagation for `django.utils.datastructures.MultiValueDict`, not covered by `InstanceTaintSteps`.
360+ */
343361 private class AdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
344362 override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
345363 // class instantiation
346364 exists ( ClassInstantiation call |
347365 nodeFrom = call .getArg ( 0 ) and
348366 nodeTo = call
349367 )
350- or
351- // normal (non-async) methods
352- nodeFrom = instance ( ) and
353- nodeTo
354- .( DataFlow:: MethodCallNode )
355- .calls ( nodeFrom , [ "getlist" , "lists" , "popitem" , "dict" , "urlencode" ] )
356368 }
357369 }
358370 }
@@ -388,15 +400,20 @@ private module Django {
388400 /**
389401 * Taint propagation for `django.core.files.uploadedfile.UploadedFile`.
390402 */
391- private class AdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
392- override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
393- // Attributes
394- nodeFrom = instance ( ) and
395- nodeTo .( DataFlow:: AttrRead ) .getObject ( ) = nodeFrom and
396- nodeTo .( DataFlow:: AttrRead ) .getAttributeName ( ) in [
403+ private class InstanceTaintSteps extends InstanceTaintStepsHelper {
404+ InstanceTaintSteps ( ) { this = "django.core.files.uploadedfile.UploadedFile" }
405+
406+ override DataFlow:: Node getInstance ( ) { result = instance ( ) }
407+
408+ override string getAttributeName ( ) {
409+ result in [
397410 "content_type" , "content_type_extra" , "content_type_extra" , "charset" , "name" , "file"
398411 ]
399412 }
413+
414+ override string getMethodName ( ) { none ( ) }
415+
416+ override string getAsyncMethodName ( ) { none ( ) }
400417 }
401418
402419 /** A file-like object instance that originates from a `UploadedFile`. */
@@ -436,13 +453,16 @@ private module Django {
436453 /**
437454 * Taint propagation for `django.urls.ResolverMatch`.
438455 */
439- private class AdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
440- override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
441- // Attributes
442- nodeFrom = instance ( ) and
443- nodeTo .( DataFlow:: AttrRead ) .getObject ( ) = nodeFrom and
444- nodeTo .( DataFlow:: AttrRead ) .getAttributeName ( ) in [ "args" , "kwargs" ]
445- }
456+ private class InstanceTaintSteps extends InstanceTaintStepsHelper {
457+ InstanceTaintSteps ( ) { this = "django.urls.ResolverMatch" }
458+
459+ override DataFlow:: Node getInstance ( ) { result = instance ( ) }
460+
461+ override string getAttributeName ( ) { result in [ "args" , "kwargs" ] }
462+
463+ override string getMethodName ( ) { none ( ) }
464+
465+ override string getAsyncMethodName ( ) { none ( ) }
446466 }
447467 }
448468}
@@ -747,15 +767,43 @@ private module PrivateDjango {
747767 /**
748768 * Taint propagation for `django.http.request.HttpRequest`.
749769 */
770+ private class InstanceTaintSteps extends InstanceTaintStepsHelper {
771+ InstanceTaintSteps ( ) { this = "django.http.request.HttpRequest" }
772+
773+ override DataFlow:: Node getInstance ( ) { result = instance ( ) }
774+
775+ override string getAttributeName ( ) {
776+ result in [
777+ // str / bytes
778+ "body" , "path" , "path_info" , "method" , "encoding" , "content_type" ,
779+ // django.http.QueryDict
780+ "GET" , "POST" ,
781+ // dict[str, str]
782+ "content_params" , "COOKIES" ,
783+ // dict[str, Any]
784+ "META" ,
785+ // HttpHeaders (case insensitive dict-like)
786+ "headers" ,
787+ // MultiValueDict[str, UploadedFile]
788+ "FILES" ,
789+ // django.urls.ResolverMatch
790+ "resolver_match"
791+ ]
792+ // TODO: Handle that a HttpRequest is iterable
793+ }
794+
795+ override string getMethodName ( ) {
796+ result in [ "get_full_path" , "get_full_path_info" , "read" , "readline" , "readlines" ]
797+ }
798+
799+ override string getAsyncMethodName ( ) { none ( ) }
800+ }
801+
802+ /**
803+ * Extra taint propagation for `django.http.request.HttpRequest`, not covered by `InstanceTaintSteps`.
804+ */
750805 private class AdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
751806 override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
752- // normal (non-async) methods
753- nodeFrom = django:: http:: request:: HttpRequest:: instance ( ) and
754- nodeTo
755- .( DataFlow:: MethodCallNode )
756- .calls ( nodeFrom ,
757- [ "get_full_path" , "get_full_path_info" , "read" , "readline" , "readlines" ] )
758- or
759807 // special handling of the `build_absolute_uri` method, see
760808 // https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.build_absolute_uri
761809 exists ( DataFlow:: AttrRead attr , DataFlow:: CallCfgNode call , DataFlow:: Node instance |
@@ -775,27 +823,6 @@ private module PrivateDjango {
775823 nodeFrom = call .getArgByName ( "location" )
776824 )
777825 )
778- or
779- // Attributes
780- nodeFrom = django:: http:: request:: HttpRequest:: instance ( ) and
781- nodeTo .( DataFlow:: AttrRead ) .getObject ( ) = nodeFrom and
782- nodeTo .( DataFlow:: AttrRead ) .getAttributeName ( ) in [
783- // str / bytes
784- "body" , "path" , "path_info" , "method" , "encoding" , "content_type" ,
785- // django.http.QueryDict
786- "GET" , "POST" ,
787- // dict[str, str]
788- "content_params" , "COOKIES" ,
789- // dict[str, Any]
790- "META" ,
791- // HttpHeaders (case insensitive dict-like)
792- "headers" ,
793- // MultiValueDict[str, UploadedFile]
794- "FILES" ,
795- // django.urls.ResolverMatch
796- "resolver_match"
797- ]
798- // TODO: Handle that a HttpRequest is iterable
799826 }
800827 }
801828
0 commit comments