Skip to content

Commit 78eff0d

Browse files
committed
Swift: Split off the Extensions.qll as well.
1 parent cbfa7e7 commit 78eff0d

File tree

6 files changed

+258
-232
lines changed

6 files changed

+258
-232
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* Provides classes and predicates for reasoning about database
3+
* queries built from user-controlled sources (that is, SQL injection
4+
* vulnerabilities).
5+
*/
6+
7+
import swift
8+
import codeql.swift.dataflow.DataFlow
9+
10+
/**
11+
* A `DataFlow::Node` that is a sink for a SQL string to be executed.
12+
*/
13+
abstract class SqlSink extends DataFlow::Node { }
14+
15+
/**
16+
* A sink for the sqlite3 C API.
17+
*/
18+
class CApiSqlSink extends SqlSink {
19+
CApiSqlSink() {
20+
// `sqlite3_exec` and variants of `sqlite3_prepare`.
21+
exists(CallExpr call |
22+
call.getStaticTarget()
23+
.(FreeFunctionDecl)
24+
.hasName([
25+
"sqlite3_exec(_:_:_:_:_:)", "sqlite3_prepare(_:_:_:_:_:)",
26+
"sqlite3_prepare_v2(_:_:_:_:_:)", "sqlite3_prepare_v3(_:_:_:_:_:_:)",
27+
"sqlite3_prepare16(_:_:_:_:_:)", "sqlite3_prepare16_v2(_:_:_:_:_:)",
28+
"sqlite3_prepare16_v3(_:_:_:_:_:_:)"
29+
]) and
30+
call.getArgument(1).getExpr() = this.asExpr()
31+
)
32+
}
33+
}
34+
35+
/**
36+
* A sink for the SQLite.swift library.
37+
*/
38+
class SQLiteSwiftSqlSink extends SqlSink {
39+
SQLiteSwiftSqlSink() {
40+
// Variants of `Connection.execute`, `connection.prepare` and `connection.scalar`.
41+
exists(CallExpr call |
42+
call.getStaticTarget()
43+
.(MethodDecl)
44+
.hasQualifiedName("Connection",
45+
["execute(_:)", "prepare(_:_:)", "run(_:_:)", "scalar(_:_:)"]) and
46+
call.getArgument(0).getExpr() = this.asExpr()
47+
)
48+
or
49+
// String argument to the `Statement` constructor.
50+
exists(CallExpr call |
51+
call.getStaticTarget().(MethodDecl).hasQualifiedName("Statement", "init(_:_:)") and
52+
call.getArgument(1).getExpr() = this.asExpr()
53+
)
54+
}
55+
}
56+
57+
/** A sink for the GRDB library. */
58+
class GrdbSqlSink extends SqlSink {
59+
GrdbSqlSink() {
60+
exists(CallExpr call, MethodDecl method |
61+
call.getStaticTarget() = method and
62+
call.getArgument(0).getExpr() = this.asExpr()
63+
|
64+
method
65+
.hasQualifiedName("Database",
66+
[
67+
"allStatements(sql:arguments:)", "cachedStatement(sql:)",
68+
"internalCachedStatement(sql:)", "execute(sql:arguments:)", "makeStatement(sql:)",
69+
"makeStatement(sql:prepFlags:)"
70+
])
71+
or
72+
method
73+
.hasQualifiedName("SQLRequest",
74+
[
75+
"init(stringLiteral:)", "init(unicodeScalarLiteral:)",
76+
"init(extendedGraphemeClusterLiteral:)", "init(stringInterpolation:)",
77+
"init(sql:arguments:adapter:cached:)"
78+
])
79+
or
80+
method
81+
.hasQualifiedName("SQL",
82+
[
83+
"init(stringLiteral:)", "init(unicodeScalarLiteral:)",
84+
"init(extendedGraphemeClusterLiteral:)", "init(stringInterpolation:)",
85+
"init(sql:arguments:)", "append(sql:arguments:)"
86+
])
87+
or
88+
method
89+
.hasQualifiedName("TableDefinition", ["column(sql:)", "check(sql:)", "constraint(sql:)"])
90+
or
91+
method.hasQualifiedName("TableAlteration", "addColumn(sql:)")
92+
or
93+
method
94+
.hasQualifiedName("ColumnDefinition",
95+
["check(sql:)", "defaults(sql:)", "generatedAs(sql:_:)"])
96+
or
97+
method
98+
.hasQualifiedName("TableRecord",
99+
[
100+
"select(sql:arguments:)", "select(sql:arguments:as:)", "filter(sql:arguments:)",
101+
"order(sql:arguments:)"
102+
])
103+
or
104+
method.hasQualifiedName("StatementCache", "statement(_:)")
105+
)
106+
or
107+
exists(CallExpr call, MethodDecl method |
108+
call.getStaticTarget() = method and
109+
call.getArgument(1).getExpr() = this.asExpr()
110+
|
111+
method
112+
.hasQualifiedName(["Row", "DatabaseValueConvertible"],
113+
[
114+
"fetchCursor(_:sql:arguments:adapter:)", "fetchAll(_:sql:arguments:adapter:)",
115+
"fetchSet(_:sql:arguments:adapter:)", "fetchOne(_:sql:arguments:adapter:)"
116+
])
117+
or
118+
method.hasQualifiedName("SQLStatementCursor", "init(database:sql:arguments:prepFlags:)")
119+
)
120+
or
121+
exists(CallExpr call, MethodDecl method |
122+
call.getStaticTarget() = method and
123+
call.getArgument(3).getExpr() = this.asExpr()
124+
|
125+
method
126+
.hasQualifiedName("CommonTableExpression", "init(recursive:named:columns:sql:arguments:)")
127+
)
128+
}
129+
}

