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:
Mathias Vorreiter Pedersen
2021-06-23 11:31:28 +02:00
parent 90fe5c5aca
commit 90633b9ce1
9 changed files with 167 additions and 166 deletions

View File

@@ -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, _)
)
}
}

View File

@@ -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

View File

@@ -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) }
}

View File

@@ -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()
)
}
}

View File

@@ -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) }
}

View 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);
}

View File

@@ -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)
)
}

View File

@@ -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

View File

@@ -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) |