Skip to content

Commit 1c64fb1

Browse files
authored
Merge pull request github#13756 from geoffw0/sources2
Swift: CustomUrlSchemes test enhancements and minor model improvement
2 parents c4b7824 + 12f2539 commit 1c64fb1

File tree

5 files changed

+123
-14
lines changed

5 files changed

+123
-14
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
5+
* Added taint flow for `NSUserActivity.referrerURL`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ private class UserActivityUrlInheritTaint extends TaintInheritingContent,
8383
{
8484
UserActivityUrlInheritTaint() {
8585
this.getField().getEnclosingDecl().asNominalTypeDecl().getName() = "NSUserActivity" and
86-
this.getField().getName() = "webpageURL"
86+
this.getField().getName() = ["webpageURL", "referrerURL"]
8787
}
8888
}
8989

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
deadEnd
2+
| customurlschemes.swift:94:59:94:76 | options |
3+
| customurlschemes.swift:133:59:133:76 | options |

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
import swift
22
import TestUtilities.InlineExpectationsTest
33
import FlowConfig
4+
import codeql.swift.dataflow.TaintTracking
5+
import codeql.swift.dataflow.DataFlow
6+
7+
module TestConfiguration implements DataFlow::ConfigSig {
8+
predicate isSource(DataFlow::Node src) { src instanceof FlowSource }
9+
10+
predicate isSink(DataFlow::Node sink) {
11+
exists(CallExpr sinkCall |
12+
sinkCall.getStaticTarget().getName().matches("sink%") and
13+
sinkCall.getAnArgument().getExpr() = sink.asExpr()
14+
)
15+
}
16+
}
17+
18+
module TestFlow = TaintTracking::Global<TestConfiguration>;
419

520
string describe(FlowSource source) {
621
source instanceof RemoteFlowSource and result = "remote"
@@ -9,7 +24,7 @@ string describe(FlowSource source) {
924
}
1025

1126
module FlowSourcesTest implements TestSig {
12-
string getARelevantTag() { result = "source" }
27+
string getARelevantTag() { result = ["source", "tainted"] }
1328

1429
predicate hasActualResult(Location location, string element, string tag, string value) {
1530
exists(FlowSource source |
@@ -19,6 +34,16 @@ module FlowSourcesTest implements TestSig {
1934
tag = "source" and
2035
value = describe(source)
2136
)
37+
or
38+
exists(DataFlow::Node sink |
39+
// this is not really what the "flowsources" test is about, but sometimes it's helpful to
40+
// have sinks and confirm that taint reaches obvious points in the flow source test code.
41+
TestFlow::flowTo(sink) and
42+
location = sink.getLocation() and
43+
element = sink.toString() and
44+
tag = "tainted" and
45+
value = ""
46+
)
2247
}
2348
}
2449

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

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,33 @@ protocol UIApplicationDelegate {
2626
}
2727

2828
class UIScene {
29-
class ConnectionOptions {}
29+
class ConnectionOptions {
30+
var userActivities: Set<NSUserActivity> { get { return Set() } }
31+
var urlContexts: Set<UIOpenURLContext> { get { return Set() } }
32+
}
3033
}
3134

3235
class UISceneSession {}
3336

34-
class NSUserActivity {}
37+
class NSUserActivity: Hashable {
38+
static func == (lhs: NSUserActivity, rhs: NSUserActivity) -> Bool {
39+
return true;
40+
}
41+
42+
func hash(into hasher: inout Hasher) {}
43+
44+
var webpageURL: URL? { get { return nil } set { } }
45+
var referrerURL: URL? { get { return nil } set { } }
46+
}
3547

3648
class UIOpenURLContext: Hashable {
3749
static func == (lhs: UIOpenURLContext, rhs: UIOpenURLContext) -> Bool {
3850
return true;
3951
}
4052

4153
func hash(into hasher: inout Hasher) {}
54+
55+
var url: URL { get { return URL() } }
4256
}
4357

4458
protocol UISceneDelegate {
@@ -48,6 +62,8 @@ protocol UISceneDelegate {
4862
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>)
4963
}
5064

65+
func sink(arg: Any) {}
66+
5167
// --- tests ---
5268

5369
class AppDelegate: UIApplicationDelegate {
@@ -64,28 +80,88 @@ class AppDelegate: UIApplicationDelegate {
6480
}
6581

6682
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
67-
launchOptions?[.url] // $ source=remote
83+
_ = launchOptions?[.url] // $ source=remote
6884
return true
6985
}
7086

7187
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
72-
launchOptions?[.url] // $ source=remote
88+
_ = launchOptions?[.url] // $ source=remote
7389
return true
7490
}
7591
}
7692

7793
class SceneDelegate : UISceneDelegate {
78-
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote
79-
func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote
80-
func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote
81-
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) {} // $ source=remote
94+
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
95+
for userActivity in options.userActivities {
96+
let x = userActivity.webpageURL
97+
sink(arg: x) // $ MISSING: tainted
98+
let y = userActivity.referrerURL
99+
sink(arg: y) // $ MISSING: tainted
100+
}
101+
102+
for urlContext in options.urlContexts {
103+
let z = urlContext.url
104+
sink(arg: z) // $ MISSING: tainted
105+
}
106+
}
107+
108+
func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
109+
let x = `continue`.webpageURL
110+
sink(arg: x) // $ tainted
111+
let y = `continue`.referrerURL
112+
sink(arg: y) // $ tainted
113+
}
114+
115+
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
116+
let x = didUpdate.webpageURL
117+
sink(arg: x) // $ tainted
118+
let y = didUpdate.referrerURL
119+
sink(arg: y) // $ tainted
120+
}
121+
122+
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) { // $ source=remote
123+
for openURLContext in openURLContexts {
124+
let x = openURLContext.url
125+
sink(arg: x) // $ MISSING: tainted
126+
}
127+
}
82128
}
83129

84130
class Extended {}
85131

86132
extension Extended : UISceneDelegate {
87-
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote
88-
func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote
89-
func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote
90-
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) {} // $ source=remote
133+
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
134+
for userActivity in options.userActivities {
135+
let x = userActivity.webpageURL
136+
sink(arg: x) // $ MISSING: tainted
137+
let y = userActivity.referrerURL
138+
sink(arg: y) // $ MISSING: tainted
139+
}
140+
141+
for urlContext in options.urlContexts {
142+
let z = urlContext.url
143+
sink(arg: z) // $ MISSING: tainted
144+
}
145+
}
146+
147+
func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
148+
let x = `continue`.webpageURL
149+
sink(arg: x) // $ tainted
150+
let y = `continue`.referrerURL
151+
sink(arg: y) // $ tainted
152+
}
153+
154+
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
155+
let x = didUpdate.webpageURL
156+
sink(arg: x) // $ tainted
157+
let y = didUpdate.referrerURL
158+
sink(arg: y) // $ tainted
159+
}
160+
161+
func scene(_: UIScene, openURLContexts: Set<UIOpenURLContext>) { // $ source=remote
162+
for openURLContext in openURLContexts {
163+
let x = openURLContext.url
164+
sink(arg: x) // $ MISSING: tainted
165+
}
166+
}
91167
}

0 commit comments

Comments
 (0)