Skip to content

Commit 3468593

Browse files
authored
Merge pull request github#4915 from geoffw0/sqltaint
C++: Fix FPs in cpp/sql-injection
2 parents 842ed62 + 7409dd0 commit 3468593

File tree

5 files changed

+58
-1
lines changed

5 files changed

+58
-1
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class Configuration extends TaintTrackingConfiguration {
2727
override predicate isSink(Element tainted) {
2828
exists(SQLLikeFunction runSql | runSql.outermostWrapperFunctionCall(tainted, _))
2929
}
30+
31+
override predicate isBarrier(Expr e) {
32+
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
33+
}
3034
}
3135

3236
from

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,9 @@ module TaintedWithPath {
545545
/** Override this to specify which elements are sinks in this configuration. */
546546
abstract predicate isSink(Element e);
547547

548+
/** Override this to specify which expressions are barriers in this configuration. */
549+
predicate isBarrier(Expr e) { nodeIsBarrier(getNodeForExpr(e)) }
550+
548551
/**
549552
* Override this predicate to `any()` to allow taint to flow through global
550553
* variables.
@@ -578,7 +581,9 @@ module TaintedWithPath {
578581
)
579582
}
580583

581-
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
584+
override predicate isBarrier(DataFlow::Node node) {
585+
exists(TaintTrackingConfiguration cfg, Expr e | cfg.isBarrier(e) and node = getNodeForExpr(e))
586+
}
582587

583588
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
584589
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
edges
2+
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... |
3+
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... |
4+
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 |
5+
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 |
6+
nodes
7+
| test.c:15:20:15:23 | argv | semmle.label | argv |
8+
| test.c:15:20:15:23 | argv | semmle.label | argv |
9+
| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... |
10+
| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... |
11+
| test.c:21:18:21:23 | query1 | semmle.label | query1 |
12+
#select
13+
| 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) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-089/SqlTainted.ql
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Semmle test case for rule SprintfToSqlQuery.ql (Uncontrolled sprintf for SQL query)
2+
// Associated with CWE-089: SQL injection. http://cwe.mitre.org/data/definitions/89.html
3+
4+
///// Library routines /////
5+
6+
typedef unsigned long size_t;
7+
int snprintf(char *s, size_t n, const char *format, ...);
8+
void sanitizeString(char *stringOut, size_t len, const char *strIn);
9+
int mysql_query(int arg1, const char *sqlArg);
10+
int atoi(const char *nptr);
11+
12+
///// Test code /////
13+
14+
int main(int argc, char** argv) {
15+
char *userName = argv[2];
16+
int userNumber = atoi(argv[3]);
17+
18+
// a string from the user is injected directly into an SQL query.
19+
char query1[1000] = {0};
20+
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName);
21+
mysql_query(0, query1); // BAD
22+
23+
// the user string is encoded by a library routine.
24+
char userNameSanitized[1000] = {0};
25+
sanitizeString(userNameSanitized, 1000, userName);
26+
char query2[1000] = {0};
27+
snprintf(query2, 1000, "SELECT UID FROM USERS where name = \"%s\"", userNameSanitized);
28+
mysql_query(0, query2); // GOOD
29+
30+
// an integer from the user is injected into an SQL query.
31+
char query3[1000] = {0};
32+
snprintf(query3, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber);
33+
mysql_query(0, query3); // GOOD
34+
}

0 commit comments

Comments
 (0)