@@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow
8
8
private import semmle.python.dataflow.new.RemoteFlowSources
9
9
private import semmle.python.dataflow.new.TaintTracking
10
10
private import semmle.python.Concepts
11
+ private import semmle.python.ApiGraphs
11
12
private import semmle.python.frameworks.PEP249
12
13
private import semmle.python.regex
13
14
@@ -1975,6 +1976,50 @@ private module Django {
1975
1976
}
1976
1977
}
1977
1978
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
+ // ---------------------------------------------------------------------------
1978
2023
/**
1979
2024
* Gets the last decorator call for the function `func`, if `func` has decorators.
1980
2025
*/
@@ -1983,6 +2028,97 @@ private module Django {
1983
2028
not exists ( Call other_decorator | other_decorator .getArg ( 0 ) = result )
1984
2029
}
1985
2030
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
+
1986
2122
// ---------------------------------------------------------------------------
1987
2123
// routing modeling
1988
2124
// ---------------------------------------------------------------------------
@@ -2068,7 +2204,7 @@ private module Django {
2068
2204
}
2069
2205
2070
2206
/** A class that we consider a django View class. */
2071
- abstract class DjangoViewClass extends DjangoViewClassHelper {
2207
+ abstract class DjangoViewClass extends DjangoViewClassHelper , SelfRefMixin {
2072
2208
/** Gets a function that could handle incoming requests, if any. */
2073
2209
Function getARequestHandler ( ) {
2074
2210
// 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 {
2080
2216
result .getName ( ) = "get_redirect_url"
2081
2217
)
2082
2218
}
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 ( ) ) }
2106
2219
}
2107
2220
2108
2221
/**
0 commit comments