@@ -8,4 +8,178 @@ private import semmle.python.dataflow.new.DataFlow
8
8
private import semmle.python.dataflow.new.RemoteFlowSources
9
9
private import semmle.python.Concepts
10
10
private import semmle.python.ApiGraphs
11
- import semmle.python.frameworks.internal.PEP249Impl
11
+
12
+ /**
13
+ * Provides classes modeling database interfaces following PEP 249.
14
+ * See https://www.python.org/dev/peps/pep-0249/.
15
+ */
16
+ module PEP249 {
17
+ /**
18
+ * An API graph node representing a module that implements PEP 249.
19
+ */
20
+ abstract class PEP249ModuleApiNode extends API:: Node {
21
+ /** Gets a string representation of this element. */
22
+ override string toString ( ) { result = this .( API:: Node ) .toString ( ) }
23
+ }
24
+
25
+ /** Gets a reference to the `connect` function of a module that implements PEP 249. */
26
+ DataFlow:: Node connect ( ) {
27
+ result = any ( PEP249ModuleApiNode a ) .getMember ( "connect" ) .getAValueReachableFromSource ( )
28
+ }
29
+
30
+ /**
31
+ * Provides models for database connections (following PEP 249).
32
+ *
33
+ * See https://www.python.org/dev/peps/pep-0249/#connection-objects.
34
+ */
35
+ module Connection {
36
+ /**
37
+ * A source of database connections (following PEP 249), extend this class to model new instances.
38
+ *
39
+ * This can include instantiations of the class, return values from function
40
+ * calls, or a special parameter that will be set when functions are called by external
41
+ * libraries.
42
+ *
43
+ * Use the predicate `Connection::instance()` to get references to database connections (following PEP 249).
44
+ *
45
+ * Extend this class if the module implementing PEP 249 offers more direct ways to obtain
46
+ * a connection than going through `connect`.
47
+ */
48
+ abstract class InstanceSource extends DataFlow:: Node { }
49
+
50
+ /** A call to the `connect` function of a module that implements PEP 249. */
51
+ private class ConnectCall extends InstanceSource , DataFlow:: CallCfgNode {
52
+ ConnectCall ( ) { this .getFunction ( ) = connect ( ) }
53
+ }
54
+
55
+ /** Gets a reference to a database connection (following PEP 249). */
56
+ private DataFlow:: TypeTrackingNode instance ( DataFlow:: TypeTracker t ) {
57
+ t .start ( ) and
58
+ result instanceof InstanceSource
59
+ or
60
+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
61
+ }
62
+
63
+ /** Gets a reference to a database connection (following PEP 249). */
64
+ DataFlow:: Node instance ( ) { instance ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
65
+ }
66
+
67
+ /**
68
+ * Provides models for database cursors (following PEP 249).
69
+ *
70
+ * These are returned by the `cursor` method on a database connection.
71
+ * See https://www.python.org/dev/peps/pep-0249/#cursor.
72
+ */
73
+ module Cursor {
74
+ /**
75
+ * A source of database cursors (following PEP 249), extend this class to model new instances.
76
+ *
77
+ * This can include instantiations of the class, return values from function
78
+ * calls, or a special parameter that will be set when functions are called by external
79
+ * libraries.
80
+ *
81
+ * Use the predicate `Cursor::instance()` to get references to database cursors (following PEP 249).
82
+ *
83
+ * Extend this class if the module implementing PEP 249 offers more direct ways to obtain
84
+ * a connection than going through `connect`.
85
+ */
86
+ abstract class InstanceSource extends DataFlow:: LocalSourceNode { }
87
+
88
+ /** Gets a reference to a database cursor. */
89
+ private DataFlow:: TypeTrackingNode instance ( DataFlow:: TypeTracker t ) {
90
+ t .start ( ) and
91
+ result instanceof InstanceSource
92
+ or
93
+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
94
+ }
95
+
96
+ /** Gets a reference to a database cursor. */
97
+ DataFlow:: Node instance ( ) { instance ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
98
+
99
+ /** Gets a reference to the `cursor` method on a database connection. */
100
+ private DataFlow:: TypeTrackingNode methodRef ( DataFlow:: TypeTracker t ) {
101
+ t .startInAttr ( "cursor" ) and
102
+ result = Connection:: instance ( )
103
+ or
104
+ exists ( DataFlow:: TypeTracker t2 | result = methodRef ( t2 ) .track ( t2 , t ) )
105
+ }
106
+
107
+ /** Gets a reference to the `cursor` method on a database connection. */
108
+ DataFlow:: Node methodRef ( ) { methodRef ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
109
+
110
+ /** A call to the `cursor` method on a database connection */
111
+ private class CursorCall extends InstanceSource , DataFlow:: CallCfgNode {
112
+ CursorCall ( ) { this .getFunction ( ) = methodRef ( ) }
113
+ }
114
+
115
+ /** Gets a reference to a result of calling the `cursor` method on a database connection. */
116
+ private DataFlow:: TypeTrackingNode methodResult ( DataFlow:: TypeTracker t ) {
117
+ t .start ( ) and
118
+ result .asCfgNode ( ) .( CallNode ) .getFunction ( ) = methodRef ( ) .asCfgNode ( )
119
+ or
120
+ exists ( DataFlow:: TypeTracker t2 | result = methodResult ( t2 ) .track ( t2 , t ) )
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Gets a reference to the `execute` method on a cursor (or on a connection).
126
+ *
127
+ * Note: while `execute` method on a connection is not part of PEP249, if it is used, we
128
+ * recognize it as an alias for constructing a cursor and calling `execute` on it.
129
+ *
130
+ * See https://peps.python.org/pep-0249/#execute.
131
+ */
132
+ private DataFlow:: TypeTrackingNode execute ( DataFlow:: TypeTracker t ) {
133
+ t .startInAttr ( "execute" ) and
134
+ result in [ Cursor:: instance ( ) , Connection:: instance ( ) ]
135
+ or
136
+ exists ( DataFlow:: TypeTracker t2 | result = execute ( t2 ) .track ( t2 , t ) )
137
+ }
138
+
139
+ /**
140
+ * Gets a reference to the `execute` method on a cursor (or on a connection).
141
+ *
142
+ * Note: while `execute` method on a connection is not part of PEP249, if it is used, we
143
+ * recognize it as an alias for constructing a cursor and calling `execute` on it.
144
+ *
145
+ * See https://peps.python.org/pep-0249/#execute.
146
+ */
147
+ DataFlow:: Node execute ( ) { execute ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
148
+
149
+ /**
150
+ * A call to the `execute` method on a cursor or a connection.
151
+ *
152
+ * See https://peps.python.org/pep-0249/#execute
153
+ *
154
+ * Note: While `execute` method on a connection is not part of PEP249, if it is used, we
155
+ * recognize it as an alias for constructing a cursor and calling `execute` on it.
156
+ */
157
+ private class ExecuteCall extends SqlExecution:: Range , DataFlow:: CallCfgNode {
158
+ ExecuteCall ( ) { this .getFunction ( ) = execute ( ) }
159
+
160
+ override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
161
+ }
162
+
163
+ private DataFlow:: TypeTrackingNode executemany ( DataFlow:: TypeTracker t ) {
164
+ t .startInAttr ( "executemany" ) and
165
+ result in [ Cursor:: instance ( ) , Connection:: instance ( ) ]
166
+ or
167
+ exists ( DataFlow:: TypeTracker t2 | result = executemany ( t2 ) .track ( t2 , t ) )
168
+ }
169
+
170
+ private DataFlow:: Node executemany ( ) { executemany ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
171
+
172
+ /**
173
+ * A call to the `executemany` method on a cursor or a connection.
174
+ *
175
+ * See https://peps.python.org/pep-0249/#executemany
176
+ *
177
+ * Note: While `executemany` method on a connection is not part of PEP249, if it is used, we
178
+ * recognize it as an alias for constructing a cursor and calling `executemany` on it.
179
+ */
180
+ private class ExecutemanyCall extends SqlExecution:: Range , DataFlow:: CallCfgNode {
181
+ ExecutemanyCall ( ) { this .getFunction ( ) = executemany ( ) }
182
+
183
+ override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
184
+ }
185
+ }
0 commit comments