Skip to content

Commit e2c9240

Browse files
committed
Add a new Custom URL Scheme source
Also adds a couple of data flow steps to model flow through `?` expressions.
1 parent 9e5d9f8 commit e2c9240

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ private module Cached {
148148
// flow through `!`
149149
nodeFrom.asExpr() = nodeTo.asExpr().(ForceValueExpr).getSubExpr()
150150
or
151+
// flow through `?`
152+
nodeFrom.asExpr() = nodeTo.asExpr().(BindOptionalExpr).getSubExpr()
153+
or
154+
nodeFrom.asExpr() = nodeTo.asExpr().(OptionalEvaluationExpr).getSubExpr()
155+
or
151156
// flow through a flow summary (extension of `SummaryModelCsv`)
152157
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
153158
}
Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,54 @@
11
import swift
2+
private import codeql.swift.dataflow.DataFlow
23
private import codeql.swift.dataflow.ExternalFlow
4+
private import codeql.swift.dataflow.FlowSources
35

46
private class UrlRemoteFlowSource extends SourceModelCsv {
57
override predicate row(string row) {
68
row =
79
[
810
";UIApplicationDelegate;true;application(_:open:options:);;;Parameter[1];remote",
911
";UIApplicationDelegate;true;application(_:handleOpen:);;;Parameter[1];remote",
10-
";UIApplicationDelegate;true;application(_:open:sourceApplication:annotation:);;;Parameter[1];remote"
12+
";UIApplicationDelegate;true;application(_:open:sourceApplication:annotation:);;;Parameter[1];remote",
13+
// TODO: The actual source is the value of `UIApplication.LaunchOptionsKey.url` in the launchOptions dictionary.
14+
// Use dictionary value contents when available.
15+
// ";UIApplicationDelegate;true;application(_:didFinishLaunchingWithOptions:);;;Parameter[1].MapValue;remote",
16+
// ";UIApplicationDelegate;true;application(_:willFinishLaunchingWithOptions:);;;Parameter[1].MapValue;remote"
1117
]
1218
}
1319
}
20+
21+
/**
22+
* A read of `UIApplication.LaunchOptionsKey.url` on a dictionary received in
23+
* `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)` or
24+
* `UIApplicationDelegate.application(_:willFinishLaunchingWithOptions:)`.
25+
*/
26+
// This is a temporary workaround until the TODO above is addressed.
27+
private class UrlLaunchOptionsRemoteFlowSource extends RemoteFlowSource {
28+
UrlLaunchOptionsRemoteFlowSource() {
29+
exists(ApllicationWithLaunchOptionsFunc f, SubscriptExpr e |
30+
DataFlow::localExprFlow(f.getParam(1).getAnAccess(), e.getBase()) and
31+
e.getAnArgument().getExpr().(MemberRefExpr).getMember() instanceof LaunchOptionsUrlVarDecl and
32+
this.asExpr() = e
33+
)
34+
}
35+
36+
override string getSourceType() {
37+
result = "Remote URL in UIApplicationDelegate.application.launchOptions"
38+
}
39+
}
40+
41+
private class ApllicationWithLaunchOptionsFunc extends FuncDecl {
42+
ApllicationWithLaunchOptionsFunc() {
43+
this.getName() = "application(_:" + ["did", "will"] + "FinishLaunchingWithOptions:)" and
44+
this.getEnclosingDecl().(ClassOrStructDecl).getABaseTypeDecl*().(ProtocolDecl).getName() =
45+
"UIApplicationDelegate"
46+
}
47+
}
48+
49+
private class LaunchOptionsUrlVarDecl extends VarDecl {
50+
LaunchOptionsUrlVarDecl() {
51+
this.getEnclosingDecl().(StructDecl).getName() = "UIApplication.LaunchOptionsKey" and
52+
this.getName() = "url"
53+
}
54+
}
Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,45 @@
11
// --- stubs ---
22
class UIApplication {
3-
struct OpenURLOptionsKey {}
3+
struct OpenURLOptionsKey: Hashable {}
4+
struct LaunchOptionsKey: Hashable {
5+
init(rawValue: String) {}
6+
public static let url: UIApplication.LaunchOptionsKey = UIApplication.LaunchOptionsKey(rawValue: "")
7+
}
48
}
59

610
struct URL {}
711

812
protocol UIApplicationDelegate {
9-
optional func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool
10-
optional func application(_ application: UIApplication, handleOpen url: URL) -> Bool
11-
optional func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool
13+
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool
14+
func application(_ application: UIApplication, handleOpen url: URL) -> Bool
15+
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool
16+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool
17+
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool
1218
}
1319

1420
// --- tests ---
1521

1622
class AppDelegate: UIApplicationDelegate {
1723
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { // SOURCE
24+
return false
1825
}
1926

2027
func application(_ application: UIApplication, handleOpen url: URL) -> Bool { // SOURCE
28+
return false
2129
}
2230

2331
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { // SOURCE
32+
return false
33+
}
34+
35+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
36+
launchOptions?[.url] // SOURCE
37+
return false
38+
}
39+
40+
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
41+
launchOptions?[.url] // SOURCE
42+
return false
2443
}
2544

2645
}

0 commit comments

Comments
 (0)