@@ -8,4 +8,178 @@ private import semmle.python.dataflow.new.DataFlow
88private import semmle.python.dataflow.new.RemoteFlowSources
99private import semmle.python.Concepts
1010private 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