Skip to content

Commit 679d64f

Browse files
authored
Merge pull request #14647 from microsoft/24-odbc-model-instantiation-upstream2
C++: Adding a model implementation for ODBC.
2 parents 81d77bf + 30a512c commit 679d64f

File tree

5 files changed

+66
-0
lines changed

5 files changed

+66
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ private import implementations.Accept
3535
private import implementations.Poll
3636
private import implementations.Select
3737
private import implementations.MySql
38+
private import implementations.ODBC
3839
private import implementations.SqLite3
3940
private import implementations.PostgreSql
4041
private import implementations.System
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Provides implementation classes modeling the ODBC C/C++ API.
3+
* See `semmle.code.cpp.models.Models` for usage information.
4+
*/
5+
6+
private import semmle.code.cpp.models.interfaces.Sql
7+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
8+
9+
/**
10+
* The `SQLExecDirect`, and `SQLPrepare` from the ODBC C/C++ API:
11+
* https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlexecdirect-function?view=sql-server-ver16
12+
* https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlprepare-function?view=sql-server-ver16
13+
*
14+
* Note, `SQLExecute` is not included because it operates on a SQLHSTMT type, not a string.
15+
* The SQLHSTMT parameter for `SQLExecute` is set through a `SQLPrepare`, which is modeled.
16+
* The other source of input to a `SQLExecute` is via a `SQLBindParameter`, which sanitizes user input,
17+
* and would be considered a barrier to SQL injection.
18+
*/
19+
private class ODBCExecutionFunction extends SqlExecutionFunction {
20+
ODBCExecutionFunction() { this.hasGlobalName(["SQLExecDirect", "SQLPrepare"]) }
21+
22+
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
23+
}
24+
// NOTE: no need to define a barrier explicitly.
25+
// `SQLBindParameter` is the typical means for sanitizing user input.
26+
// https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function?view=sql-server-ver16
27+
// First a query is establisehed via `SQLPrepare`, then parameters are bound via `SQLBindParameter`, before
28+
// the query is executed via `SQLExecute`. We are not modeling SQLExecute, so we do not need to model SQLBindParameter.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added SQL API models for `ODBC`.

cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ edges
44
| test.c:35:16:35:23 | userName indirection | test.c:40:25:40:32 | username indirection |
55
| test.c:38:7:38:20 | globalUsername indirection | test.c:51:18:51:23 | query1 indirection |
66
| test.c:40:25:40:32 | username indirection | test.c:38:7:38:20 | globalUsername indirection |
7+
| test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | userInput indirection |
8+
| test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | userInput indirection |
79
| test.cpp:39:27:39:30 | argv indirection | test.cpp:43:27:43:33 | access to array indirection |
810
nodes
911
| test.c:14:27:14:30 | argv indirection | semmle.label | argv indirection |
@@ -12,10 +14,15 @@ nodes
1214
| test.c:38:7:38:20 | globalUsername indirection | semmle.label | globalUsername indirection |
1315
| test.c:40:25:40:32 | username indirection | semmle.label | username indirection |
1416
| test.c:51:18:51:23 | query1 indirection | semmle.label | query1 indirection |
17+
| test.c:75:8:75:16 | gets output argument | semmle.label | gets output argument |
18+
| test.c:76:17:76:25 | userInput indirection | semmle.label | userInput indirection |
19+
| test.c:77:20:77:28 | userInput indirection | semmle.label | userInput indirection |
1520
| test.cpp:39:27:39:30 | argv indirection | semmle.label | argv indirection |
1621
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
1722
subpaths
1823
#select
1924
| test.c:21:18:21:23 | query1 | test.c:14:27:14:30 | argv indirection | test.c:21:18:21:23 | query1 indirection | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | argv indirection | user input (a command-line argument) |
2025
| test.c:51:18:51:23 | query1 | test.c:14:27:14:30 | argv indirection | test.c:51:18:51:23 | query1 indirection | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | argv indirection | user input (a command-line argument) |
26+
| test.c:76:17:76:25 | userInput | test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | userInput indirection | This argument to a SQL query function is derived from $@ and then passed to SQLPrepare(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
27+
| test.c:77:20:77:28 | userInput | test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | userInput indirection | This argument to a SQL query function is derived from $@ and then passed to SQLExecDirect(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
2128
| test.cpp:43:27:43:33 | access to array | test.cpp:39:27:39:30 | argv indirection | test.cpp:43:27:43:33 | access to array indirection | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)). | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |

cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,29 @@ void badFunc() {
5050
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName);
5151
mysql_query(0, query1); // BAD
5252
}
53+
54+
//ODBC Library Rountines
55+
typedef unsigned char SQLCHAR;
56+
typedef long int SQLINTEGER;
57+
typedef int SQLRETURN;
58+
typedef void* SQLHSTMT;
59+
60+
char* gets(char *str);
61+
62+
63+
SQLRETURN SQLPrepare(
64+
SQLHSTMT StatementHandle,
65+
SQLCHAR * StatementText,
66+
SQLINTEGER TextLength);
67+
68+
SQLRETURN SQLExecDirect(
69+
SQLHSTMT StatementHandle,
70+
SQLCHAR * StatementText,
71+
SQLINTEGER TextLength);
72+
73+
void ODBCTests(){
74+
char userInput[100];
75+
gets(userInput);
76+
SQLPrepare(0, userInput, 100); // BAD
77+
SQLExecDirect(0, userInput, 100); // BAD
78+
}

0 commit comments

Comments
 (0)