Skip to content

Commit 407e7cb

Browse files
authored
Merge pull request github#12045 from atorralba/atorralba/more-custom-url-schemes
Swift: Add more sources for custom URL schemes
2 parents 97b2e85 + 43b234e commit 407e7cb

File tree

6 files changed

+326
-7
lines changed

6 files changed

+326
-7
lines changed

swift/ql/lib/codeql/swift/frameworks/StandardLibrary/CustomUrlSchemes.qll

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import swift
22
private import codeql.swift.dataflow.DataFlow
33
private import codeql.swift.dataflow.ExternalFlow
44
private import codeql.swift.dataflow.FlowSources
5+
private import codeql.swift.dataflow.FlowSteps
56

67
/**
78
* A model for custom URL remote flow sources. iOS apps can receive arbitrary
@@ -14,10 +15,14 @@ private class CustomUrlRemoteFlowSource extends SourceModelCsv {
1415
";UIApplicationDelegate;true;application(_:open:options:);;;Parameter[1];remote",
1516
";UIApplicationDelegate;true;application(_:handleOpen:);;;Parameter[1];remote",
1617
";UIApplicationDelegate;true;application(_:open:sourceApplication:annotation:);;;Parameter[1];remote",
17-
// TODO: The actual source is the value of `UIApplication.LaunchOptionsKey.url` in the launchOptions dictionary.
18+
// TODO 1: The actual source is the value of `UIApplication.LaunchOptionsKey.url` in the launchOptions dictionary.
1819
// Use dictionary value contents when available.
1920
// ";UIApplicationDelegate;true;application(_:didFinishLaunchingWithOptions:);;;Parameter[1].MapValue;remote",
2021
// ";UIApplicationDelegate;true;application(_:willFinishLaunchingWithOptions:);;;Parameter[1].MapValue;remote"
22+
";UISceneDelegate;true;scene(_:continue:);;;Parameter[1];remote",
23+
";UISceneDelegate;true;scene(_:didUpdate:);;;Parameter[1];remote",
24+
";UISceneDelegate;true;scene(_:openURLContexts:);;;Parameter[1];remote",
25+
";UISceneDelegate;true;scene(_:willConnectTo:options:);;;Parameter[2];remote"
2126
]
2227
}
2328
}
@@ -27,7 +32,7 @@ private class CustomUrlRemoteFlowSource extends SourceModelCsv {
2732
* `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)` or
2833
* `UIApplicationDelegate.application(_:willFinishLaunchingWithOptions:)`.
2934
*/
30-
// This is a temporary workaround until the TODO above is addressed.
35+
// This is a temporary workaround until the TODO 1 above is addressed.
3136
private class UrlLaunchOptionsRemoteFlowSource extends RemoteFlowSource {
3237
UrlLaunchOptionsRemoteFlowSource() {
3338
exists(ApplicationWithLaunchOptionsFunc f, SubscriptExpr e |
@@ -56,3 +61,37 @@ private class LaunchOptionsUrlVarDecl extends VarDecl {
5661
this.getName() = "url"
5762
}
5863
}
64+
65+
/**
66+
* A content implying that, if a `UIOpenURLContext` is tainted, then its field `url` is also tainted.
67+
*/
68+
private class UiOpenUrlContextUrlInheritTaint extends TaintInheritingContent,
69+
DataFlow::Content::FieldContent {
70+
UiOpenUrlContextUrlInheritTaint() {
71+
this.getField().getEnclosingDecl().(NominalTypeDecl).getName() = "UIOpenURLContext" and
72+
this.getField().getName() = "url"
73+
}
74+
}
75+
76+
/**
77+
* A content implying that, if a `NSUserActivity` is tainted, then its field `webpageURL` is also tainted.
78+
*/
79+
private class UserActivityUrlInheritTaint extends TaintInheritingContent,
80+
DataFlow::Content::FieldContent {
81+
UserActivityUrlInheritTaint() {
82+
this.getField().getEnclosingDecl().(NominalTypeDecl).getName() = "NSUserActivity" and
83+
this.getField().getName() = "webpageURL"
84+
}
85+
}
86+
87+
/**
88+
* A content implying that, if a `UIScene.ConnectionOptions` is tainted, then its fields
89+
* `userActivities` and `urlContexts` are also tainted.
90+
*/
91+
private class ConnectionOptionsFieldsInheritTaint extends TaintInheritingContent,
92+
DataFlow::Content::FieldContent {
93+
ConnectionOptionsFieldsInheritTaint() {
94+
this.getField().getEnclosingDecl().(NominalTypeDecl).getName() = "ConnectionOptions" and
95+
this.getField().getName() = ["userActivities", "urlContexts"]
96+
}
97+
}

swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@
1717
| alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | external |
1818
| alamofire.swift:455:23:455:32 | .data | external |
1919
| alamofire.swift:461:23:461:32 | .data | external |
20-
| customurlschemes.swift:30:44:30:54 | url | external |
21-
| customurlschemes.swift:34:52:34:68 | url | external |
22-
| customurlschemes.swift:38:52:38:62 | url | external |
23-
| customurlschemes.swift:43:9:43:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions |
24-
| customurlschemes.swift:48:9:48:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions |
20+
| customurlschemes.swift:53:44:53:54 | url | external |
21+
| customurlschemes.swift:57:52:57:68 | url | external |
22+
| customurlschemes.swift:61:52:61:62 | url | external |
23+
| customurlschemes.swift:66:9:66:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions |
24+
| customurlschemes.swift:71:9:71:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions |
25+
| customurlschemes.swift:77:59:77:76 | options | external |
26+
| customurlschemes.swift:78:28:78:38 | continue | external |
27+
| customurlschemes.swift:79:28:79:39 | didUpdate | external |
28+
| customurlschemes.swift:80:28:80:65 | openURLContexts | external |
29+
| customurlschemes.swift:86:59:86:76 | options | external |
30+
| customurlschemes.swift:87:28:87:38 | continue | external |
31+
| customurlschemes.swift:88:28:88:39 | didUpdate | external |
32+
| customurlschemes.swift:89:28:89:65 | openURLContexts | external |
2533
| data.swift:18:20:18:54 | call to Data.init(contentsOf:options:) | external |
2634
| file://:0:0:0:0 | .data | external |
2735
| file://:0:0:0:0 | .result | external |

swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,29 @@ protocol UIApplicationDelegate {
2424
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool
2525
}
2626

27+
class UIScene {
28+
class ConnectionOptions {}
29+
}
30+
31+
class UISceneSession {}
32+
33+
class NSUserActivity {}
34+
35+
class UIOpenURLContext: Hashable {
36+
static func == (lhs: UIOpenURLContext, rhs: UIOpenURLContext) -> Bool {
37+
return true;
38+
}
39+
40+
func hash(into hasher: inout Hasher) {}
41+
}
42+
43+
protocol UISceneDelegate {
44+
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions)
45+
func scene(_: UIScene, continue: NSUserActivity)
46+
func scene(_: UIScene, didUpdate: NSUserActivity)
47+
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>)
48+
}
49+
2750
// --- tests ---
2851