swift/ql/lib/codeql/swift/security/SqlInjectionQuery.qll

Lines changed: 1 addition & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -8,127 +8,7 @@ import swift
88
import codeql.swift.dataflow.DataFlow
99
import codeql.swift.dataflow.TaintTracking
1010
import codeql.swift.dataflow.FlowSources
11-
12-
/**
13-
* A `DataFlow::Node` that is a sink for a SQL string to be executed.
14-
*/
15-
abstract class SqlSink extends DataFlow::Node { }
16-
17-
/**
18-
* A sink for the sqlite3 C API.
19-
*/
20-
class CApiSqlSink extends SqlSink {
21-
CApiSqlSink() {
22-
// `sqlite3_exec` and variants of `sqlite3_prepare`.
23-
exists(CallExpr call |
24-
call.getStaticTarget()
25-
.(FreeFunctionDecl)
26-
.hasName([
27-
"sqlite3_exec(_:_:_:_:_:)", "sqlite3_prepare(_:_:_:_:_:)",
28-
"sqlite3_prepare_v2(_:_:_:_:_:)", "sqlite3_prepare_v3(_:_:_:_:_:_:)",
29-
"sqlite3_prepare16(_:_:_:_:_:)", "sqlite3_prepare16_v2(_:_:_:_:_:)",
30-
"sqlite3_prepare16_v3(_:_:_:_:_:_:)"
31-
]) and
32-
call.getArgument(1).getExpr() = this.asExpr()
33-
)
34-
}
35-
}
36-
37-
/**
38-
* A sink for the SQLite.swift library.
39-
*/
40-
class SQLiteSwiftSqlSink extends SqlSink {
41-
SQLiteSwiftSqlSink() {
42-
// Variants of `Connection.execute`, `connection.prepare` and `connection.scalar`.
43-
exists(CallExpr call |
44-
call.getStaticTarget()
45-
.(MethodDecl)
46-
.hasQualifiedName("Connection",
47-
["execute(_:)", "prepare(_:_:)", "run(_:_:)", "scalar(_:_:)"]) and
48-
call.getArgument(0).getExpr() = this.asExpr()
49-
)
50-
or
51-
// String argument to the `Statement` constructor.
52-
exists(CallExpr call |
53-
call.getStaticTarget().(MethodDecl).hasQualifiedName("Statement", "init(_:_:)") and
54-
call.getArgument(1).getExpr() = this.asExpr()
55-
)
56-
}
57-
}
58-
59-
/** A sink for the GRDB library. */
60-
class GrdbSqlSink extends SqlSink {
61-
GrdbSqlSink() {
62-
exists(CallExpr call, MethodDecl method |
63-
call.getStaticTarget() = method and
64-
call.getArgument(0).getExpr() = this.asExpr()
65-
|
66-
method
67-
.hasQualifiedName("Database",
68-
[
69-
"allStatements(sql:arguments:)", "cachedStatement(sql:)",
70-
"internalCachedStatement(sql:)", "execute(sql:arguments:)", "makeStatement(sql:)",
71-
"makeStatement(sql:prepFlags:)"
72-
])
73-
or
74-
method
75-
.hasQualifiedName("SQLRequest",
76-
[
77-
"init(stringLiteral:)", "init(unicodeScalarLiteral:)",
78-
"init(extendedGraphemeClusterLiteral:)", "init(stringInterpolation:)",
79-
"init(sql:arguments:adapter:cached:)"
80-
])
81-
or
82-
method
83-
.hasQualifiedName("SQL",
84-
[
85-
"init(stringLiteral:)", "init(unicodeScalarLiteral:)",
86-
"init(extendedGraphemeClusterLiteral:)", "init(stringInterpolation:)",
87-
"init(sql:arguments:)", "append(sql:arguments:)"
88-
])
89-
or
90-
method
91-
.hasQualifiedName("TableDefinition", ["column(sql:)", "check(sql:)", "constraint(sql:)"])
92-
or
93-
method.hasQualifiedName("TableAlteration", "addColumn(sql:)")
94-
or
95-
method
96-
.hasQualifiedName("ColumnDefinition",
97-
["check(sql:)", "defaults(sql:)", "generatedAs(sql:_:)"])
98-
or
99-
method
100-
.hasQualifiedName("TableRecord",
101-
[
102-
"select(sql:arguments:)", "select(sql:arguments:as:)", "filter(sql:arguments:)",
103-
"order(sql:arguments:)"
104-
])
105-
or
106-
method.hasQualifiedName("StatementCache", "statement(_:)")
107-
)
108-
or
109-
exists(CallExpr call, MethodDecl method |
110-
call.getStaticTarget() = method and
111-
call.getArgument(1).getExpr() = this.asExpr()
112-
|
113-
method
114-
.hasQualifiedName(["Row", "DatabaseValueConvertible"],
115-
[
116-
"fetchCursor(_:sql:arguments:adapter:)", "fetchAll(_:sql:arguments:adapter:)",
117-
"fetchSet(_:sql:arguments:adapter:)", "fetchOne(_:sql:arguments:adapter:)"
118-
])
119-
or
120-
method.hasQualifiedName("SQLStatementCursor", "init(database:sql:arguments:prepFlags:)")
121-
)
122-
or
123-
exists(CallExpr call, MethodDecl method |
124-
call.getStaticTarget() = method and
125-
call.getArgument(3).getExpr() = this.asExpr()
126-
|
127-
method
128-
.hasQualifiedName("CommonTableExpression", "init(recursive:named:columns:sql:arguments:)")
129-
)
130-
}
131-
}
11+
import codeql.swift.security.SqlInjectionExtensions
13212

