Skip to content

Commit 1edd4d8

Browse files
committed
Swift: Add an example with flow through a callback function.
1 parent 197f036 commit 1edd4d8

File tree

5 files changed

+111
-32
lines changed

5 files changed

+111
-32
lines changed

swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ private import internal.FlowSummaryImplSpecific
8080
private module Frameworks {
8181
private import codeql.swift.frameworks.StandardLibrary.String
8282
private import codeql.swift.frameworks.StandardLibrary.Url
83+
private import codeql.swift.frameworks.StandardLibrary.UrlSession
8384
}
8485

8586
/**
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
private import codeql.swift.dataflow.ExternalFlow
2+
3+
private class UrlSessionSummaries extends SummaryModelCsv {
4+
override predicate row(string row) {
5+
row =
6+
";URLSession;true;dataTask(with:completionHandler:);;;Argument[0];Argument[1].Parameter[0];taint"
7+
}
8+
}

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,17 @@
123123
| string.swift:39:13:39:19 | ... .+(_:_:) ... | string.swift:39:13:39:29 | ... .+(_:_:) ... |
124124
| string.swift:39:19:39:19 | tainted | string.swift:39:13:39:19 | ... .+(_:_:) ... |
125125
| string.swift:39:29:39:29 | < | string.swift:39:13:39:29 | ... .+(_:_:) ... |
126-
| url.swift:14:29:14:29 | clean | url.swift:14:17:14:34 | call to init(string:) |
127-
| url.swift:15:31:15:31 | tainted | url.swift:15:19:15:38 | call to init(string:) |
128-
| url.swift:20:24:20:24 | clean | url.swift:20:12:20:46 | call to init(string:relativeTo:) |
129-
| url.swift:20:43:20:43 | nil | url.swift:20:12:20:46 | call to init(string:relativeTo:) |
130-
| url.swift:21:24:21:24 | tainted | url.swift:21:12:21:48 | call to init(string:relativeTo:) |
131-
| url.swift:21:45:21:45 | nil | url.swift:21:12:21:48 | call to init(string:relativeTo:) |
132-
| url.swift:22:24:22:24 | clean | url.swift:22:12:22:51 | call to init(string:relativeTo:) |
133-
| url.swift:22:43:22:43 | urlClean | url.swift:22:12:22:51 | call to init(string:relativeTo:) |
134-
| url.swift:23:24:23:24 | clean | url.swift:23:12:23:53 | call to init(string:relativeTo:) |
135-
| url.swift:23:43:23:43 | urlTainted | url.swift:23:12:23:53 | call to init(string:relativeTo:) |
136-
| url.swift:25:25:25:25 | clean | url.swift:25:13:25:30 | call to init(string:) |
137-
| url.swift:29:25:29:25 | tainted | url.swift:29:13:29:32 | call to init(string:) |
138-
| url.swift:34:26:34:26 | clean | url.swift:34:14:34:31 | call to init(string:) |
139-
| url.swift:38:28:38:28 | tainted | url.swift:38:16:38:35 | call to init(string:) |
126+
| url.swift:40:29:40:29 | clean | url.swift:40:17:40:34 | call to init(string:) |
127+
| url.swift:41:31:41:31 | tainted | url.swift:41:19:41:38 | call to init(string:) |
128+
| url.swift:46:24:46:24 | clean | url.swift:46:12:46:46 | call to init(string:relativeTo:) |
129+
| url.swift:46:43:46:43 | nil | url.swift:46:12:46:46 | call to init(string:relativeTo:) |
130+
| url.swift:47:24:47:24 | tainted | url.swift:47:12:47:48 | call to init(string:relativeTo:) |
131+
| url.swift:47:45:47:45 | nil | url.swift:47:12:47:48 | call to init(string:relativeTo:) |
132+
| url.swift:48:24:48:24 | clean | url.swift:48:12:48:51 | call to init(string:relativeTo:) |
133+
| url.swift:48:43:48:43 | urlClean | url.swift:48:12:48:51 | call to init(string:relativeTo:) |
134+
| url.swift:49:24:49:24 | clean | url.swift:49:12:49:53 | call to init(string:relativeTo:) |
135+
| url.swift:49:43:49:43 | urlTainted | url.swift:49:12:49:53 | call to init(string:relativeTo:) |
136+
| url.swift:51:25:51:25 | clean | url.swift:51:13:51:30 | call to init(string:) |
137+
| url.swift:55:25:55:25 | tainted | url.swift:55:13:55:32 | call to init(string:) |
138+
| url.swift:60:26:60:26 | clean | url.swift:60:14:60:31 | call to init(string:) |
139+
| url.swift:64:28:64:28 | tainted | url.swift:64:16:64:35 | call to init(string:) |

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

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
edges
2+
| file://:0:0:0:0 | [summary] to write: argument 1.parameter 0 in dataTask(with:completionHandler:) : | url.swift:67:61:67:61 | data : |
23
| string.swift:5:11:5:18 | call to source() : | string.swift:7:13:7:13 | "..." |
34
| string.swift:5:11:5:18 | call to source() : | string.swift:9:13:9:13 | "..." |
45
| string.swift:5:11:5:18 | call to source() : | string.swift:11:13:11:13 | "..." |
@@ -12,11 +13,34 @@ edges
1213
| try.swift:9:17:9:24 | call to source() : | try.swift:9:13:9:24 | try ... |
1314
| try.swift:15:17:15:24 | call to source() : | try.swift:15:12:15:24 | try! ... |
1415
| try.swift:18:18:18:25 | call to source() : | try.swift:18:12:18:27 | ...! |
15-
| url.swift:13:16:13:23 | call to source() : | url.swift:18:12:18:12 | urlTainted |
16-
| url.swift:13:16:13:23 | call to source() : | url.swift:21:12:21:49 | ...! |
17-
| url.swift:13:16:13:23 | call to source() : | url.swift:23:12:23:54 | ...! |
18-
| url.swift:13:16:13:23 | call to source() : | url.swift:39:12:39:12 | ...! |
16+
| url.swift:8:2:8:25 | [summary param] 0 in init(string:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : |
17+
| url.swift:8:8:8:16 | string : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : |
18+
| url.swift:26:2:29:55 | [summary param] 0 in dataTask(with:completionHandler:) : | file://:0:0:0:0 | [summary] to write: argument 1.parameter 0 in dataTask(with:completionHandler:) : |
19+
| url.swift:27:5:27:15 | url : | file://:0:0:0:0 | [summary] to write: argument 1.parameter 0 in dataTask(with:completionHandler:) : |
20+
| url.swift:39:16:39:23 | call to source() : | url.swift:41:31:41:31 | tainted : |
21+
| url.swift:39:16:39:23 | call to source() : | url.swift:44:12:44:12 | urlTainted |
22+
| url.swift:39:16:39:23 | call to source() : | url.swift:47:12:47:49 | ...! |
23+
| url.swift:39:16:39:23 | call to source() : | url.swift:49:12:49:54 | ...! |
24+
| url.swift:39:16:39:23 | call to source() : | url.swift:64:28:64:28 | tainted : |
25+
| url.swift:39:16:39:23 | call to source() : | url.swift:65:12:65:12 | ...! |
26+
| url.swift:39:16:39:23 | call to source() : | url.swift:67:46:67:46 | urlTainted : |
27+
| url.swift:41:19:41:38 | call to init(string:) : | url.swift:44:12:44:12 | urlTainted |
28+
| url.swift:41:19:41:38 | call to init(string:) : | url.swift:49:12:49:54 | ...! |
29+
| url.swift:41:19:41:38 | call to init(string:) : | url.swift:67:46:67:46 | urlTainted : |
30+
| url.swift:41:31:41:31 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in init(string:) : |
31+
| url.swift:41:31:41:31 | tainted : | url.swift:8:8:8:16 | string : |
32+
| url.swift:41:31:41:31 | tainted : | url.swift:41:19:41:38 | call to init(string:) : |
33+
| url.swift:64:16:64:35 | call to init(string:) : | url.swift:65:12:65:12 | ...! |
34+
| url.swift:64:28:64:28 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in init(string:) : |
35+
| url.swift:64:28:64:28 | tainted : | url.swift:8:8:8:16 | string : |
36+
| url.swift:64:28:64:28 | tainted : | url.swift:64:16:64:35 | call to init(string:) : |
37+
| url.swift:67:46:67:46 | urlTainted : | url.swift:26:2:29:55 | [summary param] 0 in dataTask(with:completionHandler:) : |
38+
| url.swift:67:46:67:46 | urlTainted : | url.swift:27:5:27:15 | url : |
39+
| url.swift:67:61:67:61 | data : | url.swift:68:15:68:19 | ...! |
1940
nodes
41+
| file://:0:0:0:0 | [summary] to write: argument 1.parameter 0 in dataTask(with:completionHandler:) : | semmle.label | [summary] to write: argument 1.parameter 0 in dataTask(with:completionHandler:) : |
42+
| file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | semmle.label | [summary] to write: return (return) in init(string:) : |
43+
| file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | semmle.label | [summary] to write: return (return) in init(string:) : |
2044
| string.swift:5:11:5:18 | call to source() : | semmle.label | call to source() : |
2145
| string.swift:7:13:7:13 | "..." | semmle.label | "..." |
2246
| string.swift:9:13:9:13 | "..." | semmle.label | "..." |
@@ -35,12 +59,27 @@ nodes
3559
| try.swift:15:17:15:24 | call to source() : | semmle.label | call to source() : |
3660
| try.swift:18:12:18:27 | ...! | semmle.label | ...! |
3761
| try.swift:18:18:18:25 | call to source() : | semmle.label | call to source() : |
38-
| url.swift:13:16:13:23 | call to source() : | semmle.label | call to source() : |
39-
| url.swift:18:12:18:12 | urlTainted | semmle.label | urlTainted |
40-
| url.swift:21:12:21:49 | ...! | semmle.label | ...! |
41-
| url.swift:23:12:23:54 | ...! | semmle.label | ...! |
42-
| url.swift:39:12:39:12 | ...! | semmle.label | ...! |
62+
| url.swift:8:2:8:25 | [summary param] 0 in init(string:) : | semmle.label | [summary param] 0 in init(string:) : |
63+
| url.swift:8:8:8:16 | string : | semmle.label | string : |
64+
| url.swift:26:2:29:55 | [summary param] 0 in dataTask(with:completionHandler:) : | semmle.label | [summary param] 0 in dataTask(with:completionHandler:) : |
65+
| url.swift:27:5:27:15 | url : | semmle.label | url : |
66+
| url.swift:39:16:39:23 | call to source() : | semmle.label | call to source() : |
67+
| url.swift:41:19:41:38 | call to init(string:) : | semmle.label | call to init(string:) : |
68+
| url.swift:41:31:41:31 | tainted : | semmle.label | tainted : |
69+
| url.swift:44:12:44:12 | urlTainted | semmle.label | urlTainted |
70+
| url.swift:47:12:47:49 | ...! | semmle.label | ...! |
71+
| url.swift:49:12:49:54 | ...! | semmle.label | ...! |
72+
| url.swift:64:16:64:35 | call to init(string:) : | semmle.label | call to init(string:) : |
73+
| url.swift:64:28:64:28 | tainted : | semmle.label | tainted : |
74+
| url.swift:65:12:65:12 | ...! | semmle.label | ...! |
75+
| url.swift:67:46:67:46 | urlTainted : | semmle.label | urlTainted : |
76+
| url.swift:67:61:67:61 | data : | semmle.label | data : |
77+
| url.swift:68:15:68:19 | ...! | semmle.label | ...! |
4378
subpaths
79+
| url.swift:41:31:41:31 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in init(string:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | url.swift:41:19:41:38 | call to init(string:) : |
80+
| url.swift:41:31:41:31 | tainted : | url.swift:8:8:8:16 | string : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | url.swift:41:19:41:38 | call to init(string:) : |
81+
| url.swift:64:28:64:28 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in init(string:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | url.swift:64:16:64:35 | call to init(string:) : |
82+
| url.swift:64:28:64:28 | tainted : | url.swift:8:8:8:16 | string : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | url.swift:64:16:64:35 | call to init(string:) : |
4483
#select
4584
| string.swift:7:13:7:13 | "..." | string.swift:5:11:5:18 | call to source() : | string.swift:7:13:7:13 | "..." | result |
4685
| string.swift:9:13:9:13 | "..." | string.swift:5:11:5:18 | call to source() : | string.swift:9:13:9:13 | "..." | result |
@@ -55,7 +94,8 @@ subpaths
5594
| try.swift:9:13:9:24 | try ... | try.swift:9:17:9:24 | call to source() : | try.swift:9:13:9:24 | try ... | result |
5695
| try.swift:15:12:15:24 | try! ... | try.swift:15:17:15:24 | call to source() : | try.swift:15:12:15:24 | try! ... | result |
5796
| try.swift:18:12:18:27 | ...! | try.swift:18:18:18:25 | call to source() : | try.swift:18:12:18:27 | ...! | result |
58-
| url.swift:18:12:18:12 | urlTainted | url.swift:13:16:13:23 | call to source() : | url.swift:18:12:18:12 | urlTainted | result |
59-
| url.swift:21:12:21:49 | ...! | url.swift:13:16:13:23 | call to source() : | url.swift:21:12:21:49 | ...! | result |
60-
| url.swift:23:12:23:54 | ...! | url.swift:13:16:13:23 | call to source() : | url.swift:23:12:23:54 | ...! | result |
61-
| url.swift:39:12:39:12 | ...! | url.swift:13:16:13:23 | call to source() : | url.swift:39:12:39:12 | ...! | result |
97+
| url.swift:44:12:44:12 | urlTainted | url.swift:39:16:39:23 | call to source() : | url.swift:44:12:44:12 | urlTainted | result |
98+
| url.swift:47:12:47:49 | ...! | url.swift:39:16:39:23 | call to source() : | url.swift:47:12:47:49 | ...! | result |
99+
| url.swift:49:12:49:54 | ...! | url.swift:39:16:39:23 | call to source() : | url.swift:49:12:49:54 | ...! | result |
100+
| url.swift:65:12:65:12 | ...! | url.swift:39:16:39:23 | call to source() : | url.swift:65:12:65:12 | ...! | result |
101+
| url.swift:68:15:68:19 | ...! | url.swift:39:16:39:23 | call to source() : | url.swift:68:15:68:19 | ...! | result |
Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
11

2+
class NSObject
3+
{
4+
}
5+
26
struct URL
37
{
48
init?(string: String) {}
59
init?(string: String, relativeTo: URL?) {}
610
}
711

12+
class Data
13+
{
14+
init<S>(_ elements: S) {}
15+
}
16+
17+
class URLResponse : NSObject {}
18+
19+
class URLSessionTask : NSObject { }
20+
21+
class URLSessionDataTask : URLSessionTask { }
22+
23+
class URLSession {
24+
class var shared: URLSession { get { return URLSession() } }
25+
26+
func dataTask(
27+
with url: URL,
28+
completionHandler: (Data?, URLResponse?, Error?) -> Void
29+
) -> URLSessionDataTask { return URLSessionDataTask() }
30+
}
31+
832
func source() -> String { return "" }
933
func sink(arg: URL) {}
34+
func sink(data: Data) {}
35+
func sink(string: String) {}
1036

1137
func taintThroughURL() {
1238
let clean = "http://example.com/"
@@ -15,19 +41,19 @@ func taintThroughURL() {
1541
let urlTainted = URL(string: tainted)!
1642

1743
sink(arg: urlClean)
18-
sink(arg: urlTainted) // $ tainted=13
44+
sink(arg: urlTainted) // $ tainted=39
1945

2046
sink(arg: URL(string: clean, relativeTo: nil)!)
21-
sink(arg: URL(string: tainted, relativeTo: nil)!) // $ tainted=13
47+
sink(arg: URL(string: tainted, relativeTo: nil)!) // $ tainted=39
2248
sink(arg: URL(string: clean, relativeTo: urlClean)!)
23-
sink(arg: URL(string: clean, relativeTo: urlTainted)!) // $ tainted=13
49+
sink(arg: URL(string: clean, relativeTo: urlTainted)!) // $ tainted=39
2450

2551
if let x = URL(string: clean) {
2652
sink(arg: x)
2753
}
2854

2955
if let y = URL(string: tainted) {
30-
sink(arg: y) // $ MISSING: tainted=13
56+
sink(arg: y) // $ MISSING: tainted=39
3157
}
3258

3359
var urlClean2 : URL!
@@ -36,5 +62,9 @@ func taintThroughURL() {
3662

3763
var urlTainted2 : URL!
3864
urlTainted2 = URL(string: tainted)
39-
sink(arg: urlTainted2) // $ tainted=13
65+
sink(arg: urlTainted2) // $ tainted=39
66+
67+
let task = URLSession.shared.dataTask(with: urlTainted) { (data, response, error) in
68+
sink(data: data!) // $ tainted=39
69+
}
4070
}

0 commit comments

Comments
 (0)