@@ -7,91 +7,42 @@ private import python
77private import semmle.python.dataflow.new.DataFlow
88private import semmle.python.Concepts
99private import semmle.python.ApiGraphs
10+ private import semmle.python.frameworks.data.ModelsAsData
1011
1112/** Provides models for the `asyncpg` PyPI package. */
1213private module Asyncpg {
13- private import semmle.python.internal.Awaited
14-
15- /** Gets a `ConnectionPool` that is created when the result of `asyncpg.create_pool()` is awaited. */
16- API:: Node connectionPool ( ) {
17- result = API:: moduleImport ( "asyncpg" ) .getMember ( "create_pool" ) .getReturn ( ) .getAwaited ( )
18- }
19-
20- /**
21- * Gets a `Connection` that is created when
22- * - the result of `asyncpg.connect()` is awaited.
23- * - the result of calling `acquire` on a `ConnectionPool` is awaited.
24- */
25- API:: Node connection ( ) {
26- result = API:: moduleImport ( "asyncpg" ) .getMember ( "connect" ) .getReturn ( ) .getAwaited ( )
27- or
28- result = connectionPool ( ) .getMember ( "acquire" ) .getReturn ( ) .getAwaited ( )
29- }
30-
31- /** `Connection`s and `ConnectionPool`s provide some methods that execute SQL. */
32- class SqlExecutionOnConnection extends SqlExecution:: Range , DataFlow:: MethodCallNode {
33- string methodName ;
34-
35- SqlExecutionOnConnection ( ) {
36- this = [ connectionPool ( ) , connection ( ) ] .getMember ( methodName ) .getACall ( ) and
37- methodName in [ "copy_from_query" , "execute" , "fetch" , "fetchrow" , "fetchval" , "executemany" ]
38- }
39-
40- override DataFlow:: Node getSql ( ) {
41- methodName in [ "copy_from_query" , "execute" , "fetch" , "fetchrow" , "fetchval" ] and
42- result in [ this .getArg ( 0 ) , this .getArgByName ( "query" ) ]
43- or
44- methodName = "executemany" and
45- result in [ this .getArg ( 0 ) , this .getArgByName ( "command" ) ]
46- }
47- }
48-
49- /** A model of `Connection` and `ConnectionPool`, which provide some methods that access the file system. */
50- class FileAccessOnConnection extends FileSystemAccess:: Range , DataFlow:: MethodCallNode {
51- string methodName ;
52-
53- FileAccessOnConnection ( ) {
54- this = [ connectionPool ( ) , connection ( ) ] .getMember ( methodName ) .getACall ( ) and
55- methodName in [ "copy_from_query" , "copy_from_table" , "copy_to_table" ]
56- }
57-
58- // The path argument is keyword only.
59- override DataFlow:: Node getAPathArgument ( ) {
60- methodName in [ "copy_from_query" , "copy_from_table" ] and
61- result = this .getArgByName ( "output" )
62- or
63- methodName = "copy_to_table" and
64- result = this .getArgByName ( "source" )
14+ class AsyncpgModel extends ModelInput:: TypeModelCsv {
15+ override predicate row ( string row ) {
16+ // package1;type1;package2;type2;path
17+ row =
18+ [
19+ // a `ConnectionPool` that is created when the result of `asyncpg.create_pool()` is awaited.
20+ "asyncpg;ConnectionPool;asyncpg;;Member[create_pool].ReturnValue.Awaited" ,
21+ // a `Connection` that is created when
22+ // * - the result of `asyncpg.connect()` is awaited.
23+ // * - the result of calling `acquire` on a `ConnectionPool` is awaited.
24+ "asyncpg;Connection;asyncpg;;Member[connect].ReturnValue.Awaited" ,
25+ "asyncpg;Connection;asyncpg;ConnectionPool;Member[acquire].ReturnValue.Awaited" ,
26+ // Creating an internal `~Connection` type that contains both `Connection` and `ConnectionPool`.
27+ "asyncpg;~Connection;asyncpg;Connection;" , "asyncpg;~Connection;asyncpg;ConnectionPool;"
28+ ]
6529 }
6630 }
6731
68- /**
69- * Provides models of the `PreparedStatement` class in `asyncpg`.
70- * `PreparedStatement`s are created when the result of calling `prepare(query)` on a connection is awaited.
71- * The result of calling `prepare(query)` is a `PreparedStatementFactory` and the argument, `query` needs to
72- * be tracked to the place where a `PreparedStatement` is created and then further to any executing methods.
73- * Hence the two type trackers.
74- */
75- module PreparedStatement {
76- class PreparedStatementConstruction extends SqlConstruction:: Range , API:: CallNode {
77- PreparedStatementConstruction ( ) { this = connection ( ) .getMember ( "prepare" ) .getACall ( ) }
78-
79- override DataFlow:: Node getSql ( ) { result = this .getParameter ( 0 , "query" ) .getARhs ( ) }
80- }
81-
82- class PreparedStatementExecution extends SqlExecution:: Range , API:: CallNode {
83- PreparedStatementConstruction prepareCall ;
84-
85- PreparedStatementExecution ( ) {
86- this =
87- prepareCall
88- .getReturn ( )
89- .getAwaited ( )
90- .getMember ( [ "executemany" , "fetch" , "fetchrow" , "fetchval" ] )
91- .getACall ( )
92- }
93-
94- override DataFlow:: Node getSql ( ) { result = prepareCall .getSql ( ) }
32+ class AsyncpgSink extends ModelInput:: SinkModelCsv {
33+ // package;type;path;kind
34+ override predicate row ( string row ) {
35+ row =
36+ [
37+ // `Connection`s and `ConnectionPool`s provide some methods that execute SQL.
38+ "asyncpg;~Connection;Member[copy_from_query,execute,fetch,fetchrow,fetchval].Argument[0,query:];sql-injection" ,
39+ "asyncpg;~Connection;Member[executemany].Argument[0,command:];sql-injection" ,
40+ // A model of `Connection` and `ConnectionPool`, which provide some methods that access the file system.
41+ "asyncpg;~Connection;Member[copy_from_query,copy_from_table].Argument[output:];path-injection" ,
42+ "asyncpg;~Connection;Member[copy_to_table].Argument[source:];path-injection" ,
43+ // the `PreparedStatement` class in `asyncpg`.
44+ "asyncpg;Connection;Member[prepare].Argument[0,query:];sql-injection" ,
45+ ]
9546 }
9647 }
9748
@@ -106,7 +57,9 @@ private module Asyncpg {
10657 */
10758 module Cursor {
10859 class CursorConstruction extends SqlConstruction:: Range , API:: CallNode {
109- CursorConstruction ( ) { this = connection ( ) .getMember ( "cursor" ) .getACall ( ) }
60+ CursorConstruction ( ) {
61+ this = ModelOutput:: getATypeNode ( "asyncpg" , "Connection" ) .getMember ( "cursor" ) .getACall ( )
62+ }
11063
11164 override DataFlow:: Node getSql ( ) { result = this .getParameter ( 0 , "query" ) .getARhs ( ) }
11265 }
@@ -121,8 +74,11 @@ private module Asyncpg {
12174 this = c .getReturn ( ) .getAwaited ( ) .getAnImmediateUse ( )
12275 )
12376 or
124- exists ( PreparedStatement:: PreparedStatementConstruction prepareCall |
125- sql = prepareCall .getSql ( ) and
77+ exists ( API:: CallNode prepareCall |
78+ prepareCall =
79+ ModelOutput:: getATypeNode ( "asyncpg" , "Connection" ) .getMember ( "prepare" ) .getACall ( )
80+ |
81+ sql = prepareCall .getParameter ( 0 , "query" ) .getARhs ( ) and
12682 this =
12783 prepareCall
12884 .getReturn ( )
0 commit comments