Skip to content

Commit 092fbd6

Browse files
committed
C++: Create a new SQL interface.
1 parent 38a38fd commit 092fbd6

File tree

1 file changed

+140
-0
lines changed
  • cpp/ql/src/semmle/code/cpp/security

1 file changed

+140
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/**
2+
* This file provides classes for working with various SQL libraries and frameworks.
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
7+
8+
/**
9+
* An abstract class that represents SQL parameters and escaping functions.
10+
*
11+
* To add support for a new SQL framework, extend this class with
12+
* a subclass whose characteristic predicate is a unique singleton string.
13+
* For example, write
14+
*
15+
* ```ql
16+
* class MySqlFunctionality extends SqlFunctionality {
17+
* MySqlFunctionality() { this = "MySqlFunctionality" }
18+
* // Override `getAnSqlParameter`.
19+
* // Optionally override `getAnEscapedParameter`.
20+
* }
21+
* ```
22+
*/
23+
abstract class SqlFunctionality extends string {
24+
bindingset[this]
25+
SqlFunctionality() { any() }
26+
27+
/**
28+
* Holds if `input` to the function `func` represents data that is passed to an SQL server.
29+
*/
30+
abstract predicate getAnSqlParameter(Function func, FunctionInput input);
31+
32+
/**
33+
* Holds if the `output` from `func` escapes the SQL input `input` such that is it safe to pass to
34+
* an SQL server.
35+
*/
36+
predicate getAnEscapedParameter(Function func, FunctionInput input, FunctionOutput output) {
37+
none()
38+
}
39+
}
40+
41+
private class MySqlFunctionality extends SqlFunctionality {
42+
MySqlFunctionality() { this = "MySqlFunctionality" }
43+
44+
override predicate getAnSqlParameter(Function func, FunctionInput input) {
45+
func.hasName(["mysql_query", "mysql_real_query"]) and
46+
input.isParameterDeref(1)
47+
}
48+
}
49+
50+
private class SqLite3Functionality extends SqlFunctionality {
51+
SqLite3Functionality() { this = "SqLite3Functionality" }
52+
53+
override predicate getAnSqlParameter(Function func, FunctionInput input) {
54+
func.hasName("sqlite3_exec") and
55+
input.isParameterDeref(1)
56+
}
57+
}
58+
59+
private module PostgreSql {
60+
private predicate pqxxTransactionSqlArgument(string function, int arg) {
61+
function = "exec" and arg = 0
62+
or
63+
function = "exec0" and arg = 0
64+
or
65+
function = "exec1" and arg = 0
66+
or
67+
function = "exec_n" and arg = 1
68+
or
69+
function = "exec_params" and arg = 0
70+
or
71+
function = "exec_params0" and arg = 0
72+
or
73+
function = "exec_params1" and arg = 0
74+
or
75+
function = "exec_params_n" and arg = 1
76+
or
77+
function = "query_value" and arg = 0
78+
or
79+
function = "stream" and arg = 0
80+
}
81+
82+
private predicate pqxxConnectionSqlArgument(string function, int arg) {
83+
function = "prepare" and arg = 1
84+
}
85+
86+
private predicate pqxxTransationClassNames(string className, string namespace) {
87+
namespace = "pqxx" and
88+
className in [
89+
"dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction",
90+
"subtransaction", "transaction", "basic_transaction", "transaction_base", "work"
91+
]
92+
}
93+
94+
private predicate pqxxConnectionClassNames(string className, string namespace) {
95+
namespace = "pqxx" and
96+
className in ["connection_base", "basic_connection", "connection"]
97+
}
98+
99+
private predicate pqxxEscapeArgument(string function, int arg) {
100+
arg = 0 and
101+
function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"]
102+
}
103+
104+
class PostgreSqlFunctionality extends SqlFunctionality {
105+
PostgreSqlFunctionality() { this = "PostgreSqlFunctionality" }
106+
107+
override predicate getAnSqlParameter(Function func, FunctionInput input) {
108+
exists(int argIndex, UserType t |
109+
func.getDeclaringType() = t and
110+
// transaction exec and connection prepare variations
111+
(
112+
pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) and
113+
pqxxTransactionSqlArgument(func.getName(), argIndex)
114+
or
115+
pqxxConnectionClassNames(t.getName(), t.getNamespace().getName()) and
116+
pqxxConnectionSqlArgument(func.getName(), argIndex)
117+
) and
118+
input.isParameterDeref(argIndex)
119+
)
120+
}
121+
122+
override predicate getAnEscapedParameter(
123+
Function func, FunctionInput input, FunctionOutput output
124+
) {
125+
exists(int argIndex, UserType t |
126+
func.getDeclaringType() = t and
127+
// transaction and connection escape functions
128+
(
129+
pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) or
130+
pqxxConnectionClassNames(t.getName(), t.getNamespace().getName())
131+
) and
132+
pqxxEscapeArgument(func.getName(), argIndex) and
133+
input.isParameterDeref(argIndex) and
134+
output.isReturnValueDeref()
135+
)
136+
}
137+
}
138+
}
139+
140+
private import PostgreSql

0 commit comments

Comments
 (0)