Python: Add modeling of peewee

This commit is contained in:
Rasmus Wriedt Larsen
2021-06-25 17:50:59 +02:00
parent 1317ae298c
commit 97571e0b4f
5 changed files with 200 additions and 4 deletions

View File

@@ -174,6 +174,7 @@ Python built-in support
MySQL-python, Database
psycopg2, Database
sqlite3, Database
peewee, Database ORM
cryptography, Cryptography library
pycryptodome, Cryptography library
pycryptodomex, Cryptography library

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* Added modeling of raw SQL execution from the PyPI package `peewee`.

View File

@@ -25,6 +25,7 @@ private import semmle.python.frameworks.Rsa
private import semmle.python.frameworks.Simplejson
private import semmle.python.frameworks.Stdlib
private import semmle.python.frameworks.Tornado
private import semmle.python.frameworks.Peewee
private import semmle.python.frameworks.Twisted
private import semmle.python.frameworks.Ujson
private import semmle.python.frameworks.Yaml

View File

@@ -0,0 +1,192 @@
/**
* Provides classes modeling security-relevant aspects of the `peewee` PyPI package.
* See
* - https://pypi.org/project/peewee/
* - https://docs.peewee-orm.com/en/latest/index.html
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.PEP249
/**
* Provides models for the `peewee` PyPI package.
* See
* - https://pypi.org/project/peewee/
* - https://docs.peewee-orm.com/en/latest/index.html
*/
private module Peewee {
/** Provides models for the `peewee.Database` class and subclasses. */
module Database {
/** Gets a reference to the `peewee.Database` class or any subclass. */
API::Node subclassRef() {
result = API::moduleImport("peewee").getMember("Database").getASubclass*()
or
// known subclasses
result =
API::moduleImport("peewee")
.getMember(["SqliteDatabase", "MySQLDatabase", "PostgresqlDatabase"])
.getASubclass*()
or
// Ohter known subclasses, semi auto generated by using
// ```codeql
// class DBClass extends Class, SelfRefMixin {
// DBClass() {
// exists(this.getLocation().getFile().getRelativePath()) and
// this.getName().matches("%Database") and
// this.getABase().(Name).getId().matches("%Database")
// }
// }
//
// from DBClass dbClass, Module mod
// where
// dbClass.getScope() = mod
// select mod.getName()+ "." + dbClass.getName()
// ```
result =
API::moduleImport("playhouse")
.getMember("apsw_ext")
.getMember("APSWDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("cockroachdb")
.getMember("CockroachDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("cockroachdb")
.getMember("PooledCockroachDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("mysql_ext")
.getMember("MySQLConnectorDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("PooledCSqliteExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("PooledMySQLDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("PooledPostgresqlDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("PooledPostgresqlExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("PooledSqliteDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("PooledSqliteExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("_PooledPostgresqlDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("pool")
.getMember("_PooledSqliteDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("postgres_ext")
.getMember("PostgresqlExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("sqlcipher_ext")
.getMember("SqlCipherDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("sqlcipher_ext")
.getMember("SqlCipherExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("sqlite_ext")
.getMember("CSqliteExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("sqlite_ext")
.getMember("SqliteExtDatabase")
.getASubclass*()
or
result =
API::moduleImport("playhouse")
.getMember("sqliteq")
.getMember("SqliteQueueDatabase")
.getASubclass*()
}
/** Gets a reference to an instance of `peewee.Database` or any subclass. */
API::Node instance() { result = subclassRef().getReturn() }
}
/**
* A call to the `connection` method on a `peewee.Database` instance.
* https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.connection.
*/
class PeeweeDatabaseConnectionCall extends PEP249::Connection::InstanceSource,
DataFlow::CallCfgNode {
PeeweeDatabaseConnectionCall() {
this = Database::instance().getMember("connection").getACall()
}
}
/**
* A call to the `cursor` method on a `peewee.Database` instance.
* https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.cursor.
*/
class PeeweeDatabaseCursorCall extends PEP249::Cursor::InstanceSource, DataFlow::CallCfgNode {
PeeweeDatabaseCursorCall() { this = Database::instance().getMember("cursor").getACall() }
}
/**
* A call to the `execute_sql` method on a `peewee.Database` instance.
* See https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.execute_sql.
*/
class PeeweeDatabaseExecuteSqlCall extends SqlExecution::Range, DataFlow::CallCfgNode {
PeeweeDatabaseExecuteSqlCall() {
this = Database::instance().getMember("execute_sql").getACall()
}
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
}
}

View File

@@ -7,13 +7,13 @@ db = peewee.MySQLDatabase()
conn = db.connection()
cursor = conn.cursor()
cursor.execute("sql") # $ MISSING: getSql="sql"
cursor.execute("sql") # $ getSql="sql"
cursor = db.cursor()
cursor.execute("sql") # $ MISSING: getSql="sql"
cursor.execute("sql") # $ getSql="sql"
db.execute_sql("sql") # $ MISSING: getSql="sql"
db.execute_sql("sql") # $ getSql="sql"
# Pool extension
pool = playhouse.pool.PooledMySQLDatabase(...)
pool.execute_sql("sql") # $ MISSING: getSql="sql"
pool.execute_sql("sql") # $ getSql="sql"