@@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow
88private import semmle.python.dataflow.new.RemoteFlowSources
99private import semmle.python.dataflow.new.TaintTracking
1010private import semmle.python.Concepts
11+ private import semmle.python.ApiGraphs
1112private import semmle.python.frameworks.PEP249
1213private import semmle.python.regex
1314
@@ -1975,6 +1976,50 @@ private module Django {
19751976 }
19761977 }
19771978
1979+ /** Provides models for django forms (defined in the `django.forms` module) */
1980+ module Forms {
1981+ /**
1982+ * Provides models for the `django.forms.Form` class and subclasses.
1983+ *
1984+ * See https://docs.djangoproject.com/en/3.1/ref/forms/api/
1985+ */
1986+ module Form {
1987+ /** Gets a reference to the `django.forms.Form` class or any subclass. */
1988+ API:: Node subclassRef ( ) {
1989+ result =
1990+ API:: moduleImport ( "django" )
1991+ .getMember ( "forms" )
1992+ .getMember ( [
1993+ "Form"
1994+ // TODO: Known subclasses
1995+ ] )
1996+ .getASubclass * ( )
1997+ }
1998+ }
1999+
2000+ /**
2001+ * Provides models for the `django.forms.Field` class and subclasses.
2002+ *
2003+ * See https://docs.djangoproject.com/en/3.1/ref/forms/fields/
2004+ */
2005+ module Field {
2006+ /** Gets a reference to the `django.forms.Form` class or any subclass. */
2007+ API:: Node subclassRef ( ) {
2008+ result =
2009+ API:: moduleImport ( "django" )
2010+ .getMember ( "forms" )
2011+ .getMember ( [
2012+ "Field"
2013+ // TODO: Known subclasses
2014+ ] )
2015+ .getASubclass * ( )
2016+ }
2017+ }
2018+ }
2019+
2020+ // ---------------------------------------------------------------------------
2021+ // Helpers
2022+ // ---------------------------------------------------------------------------
19782023 /**
19792024 * Gets the last decorator call for the function `func`, if `func` has decorators.
19802025 */
@@ -1983,6 +2028,97 @@ private module Django {
19832028 not exists ( Call other_decorator | other_decorator .getArg ( 0 ) = result )
19842029 }
19852030
2031+ /** Adds the `getASelfRef` member predicate when modeling a class. */
2032+ abstract private class SelfRefMixin extends Class {
2033+ /**
2034+ * Gets a reference to instances of this class, originating from a self parameter of
2035+ * a method defined on this class.
2036+ *
2037+ * Note: TODO: This doesn't take MRO into account
2038+ * Note: TODO: This doesn't take staticmethod/classmethod into account
2039+ */
2040+ private DataFlow:: Node getASelfRef ( DataFlow:: TypeTracker t ) {
2041+ t .start ( ) and
2042+ result .( DataFlow:: ParameterNode ) .getParameter ( ) = this .getAMethod ( ) .getArg ( 0 )
2043+ or
2044+ exists ( DataFlow:: TypeTracker t2 | result = this .getASelfRef ( t2 ) .track ( t2 , t ) )
2045+ }
2046+
2047+ /**
2048+ * Gets a reference to instances of this class, originating from a self parameter of
2049+ * a method defined on this class.
2050+ *
2051+ * Note: TODO: This doesn't take MRO into account
2052+ * Note: TODO: This doesn't take staticmethod/classmethod into account
2053+ */
2054+ DataFlow:: Node getASelfRef ( ) { result = this .getASelfRef ( DataFlow:: TypeTracker:: end ( ) ) }
2055+ }
2056+
2057+ // ---------------------------------------------------------------------------
2058+ // Form and form field modeling
2059+ // ---------------------------------------------------------------------------
2060+ /**
2061+ * A class that is a subclass of the `django.forms.Form` class,
2062+ * thereby handling user input.
2063+ */
2064+ class DjangoFormClass extends Class , SelfRefMixin {
2065+ DjangoFormClass ( ) { this .getABase ( ) = Django:: Forms:: Form:: subclassRef ( ) .getAUse ( ) .asExpr ( ) }
2066+ }
2067+
2068+ /**
2069+ * A source of cleaned_data (either the return value from `super().clean()`, or a reference to `self.cleaned_data`)
2070+ *
2071+ * See https://docs.djangoproject.com/en/3.1/ref/forms/validation/#form-and-field-validation
2072+ */
2073+ private class DjangoFormCleanedData extends RemoteFlowSource:: Range , DataFlow:: Node {
2074+ DjangoFormCleanedData ( ) {
2075+ exists ( DjangoFormClass cls , Function meth |
2076+ cls .getAMethod ( ) = meth and
2077+ (
2078+ this = API:: builtin ( "super" ) .getReturn ( ) .getMember ( "clean" ) .getACall ( ) and
2079+ this .getScope ( ) = meth
2080+ or
2081+ this .( DataFlow:: AttrRead ) .getAttributeName ( ) = "cleaned_data" and
2082+ this .( DataFlow:: AttrRead ) .getObject ( ) = cls .getASelfRef ( )
2083+ )
2084+ )
2085+ }
2086+
2087+ override string getSourceType ( ) {
2088+ result = "django.forms.Field subclass, value parameter in method"
2089+ }
2090+ }
2091+
2092+ /**
2093+ * A class that is a subclass of the `django.forms.Field` class,
2094+ * thereby handling user input.
2095+ */
2096+ class DjangoFormFieldClass extends Class {
2097+ DjangoFormFieldClass ( ) {
2098+ this .getABase ( ) = Django:: Forms:: Field:: subclassRef ( ) .getAUse ( ) .asExpr ( )
2099+ // api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent()
2100+ }
2101+ }
2102+
2103+ /**
2104+ * A parameter in a method on a `DjangoFormFieldClass` that receives the user-supplied value for this field.
2105+ *
2106+ * See https://docs.djangoproject.com/en/3.1/ref/forms/validation/#form-and-field-validation
2107+ */
2108+ private class DjangoFormFieldValueParam extends RemoteFlowSource:: Range , DataFlow:: ParameterNode {
2109+ DjangoFormFieldValueParam ( ) {
2110+ exists ( DjangoFormFieldClass cls , Function meth |
2111+ cls .getAMethod ( ) = meth and
2112+ meth .getName ( ) in [ "to_python" , "validate" , "run_validators" , "clean" ] and
2113+ this .getParameter ( ) = meth .getArg ( 1 )
2114+ )
2115+ }
2116+
2117+ override string getSourceType ( ) {
2118+ result = "django.forms.Field subclass, value parameter in method"
2119+ }
2120+ }
2121+
19862122 // ---------------------------------------------------------------------------
19872123 // routing modeling
19882124 // ---------------------------------------------------------------------------
@@ -2068,7 +2204,7 @@ private module Django {
20682204 }
20692205
20702206 /** A class that we consider a django View class. */
2071- abstract class DjangoViewClass extends DjangoViewClassHelper {
2207+ abstract class DjangoViewClass extends DjangoViewClassHelper , SelfRefMixin {
20722208 /** Gets a function that could handle incoming requests, if any. */
20732209 Function getARequestHandler ( ) {
20742210 // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
@@ -2080,29 +2216,6 @@ private module Django {
20802216 result .getName ( ) = "get_redirect_url"
20812217 )
20822218 }
2083-
2084- /**
2085- * Gets a reference to instances of this class, originating from a self parameter of
2086- * a method defined on this class.
2087- *
2088- * Note: TODO: This doesn't take MRO into account
2089- * Note: TODO: This doesn't take staticmethod/classmethod into account
2090- */
2091- private DataFlow:: Node getASelfRef ( DataFlow:: TypeTracker t ) {
2092- t .start ( ) and
2093- result .( DataFlow:: ParameterNode ) .getParameter ( ) = this .getAMethod ( ) .getArg ( 0 )
2094- or
2095- exists ( DataFlow:: TypeTracker t2 | result = this .getASelfRef ( t2 ) .track ( t2 , t ) )
2096- }
2097-
2098- /**
2099- * Gets a reference to instances of this class, originating from a self parameter of
2100- * a method defined on this class.
2101- *
2102- * Note: TODO: This doesn't take MRO into account
2103- * Note: TODO: This doesn't take staticmethod/classmethod into account
2104- */
2105- DataFlow:: Node getASelfRef ( ) { result = this .getASelfRef ( DataFlow:: TypeTracker:: end ( ) ) }
21062219 }
21072220
21082221 /**
0 commit comments