2952
class AppDelegate: UIApplicationDelegate {
@@ -48,5 +71,20 @@ class AppDelegate: UIApplicationDelegate {
4871
launchOptions?[.url] // SOURCE
4972
return true
5073
}
74+
}
75+
76+
class SceneDelegate : UISceneDelegate {
77+
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // SOURCE
78+
func scene(_: UIScene, continue: NSUserActivity) {} // SOURCE
79+
func scene(_: UIScene, didUpdate: NSUserActivity) {} // SOURCE
80+
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) {} // SOURCE
81+
}
82+
83+
class Extended {}
5184

85+
extension Extended : UISceneDelegate {
86+
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // SOURCE
87+
func scene(_: UIScene, continue: NSUserActivity) {} // SOURCE
88+
func scene(_: UIScene, didUpdate: NSUserActivity) {} // SOURCE
89+
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) {} // SOURCE
5290
}

swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,128 @@
964964
| try.swift:17:18:17:24 | call to clean() | try.swift:17:13:17:24 | try? ... |
965965
| try.swift:18:13:18:25 | try? ... | try.swift:18:12:18:27 | ...! |
966966
| try.swift:18:18:18:25 | call to source() | try.swift:18:13:18:25 | try? ... |
967+
| ui.swift:3:8:3:8 | SSA def(self) | ui.swift:3:8:3:8 | self[return] |
968+
| ui.swift:3:8:3:8 | self | ui.swift:3:8:3:8 | SSA def(self) |
969+
| ui.swift:5:7:5:7 | SSA def(self) | ui.swift:5:7:5:7 | self[return] |
970+
| ui.swift:5:7:5:7 | SSA def(self) | ui.swift:5:7:5:7 | self[return] |
971+
| ui.swift:5:7:5:7 | self | ui.swift:5:7:5:7 | SSA def(self) |
972+
| ui.swift:5:7:5:7 | self | ui.swift:5:7:5:7 | SSA def(self) |
973+
| ui.swift:6:17:6:17 | SSA def(self) | ui.swift:6:5:8:5 | self[return] |
974+
| ui.swift:6:17:6:17 | self | ui.swift:6:17:6:17 | SSA def(self) |
975+
| ui.swift:10:10:10:10 | SSA def(self) | ui.swift:10:5:10:43 | self[return] |
976+
| ui.swift:10:10:10:10 | self | ui.swift:10:10:10:10 | SSA def(self) |
977+
| ui.swift:10:15:10:34 | SSA def(hasher) | ui.swift:10:5:10:43 | hasher[return] |
978+
| ui.swift:10:15:10:34 | hasher | ui.swift:10:15:10:34 | SSA def(hasher) |
979+
| ui.swift:13:7:13:7 | SSA def(self) | ui.swift:13:7:13:7 | self[return] |
980+
| ui.swift:13:7:13:7 | SSA def(self) | ui.swift:13:7:13:7 | self[return] |
981+
| ui.swift:13:7:13:7 | self | ui.swift:13:7:13:7 | SSA def(self) |
982+
| ui.swift:13:7:13:7 | self | ui.swift:13:7:13:7 | SSA def(self) |
983+
| ui.swift:15:7:15:7 | SSA def(self) | ui.swift:15:7:15:7 | self[return] |
984+
| ui.swift:15:7:15:7 | SSA def(self) | ui.swift:15:7:15:7 | self[return] |
985+
| ui.swift:15:7:15:7 | self | ui.swift:15:7:15:7 | SSA def(self) |
986+
| ui.swift:15:7:15:7 | self | ui.swift:15:7:15:7 | SSA def(self) |
987+
| ui.swift:16:9:16:9 | self | ui.swift:16:9:16:9 | SSA def(self) |
988+
| ui.swift:16:9:16:9 | self | ui.swift:16:9:16:9 | SSA def(self) |
989+
| ui.swift:16:9:16:9 | self | ui.swift:16:9:16:9 | SSA def(self) |
990+
| ui.swift:16:9:16:9 | value | ui.swift:16:9:16:9 | SSA def(value) |
991+
| ui.swift:17:9:17:9 | self | ui.swift:17:9:17:9 | SSA def(self) |
992+
| ui.swift:17:9:17:9 | self | ui.swift:17:9:17:9 | SSA def(self) |
993+
| ui.swift:17:9:17:9 | self | ui.swift:17:9:17:9 | SSA def(self) |
994+
| ui.swift:17:9:17:9 | value | ui.swift:17:9:17:9 | SSA def(value) |
995+
| ui.swift:19:17:19:17 | SSA def(self) | ui.swift:19:5:21:5 | self[return] |
996+
| ui.swift:19:17:19:17 | self | ui.swift:19:17:19:17 | SSA def(self) |
997+
| ui.swift:23:10:23:10 | SSA def(self) | ui.swift:23:5:23:43 | self[return] |
998+
| ui.swift:23:10:23:10 | self | ui.swift:23:10:23:10 | SSA def(self) |
999+
| ui.swift:23:15:23:34 | SSA def(hasher) | ui.swift:23:5:23:43 | hasher[return] |
1000+
| ui.swift:23:15:23:34 | hasher | ui.swift:23:15:23:34 | SSA def(hasher) |
1001+
| ui.swift:26:8:26:8 | SSA def(self) | ui.swift:26:8:26:8 | self[return] |
1002+
| ui.swift:26:8:26:8 | self | ui.swift:26:8:26:8 | SSA def(self) |
1003+
| ui.swift:28:7:28:7 | SSA def(self) | ui.swift:28:7:28:7 | self[return] |
1004+
| ui.swift:28:7:28:7 | SSA def(self) | ui.swift:28:7:28:7 | self[return] |
1005+
| ui.swift:28:7:28:7 | self | ui.swift:28:7:28:7 | SSA def(self) |
1006+
| ui.swift:28:7:28:7 | self | ui.swift:28:7:28:7 | SSA def(self) |
1007+
| ui.swift:30:7:30:7 | SSA def(self) | ui.swift:30:7:30:7 | self[return] |
1008+
| ui.swift:30:7:30:7 | SSA def(self) | ui.swift:30:7:30:7 | self[return] |
1009+
| ui.swift:30:7:30:7 | self | ui.swift:30:7:30:7 | SSA def(self) |
1010+
| ui.swift:30:7:30:7 | self | ui.swift:30:7:30:7 | SSA def(self) |
1011+
| ui.swift:31:11:31:11 | SSA def(self) | ui.swift:31:11:31:11 | self[return] |
1012+
| ui.swift:31:11:31:11 | SSA def(self) | ui.swift:31:11:31:11 | self[return] |
1013+
| ui.swift:31:11:31:11 | self | ui.swift:31:11:31:11 | SSA def(self) |
1014+
| ui.swift:31:11:31:11 | self | ui.swift:31:11:31:11 | SSA def(self) |
1015+
| ui.swift:32:13:32:13 | self | ui.swift:32:13:32:13 | SSA def(self) |
1016+
| ui.swift:32:13:32:13 | self | ui.swift:32:13:32:13 | SSA def(self) |
1017+
| ui.swift:32:13:32:13 | self | ui.swift:32:13:32:13 | SSA def(self) |
1018+
| ui.swift:32:13:32:13 | value | ui.swift:32:13:32:13 | SSA def(value) |
1019+
| ui.swift:33:13:33:13 | self | ui.swift:33:13:33:13 | SSA def(self) |
1020+
| ui.swift:33:13:33:13 | self | ui.swift:33:13:33:13 | SSA def(self) |
1021+
| ui.swift:33:13:33:13 | self | ui.swift:33:13:33:13 | SSA def(self) |
1022+
| ui.swift:33:13:33:13 | value | ui.swift:33:13:33:13 | SSA def(value) |
1023+
| ui.swift:34:13:34:13 | self | ui.swift:34:13:34:13 | SSA def(self) |
1024+
| ui.swift:34:13:34:13 | self | ui.swift:34:13:34:13 | SSA def(self) |
1025+
| ui.swift:34:13:34:13 | self | ui.swift:34:13:34:13 | SSA def(self) |
1026+
| ui.swift:34:13:34:13 | value | ui.swift:34:13:34:13 | SSA def(value) |
1027+
| ui.swift:35:13:35:13 | self | ui.swift:35:13:35:13 | SSA def(self) |
1028+
| ui.swift:35:13:35:13 | self | ui.swift:35:13:35:13 | SSA def(self) |
1029+
| ui.swift:35:13:35:13 | self | ui.swift:35:13:35:13 | SSA def(self) |
1030+
| ui.swift:35:13:35:13 | value | ui.swift:35:13:35:13 | SSA def(value) |
1031+
| ui.swift:36:13:36:13 | self | ui.swift:36:13:36:13 | SSA def(self) |
1032+
| ui.swift:36:13:36:13 | self | ui.swift:36:13:36:13 | SSA def(self) |
1033+
| ui.swift:36:13:36:13 | self | ui.swift:36:13:36:13 | SSA def(self) |
1034+
| ui.swift:36:13:36:13 | value | ui.swift:36:13:36:13 | SSA def(value) |
1035+
| ui.swift:37:13:37:13 | self | ui.swift:37:13:37:13 | SSA def(self) |
1036+
| ui.swift:37:13:37:13 | self | ui.swift:37:13:37:13 | SSA def(self) |
1037+
| ui.swift:37:13:37:13 | self | ui.swift:37:13:37:13 | SSA def(self) |
1038+
| ui.swift:37:13:37:13 | value | ui.swift:37:13:37:13 | SSA def(value) |
1039+
| ui.swift:38:13:38:13 | self | ui.swift:38:13:38:13 | SSA def(self) |
1040+
| ui.swift:38:13:38:13 | self | ui.swift:38:13:38:13 | SSA def(self) |
1041+
| ui.swift:38:13:38:13 | self | ui.swift:38:13:38:13 | SSA def(self) |
1042+
| ui.swift:38:13:38:13 | value | ui.swift:38:13:38:13 | SSA def(value) |
1043+
| ui.swift:41:11:41:11 | SSA def(self) | ui.swift:41:11:41:11 | self[return] |
1044+
| ui.swift:41:11:41:11 | SSA def(self) | ui.swift:41:11:41:11 | self[return] |
1045+
| ui.swift:41:11:41:11 | self | ui.swift:41:11:41:11 | SSA def(self) |
1046+
| ui.swift:41:11:41:11 | self | ui.swift:41:11:41:11 | SSA def(self) |
1047+
| ui.swift:50:9:50:9 | SSA def(safe) | ui.swift:53:10:53:10 | safe |
1048+
| ui.swift:50:16:50:33 | call to UIOpenURLContext.init() | ui.swift:50:9:50:9 | SSA def(safe) |
1049+
| ui.swift:51:9:51:9 | SSA def(tainted) | ui.swift:55:10:55:10 | tainted |
1050+
| ui.swift:51:19:51:26 | call to source() | ui.swift:51:9:51:9 | SSA def(tainted) |
1051+
| ui.swift:53:10:53:10 | [post] safe | ui.swift:54:10:54:10 | safe |
1052+
| ui.swift:53:10:53:10 | safe | ui.swift:53:10:53:15 | .url |
1053+
| ui.swift:53:10:53:10 | safe | ui.swift:54:10:54:10 | safe |
1054+
| ui.swift:55:10:55:10 | [post] tainted | ui.swift:56:10:56:10 | tainted |
1055+
| ui.swift:55:10:55:10 | tainted | ui.swift:55:10:55:18 | .url |
1056+
| ui.swift:55:10:55:10 | tainted | ui.swift:56:10:56:10 | tainted |
1057+
| ui.swift:60:9:60:9 | SSA def(safe) | ui.swift:63:10:63:10 | safe |
1058+
| ui.swift:60:16:60:42 | call to UIScene.ConnectionOptions.init() | ui.swift:60:9:60:9 | SSA def(safe) |
1059+
| ui.swift:61:9:61:9 | SSA def(tainted) | ui.swift:64:10:64:10 | tainted |
1060+
| ui.swift:61:19:61:26 | call to source() | ui.swift:61:9:61:9 | SSA def(tainted) |
1061+
| ui.swift:63:10:63:10 | [post] safe | ui.swift:65:10:65:10 | safe |
1062+
| ui.swift:63:10:63:10 | safe | ui.swift:63:10:63:15 | .userActivities |
1063+
| ui.swift:63:10:63:10 | safe | ui.swift:65:10:65:10 | safe |
1064+
| ui.swift:64:10:64:10 | [post] tainted | ui.swift:66:10:66:10 | tainted |
1065+
| ui.swift:64:10:64:10 | tainted | ui.swift:64:10:64:18 | .userActivities |
1066+
| ui.swift:64:10:64:10 | tainted | ui.swift:66:10:66:10 | tainted |
1067+
| ui.swift:65:10:65:10 | [post] safe | ui.swift:67:10:67:10 | safe |
1068+
| ui.swift:65:10:65:10 | safe | ui.swift:67:10:67:10 | safe |
1069+
| ui.swift:66:10:66:10 | [post] tainted | ui.swift:68:10:68:10 | tainted |
1070+
| ui.swift:66:10:66:10 | tainted | ui.swift:68:10:68:10 | tainted |
1071+
| ui.swift:67:10:67:10 | [post] safe | ui.swift:69:10:69:10 | safe |
1072+
| ui.swift:67:10:67:10 | safe | ui.swift:67:10:67:15 | .urlContexts |
1073+
| ui.swift:67:10:67:10 | safe | ui.swift:69:10:69:10 | safe |
1074+
| ui.swift:68:10:68:10 | [post] tainted | ui.swift:70:10:70:10 | tainted |
1075+
| ui.swift:68:10:68:10 | tainted | ui.swift:68:10:68:18 | .urlContexts |
1076+
| ui.swift:68:10:68:10 | tainted | ui.swift:70:10:70:10 | tainted |
1077+
| ui.swift:69:10:69:10 | [post] safe | ui.swift:71:10:71:10 | safe |
1078+
| ui.swift:69:10:69:10 | safe | ui.swift:71:10:71:10 | safe |
1079+
| ui.swift:70:10:70:10 | [post] tainted | ui.swift:72:10:72:10 | tainted |
1080+
| ui.swift:70:10:70:10 | tainted | ui.swift:72:10:72:10 | tainted |
1081+
| ui.swift:71:10:71:10 | [post] safe | ui.swift:73:10:73:10 | safe |
1082+
| ui.swift:71:10:71:10 | safe | ui.swift:73:10:73:10 | safe |
1083+
| ui.swift:72:10:72:10 | [post] tainted | ui.swift:74:10:74:10 | tainted |
1084+
| ui.swift:72:10:72:10 | tainted | ui.swift:74:10:74:10 | tainted |
1085+
| ui.swift:73:10:73:10 | [post] safe | ui.swift:75:10:75:10 | safe |
1086+
| ui.swift:73:10:73:10 | safe | ui.swift:75:10:75:10 | safe |
1087+
| ui.swift:74:10:74:10 | [post] tainted | ui.swift:76:10:76:10 | tainted |
1088+
| ui.swift:74:10:74:10 | tainted | ui.swift:76:10:76:10 | tainted |
9671089
| url.swift:2:7:2:7 | SSA def(self) | url.swift:2:7:2:7 | self[return] |
9681090
| url.swift:2:7:2:7 | SSA def(self) | url.swift:2:7:2:7 | self[return] |
9691091
| url.swift:2:7:2:7 | self | url.swift:2:7:2:7 | SSA def(self) |

0 commit comments

Comments
 (0)