mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
C++: Make the new SQL abstract classes extend 'Function' instead. This is more in line with how we model RemoteFlowFunction.
This commit is contained in:
@@ -16,7 +16,6 @@ import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.security.FunctionWithWrappers
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
import semmle.code.cpp.security.Sql
|
||||
import TaintedWithPath
|
||||
|
||||
class SQLLikeFunction extends FunctionWithWrappers {
|
||||
@@ -35,10 +34,10 @@ class Configuration extends TaintTrackingConfiguration {
|
||||
or
|
||||
e.getUnspecifiedType() instanceof IntegralType
|
||||
or
|
||||
exists(SqlFunctionality sql, int arg, Function func, FunctionInput input |
|
||||
e = func.getACallToThisFunction().getArgument(arg) and
|
||||
exists(SqlBarrier sqlFunc, int arg, FunctionInput input |
|
||||
e = sqlFunc.getACallToThisFunction().getArgument(arg) and
|
||||
input.isParameterDeref(arg) and
|
||||
sql.getAnEscapedParameter(func, input, _)
|
||||
sqlFunc.getAnEscapedParameter(input, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,6 @@ private import implementations.Recv
|
||||
private import implementations.Accept
|
||||
private import implementations.Poll
|
||||
private import implementations.Select
|
||||
private import implementations.MySql
|
||||
private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
private class MySqlSink extends SqlSink {
|
||||
MySqlSink() { this.hasName(["mysql_query", "mysql_real_query"]) }
|
||||
|
||||
override predicate getAnSqlParameter(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
private predicate pqxxTransactionSqlArgument(string function, int arg) {
|
||||
function = "exec" and arg = 0
|
||||
or
|
||||
function = "exec0" and arg = 0
|
||||
or
|
||||
function = "exec1" and arg = 0
|
||||
or
|
||||
function = "exec_n" and arg = 1
|
||||
or
|
||||
function = "exec_params" and arg = 0
|
||||
or
|
||||
function = "exec_params0" and arg = 0
|
||||
or
|
||||
function = "exec_params1" and arg = 0
|
||||
or
|
||||
function = "exec_params_n" and arg = 1
|
||||
or
|
||||
function = "query_value" and arg = 0
|
||||
or
|
||||
function = "stream" and arg = 0
|
||||
}
|
||||
|
||||
private predicate pqxxConnectionSqlArgument(string function, int arg) {
|
||||
function = "prepare" and arg = 1
|
||||
}
|
||||
|
||||
private predicate pqxxTransationClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in [
|
||||
"dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction",
|
||||
"subtransaction", "transaction", "basic_transaction", "transaction_base", "work"
|
||||
]
|
||||
}
|
||||
|
||||
private predicate pqxxConnectionClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in ["connection_base", "basic_connection", "connection"]
|
||||
}
|
||||
|
||||
private predicate pqxxEscapeArgument(string function, int arg) {
|
||||
arg = 0 and
|
||||
function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"]
|
||||
}
|
||||
|
||||
private class PostgreSqlSink extends SqlSink {
|
||||
PostgreSqlSink() {
|
||||
exists(Class c |
|
||||
this.getDeclaringType() = c and
|
||||
// transaction exec and connection prepare variations
|
||||
(
|
||||
pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) and
|
||||
pqxxTransactionSqlArgument(this.getName(), _)
|
||||
or
|
||||
pqxxConnectionSqlArgument(this.getName(), _) and
|
||||
pqxxConnectionClassNames(c.getName(), c.getNamespace().getName())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate getAnSqlParameter(FunctionInput input) {
|
||||
exists(int argIndex |
|
||||
pqxxTransactionSqlArgument(this.getName(), argIndex)
|
||||
or
|
||||
pqxxConnectionSqlArgument(this.getName(), argIndex)
|
||||
|
|
||||
input.isParameterDeref(argIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class PostgreSqlBarrier extends SqlBarrier {
|
||||
PostgreSqlBarrier() {
|
||||
exists(Class c |
|
||||
this.getDeclaringType() = c and
|
||||
// transaction and connection escape functions
|
||||
(
|
||||
pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) or
|
||||
pqxxConnectionClassNames(c.getName(), c.getNamespace().getName())
|
||||
) and
|
||||
pqxxEscapeArgument(this.getName(), _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate getAnEscapedParameter(FunctionInput input, FunctionOutput output) {
|
||||
exists(int argIndex |
|
||||
input.isParameterDeref(argIndex) and
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
private class SqLite3Sink extends SqlSink {
|
||||
SqLite3Sink() { this.hasName("sqlite3_exec") }
|
||||
|
||||
override predicate getAnSqlParameter(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
30
cpp/ql/src/semmle/code/cpp/models/interfaces/Sql.qll
Normal file
30
cpp/ql/src/semmle/code/cpp/models/interfaces/Sql.qll
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Provides abstract classes for modeling functions that execute and escape SQL query strings.
|
||||
* To use this QL library, create a QL class extending `SqlSink` or `SqlBarrier` with a
|
||||
* characteristic predicate that selects the function or set of functions you are modeling.
|
||||
* Within that class, override the predicates provided by the class to match the way a
|
||||
* parameter flows into the function and, in the case of `SqlBarrier`, out of the function.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
|
||||
/**
|
||||
* An abstract class that represents a function that executes an SQL query.
|
||||
*/
|
||||
abstract class SqlSink extends Function {
|
||||
/**
|
||||
* Holds if `input` to this function represents data that is passed to an SQL server.
|
||||
*/
|
||||
abstract predicate getAnSqlParameter(FunctionInput input);
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class that represents a function that escapes an SQL query string.
|
||||
*/
|
||||
abstract class SqlBarrier extends Function {
|
||||
/**
|
||||
* Holds if the `output` escapes the SQL input `input` such that is it safe to pass to
|
||||
* an `SqlSink`.
|
||||
*/
|
||||
abstract predicate getAnEscapedParameter(FunctionInput input, FunctionOutput output);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.commons.Environment
|
||||
import semmle.code.cpp.security.SecurityOptions
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
private import Sql
|
||||
import semmle.code.cpp.models.interfaces.Sql
|
||||
|
||||
/**
|
||||
* Extend this class to customize the security queries for
|
||||
@@ -35,10 +35,10 @@ class SecurityOptions extends string {
|
||||
* An argument to a function that is passed to a SQL server.
|
||||
*/
|
||||
predicate sqlArgument(string function, int arg) {
|
||||
exists(Function func, FunctionInput input, SqlFunctionality sql |
|
||||
func.hasName(function) and
|
||||
exists(FunctionInput input, SqlSink sqlSink |
|
||||
sqlSink.hasName(function) and
|
||||
input.isParameterDeref(arg) and
|
||||
sql.getAnSqlParameter(func, input)
|
||||
sqlSink.getAnSqlParameter(input)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* This file provides classes for working with various SQL libraries and frameworks.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
/**
|
||||
* An abstract class that represents SQL parameters and escaping functions.
|
||||
*
|
||||
* To add support for a new SQL framework, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MySqlFunctionality extends SqlFunctionality {
|
||||
* MySqlFunctionality() { this = "MySqlFunctionality" }
|
||||
* // Override `getAnSqlParameter`.
|
||||
* // Optionally override `getAnEscapedParameter`.
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
abstract class SqlFunctionality extends string {
|
||||
bindingset[this]
|
||||
SqlFunctionality() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `input` to the function `func` represents data that is passed to an SQL server.
|
||||
*/
|
||||
abstract predicate getAnSqlParameter(Function func, FunctionInput input);
|
||||
|
||||
/**
|
||||
* Holds if the `output` from `func` escapes the SQL input `input` such that is it safe to pass to
|
||||
* an SQL server.
|
||||
*/
|
||||
predicate getAnEscapedParameter(Function func, FunctionInput input, FunctionOutput output) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
private class MySqlFunctionality extends SqlFunctionality {
|
||||
MySqlFunctionality() { this = "MySqlFunctionality" }
|
||||
|
||||
override predicate getAnSqlParameter(Function func, FunctionInput input) {
|
||||
func.hasName(["mysql_query", "mysql_real_query"]) and
|
||||
input.isParameterDeref(1)
|
||||
}
|
||||
}
|
||||
|
||||
private class SqLite3Functionality extends SqlFunctionality {
|
||||
SqLite3Functionality() { this = "SqLite3Functionality" }
|
||||
|
||||
override predicate getAnSqlParameter(Function func, FunctionInput input) {
|
||||
func.hasName("sqlite3_exec") and
|
||||
input.isParameterDeref(1)
|
||||
}
|
||||
}
|
||||
|
||||
private module PostgreSql {
|
||||
private predicate pqxxTransactionSqlArgument(string function, int arg) {
|
||||
function = "exec" and arg = 0
|
||||
or
|
||||
function = "exec0" and arg = 0
|
||||
or
|
||||
function = "exec1" and arg = 0
|
||||
or
|
||||
function = "exec_n" and arg = 1
|
||||
or
|
||||
function = "exec_params" and arg = 0
|
||||
or
|
||||
function = "exec_params0" and arg = 0
|
||||
or
|
||||
function = "exec_params1" and arg = 0
|
||||
or
|
||||
function = "exec_params_n" and arg = 1
|
||||
or
|
||||
function = "query_value" and arg = 0
|
||||
or
|
||||
function = "stream" and arg = 0
|
||||
}
|
||||
|
||||
private predicate pqxxConnectionSqlArgument(string function, int arg) {
|
||||
function = "prepare" and arg = 1
|
||||
}
|
||||
|
||||
private predicate pqxxTransationClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in [
|
||||
"dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction",
|
||||
"subtransaction", "transaction", "basic_transaction", "transaction_base", "work"
|
||||
]
|
||||
}
|
||||
|
||||
private predicate pqxxConnectionClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in ["connection_base", "basic_connection", "connection"]
|
||||
}
|
||||
|
||||
private predicate pqxxEscapeArgument(string function, int arg) {
|
||||
arg = 0 and
|
||||
function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"]
|
||||
}
|
||||
|
||||
class PostgreSqlFunctionality extends SqlFunctionality {
|
||||
PostgreSqlFunctionality() { this = "PostgreSqlFunctionality" }
|
||||
|
||||
override predicate getAnSqlParameter(Function func, FunctionInput input) {
|
||||
exists(int argIndex, UserType t |
|
||||
func.getDeclaringType() = t and
|
||||
// transaction exec and connection prepare variations
|
||||
(
|
||||
pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) and
|
||||
pqxxTransactionSqlArgument(func.getName(), argIndex)
|
||||
or
|
||||
pqxxConnectionClassNames(t.getName(), t.getNamespace().getName()) and
|
||||
pqxxConnectionSqlArgument(func.getName(), argIndex)
|
||||
) and
|
||||
input.isParameterDeref(argIndex)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate getAnEscapedParameter(
|
||||
Function func, FunctionInput input, FunctionOutput output
|
||||
) {
|
||||
exists(int argIndex, UserType t |
|
||||
func.getDeclaringType() = t and
|
||||
// transaction and connection escape functions
|
||||
(
|
||||
pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) or
|
||||
pqxxConnectionClassNames(t.getName(), t.getNamespace().getName())
|
||||
) and
|
||||
pqxxEscapeArgument(func.getName(), argIndex) and
|
||||
input.isParameterDeref(argIndex) and
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private import PostgreSql
|
||||
@@ -5,14 +5,14 @@ edges
|
||||
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 |
|
||||
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection |
|
||||
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | (const char *)... |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | (const char *)... |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array indirection |
|
||||
| test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array indirection |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | (const char *)... |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | (const char *)... |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array indirection |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array indirection |
|
||||
nodes
|
||||
| test.c:15:20:15:23 | argv | semmle.label | argv |
|
||||
| test.c:15:20:15:23 | argv | semmle.label | argv |
|
||||
@@ -21,15 +21,15 @@ nodes
|
||||
| test.c:21:18:21:23 | query1 | semmle.label | query1 |
|
||||
| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection |
|
||||
| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection |
|
||||
| test.cpp:44:27:44:30 | argv | semmle.label | argv |
|
||||
| test.cpp:44:27:44:30 | argv | semmle.label | argv |
|
||||
| test.cpp:44:27:44:33 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:44:27:44:33 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:44:27:44:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:44:27:44:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:44:27:44:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:44:27:44:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
| test.cpp:44:27:44:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
| test.cpp:43:27:43:30 | argv | semmle.label | argv |
|
||||
| test.cpp:43:27:43:30 | argv | semmle.label | argv |
|
||||
| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
#select
|
||||
| test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:15:20:15:23 | argv | user input (argv) |
|
||||
| test.cpp:44:27:44:33 | access to array | test.cpp:44:27:44:30 | argv | test.cpp:44:27:44:33 | access to array | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)) | test.cpp:44:27:44:30 | argv | user input (argv) |
|
||||
| test.cpp:43:27:43:33 | access to array | test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)) | test.cpp:43:27:43:30 | argv | user input (argv) |
|
||||
|
||||
Reference in New Issue
Block a user