13313
/**
13414
* A taint configuration for tainted data that reaches a SQL sink.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* Provides classes and predicates for reasoning about javascript
3+
* evaluation vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.FlowSources
9+
10+
/**
11+
* A source of untrusted, user-controlled data.
12+
*/
13+
class Source = FlowSource;
14+
15+
/**
16+
* A sink that evaluates a string of JavaScript code.
17+
*/
18+
abstract class Sink extends DataFlow::Node { }
19+
20+
class WKWebView extends Sink {
21+
WKWebView() {
22+
any(CallExpr ce |
23+
ce.getStaticTarget()
24+
.(MethodDecl)
25+
.hasQualifiedName("WKWebView",
26+
[
27+
"evaluateJavaScript(_:)", "evaluateJavaScript(_:completionHandler:)",
28+
"evaluateJavaScript(_:in:in:completionHandler:)",
29+
"evaluateJavaScript(_:in:contentWorld:)",
30+
"callAsyncJavaScript(_:arguments:in:in:completionHandler:)",
31+
"callAsyncJavaScript(_:arguments:in:contentWorld:)"
32+
])
33+
).getArgument(0).getExpr() = this.asExpr()
34+
}
35+
}
36+
37+
class WKUserContentController extends Sink {
38+
WKUserContentController() {
39+
any(CallExpr ce |
40+
ce.getStaticTarget()
41+
.(MethodDecl)
42+
.hasQualifiedName("WKUserContentController", "addUserScript(_:)")
43+
).getArgument(0).getExpr() = this.asExpr()
44+
}
45+
}
46+
47+
class UIWebView extends Sink {
48+
UIWebView() {
49+
any(CallExpr ce |
50+
ce.getStaticTarget()
51+
.(MethodDecl)
52+
.hasQualifiedName(["UIWebView", "WebView"], "stringByEvaluatingJavaScript(from:)")
53+
).getArgument(0).getExpr() = this.asExpr()
54+
}
55+
}
56+
57+
class JSContext extends Sink {
58+
JSContext() {
59+
any(CallExpr ce |
60+
ce.getStaticTarget()
61+
.(MethodDecl)
62+
.hasQualifiedName("JSContext", ["evaluateScript(_:)", "evaluateScript(_:withSourceURL:)"])
63+
).getArgument(0).getExpr() = this.asExpr()
64+
}
65+
}
66+
67+
class JSEvaluateScript extends Sink {
68+
JSEvaluateScript() {
69+
any(CallExpr ce |
70+
ce.getStaticTarget().(FreeFunctionDecl).hasName("JSEvaluateScript(_:_:_:_:_:_:)")
71+
).getArgument(1).getExpr() = this.asExpr()
72+
}
73+
}

0 commit comments

Comments
 (0)