Python: Model executemany on PEP-249 DB APIs

Note: I kept the modeling using the old approach with type-trackers
instead of `DataFlow::MethodCallNode`.

I would like a meta query for DCA to show sinks before doing this, so I
can be absolutely sure we don't loose out on any important sinks on
this... so will postpone this work to a small one-off task (added to my
todo list).
This commit is contained in:
Rasmus Wriedt Larsen
2022-10-10 14:14:29 +02:00
parent 669f4f38b9
commit dba42d6bb8
4 changed files with 29 additions and 1 deletions

View File

@@ -178,4 +178,27 @@ module PEP249 {
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
}
private DataFlow::TypeTrackingNode executemany(DataFlow::TypeTracker t) {
t.startInAttr("executemany") and
result in [Cursor::instance(), Connection::instance()]
or
exists(DataFlow::TypeTracker t2 | result = executemany(t2).track(t2, t))
}
private DataFlow::Node executemany() { executemany(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
* A call to the `executemany` method on a cursor or a connection.
*
* See https://peps.python.org/pep-0249/#executemany
*
* Note: While `executemany` method on a connection is not part of PEP249, if it is used, we
* recognize it as an alias for constructing a cursor and calling `executemany` on it.
*/
private class ExecutemanyCall extends SqlExecution::Range, DataFlow::CallCfgNode {
ExecutemanyCall() { this.getFunction() = executemany() }
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
}
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added model of `executemany` calls on PEP-249 compliant Database APIs, resulting in additional sinks for `py/sql-injection`.

View File

@@ -3,4 +3,4 @@ connection = pymssql.connect(host="localhost", user="user", password="passwd")
cursor = connection.cursor()
cursor.execute("some sql", (42,)) # $ getSql="some sql"
cursor.executemany("some sql", [(42,)]) # $ MISSING: getSql="some sql"
cursor.executemany("some sql", [(42,)]) # $ getSql="some sql"

View File

@@ -3,3 +3,4 @@ connection = pymysql.connect(host="localhost", user="user", password="passwd")
cursor = connection.cursor()
cursor.execute("some sql", (42,)) # $ getSql="some sql"
cursor.executemany("some sql", [(42,)]) # $ getSql="some sql"