Skip to content

Commit d62f76a

Browse files
authored
Merge pull request #6133 from MathiasVP/promote-sql-pqxx
C++: Promote `cpp/sql-injection-via-pqxx` out of experimental
2 parents 97c2917 + 478093a commit d62f76a

File tree

13 files changed

+226
-180
lines changed

13 files changed

+226
-180
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* The 'Uncontrolled data in SQL query' (cpp/sql-injection) query now supports the `libpqxx` library.

cpp/ql/lib/semmle/code/cpp/models/Models.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ private import implementations.Recv
3333
private import implementations.Accept
3434
private import implementations.Poll
3535
private import implementations.Select
36+
private import implementations.MySql
37+
private import implementations.SqLite3
38+
private import implementations.PostgreSql
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
private import semmle.code.cpp.models.interfaces.Sql
2+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
3+
4+
private class MySqlExecutionFunction extends SqlExecutionFunction {
5+
MySqlExecutionFunction() { this.hasName(["mysql_query", "mysql_real_query"]) }
6+
7+
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
8+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
private import semmle.code.cpp.models.interfaces.Sql
2+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
3+
4+
private predicate pqxxTransactionSqlArgument(string function, int arg) {
5+
function = "exec" and arg = 0
6+
or
7+
function = "exec0" and arg = 0
8+
or
9+
function = "exec1" and arg = 0
10+
or
11+
function = "exec_n" and arg = 1
12+
or
13+
function = "exec_params" and arg = 0
14+
or
15+
function = "exec_params0" and arg = 0
16+
or
17+
function = "exec_params1" and arg = 0
18+
or
19+
function = "exec_params_n" and arg = 1
20+
or
21+
function = "query_value" and arg = 0
22+
or
23+
function = "stream" and arg = 0
24+
}
25+
26+
private predicate pqxxConnectionSqlArgument(string function, int arg) {
27+
function = "prepare" and arg = 1
28+
}
29+
30+
private predicate pqxxTransationClassNames(string className, string namespace) {
31+
namespace = "pqxx" and
32+
className in [
33+
"dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction",
34+
"subtransaction", "transaction", "basic_transaction", "transaction_base", "work"
35+
]
36+
}
37+
38+
private predicate pqxxConnectionClassNames(string className, string namespace) {
39+
namespace = "pqxx" and
40+
className in ["connection_base", "basic_connection", "connection"]
41+
}
42+
43+
private predicate pqxxEscapeArgument(string function, int arg) {
44+
arg = 0 and
45+
function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"]
46+
}
47+
48+
private class PostgreSqlExecutionFunction extends SqlExecutionFunction {
49+
PostgreSqlExecutionFunction() {
50+
exists(Class c |
51+
this.getDeclaringType() = c and
52+
// transaction exec and connection prepare variations
53+
(
54+
pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) and
55+
pqxxTransactionSqlArgument(this.getName(), _)
56+
or
57+
pqxxConnectionSqlArgument(this.getName(), _) and
58+
pqxxConnectionClassNames(c.getName(), c.getNamespace().getName())
59+
)
60+
)
61+
}
62+
63+
override predicate hasSqlArgument(FunctionInput input) {
64+
exists(int argIndex |
65+
pqxxTransactionSqlArgument(this.getName(), argIndex)
66+
or
67+
pqxxConnectionSqlArgument(this.getName(), argIndex)
68+
|
69+
input.isParameterDeref(argIndex)
70+
)
71+
}
72+
}
73+
74+
private class PostgreSqlBarrierFunction extends SqlBarrierFunction {
75+
PostgreSqlBarrierFunction() {
76+
exists(Class c |
77+
this.getDeclaringType() = c and
78+
// transaction and connection escape functions
79+
(
80+
pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) or
81+
pqxxConnectionClassNames(c.getName(), c.getNamespace().getName())
82+
) and
83+
pqxxEscapeArgument(this.getName(), _)
84+
)
85+
}
86+
87+
override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) {
88+
exists(int argIndex |
89+
input.isParameterDeref(argIndex) and
90+
output.isReturnValueDeref() and
91+
pqxxEscapeArgument(this.getName(), argIndex)
92+
)
93+
}
94+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
private import semmle.code.cpp.models.interfaces.Sql
2+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
3+
4+
private class SqLite3ExecutionFunction extends SqlExecutionFunction {
5+
SqLite3ExecutionFunction() { this.hasName("sqlite3_exec") }
6+
7+
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
8+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Provides abstract classes for modeling functions that execute and escape SQL query strings.
3+
* To extend this QL library, create a QL class extending `SqlExecutionFunction` or `SqlEscapeFunction`
4+
* with a characteristic predicate that selects the function or set of functions you are modeling.
5+
* Within that class, override the predicates provided by the class to match the way a
6+
* parameter flows into the function and, in the case of `SqlEscapeFunction`, out of the function.
7+
*/
8+
9+
private import cpp
10+
11+
/**
12+
* An abstract class that represents a function that executes an SQL query.
13+
*/
14+
abstract class SqlExecutionFunction extends Function {
15+
/**
16+
* Holds if `input` to this function represents SQL code to be executed.
17+
*/
18+
abstract predicate hasSqlArgument(FunctionInput input);
19+
}
20+
21+
/**
22+
* An abstract class that represents a function that is a barrier to an SQL query string.
23+
*/
24+
abstract class SqlBarrierFunction extends Function {
25+
/**
26+
* Holds if the `output` is a barrier to the SQL input `input` such that is it safe to pass to
27+
* an `SqlExecutionFunction`.
28+
*/
29+
abstract predicate barrierSqlArgument(FunctionInput input, FunctionOutput output);
30+
}

cpp/ql/lib/semmle/code/cpp/security/Security.qll

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import semmle.code.cpp.exprs.Expr
77
import semmle.code.cpp.commons.Environment
88
import semmle.code.cpp.security.SecurityOptions
99
import semmle.code.cpp.models.interfaces.FlowSource
10+
import semmle.code.cpp.models.interfaces.Sql
1011

1112
/**
1213
* Extend this class to customize the security queries for
@@ -34,13 +35,11 @@ class SecurityOptions extends string {
3435
* An argument to a function that is passed to a SQL server.
3536
*/
3637
predicate sqlArgument(string function, int arg) {
37-
// MySQL C API
38-
function = "mysql_query" and arg = 1
39-
or
40-
function = "mysql_real_query" and arg = 1
41-
or
42-
// SQLite3 C API
43-
function = "sqlite3_exec" and arg = 1
38+
exists(FunctionInput input, SqlExecutionFunction sql |
39+
sql.hasName(function) and
40+
input.isParameterDeref(arg) and
41+
sql.hasSqlArgument(input)
42+
)
4443
}
4544

4645
/**

cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ class Configuration extends TaintTrackingConfiguration {
3030
}
3131

3232
override predicate isBarrier(Expr e) {
33-
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
33+
super.isBarrier(e)
34+
or
35+
e.getUnspecifiedType() instanceof IntegralType
36+
or
37+
exists(SqlBarrierFunction sql, int arg, FunctionInput input |
38+
e = sql.getACallToThisFunction().getArgument(arg) and
39+
input.isParameterDeref(arg) and
40+
sql.barrierSqlArgument(input, _)
41+
)
3442
}
3543
}
3644

cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.cpp

Lines changed: 0 additions & 28 deletions
This file was deleted.

cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.qhelp

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)