Skip to content

Commit 8170154

Browse files
committed
Add taint sources for WKScriptMessage
This is what contains externally-provided data in Webview JS-native bridges
1 parent 142e500 commit 8170154

File tree

7 files changed

+62
-0
lines changed

7 files changed

+62
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ private module Frameworks {
8282
private import codeql.swift.frameworks.StandardLibrary.String
8383
private import codeql.swift.frameworks.StandardLibrary.Url
8484
private import codeql.swift.frameworks.StandardLibrary.UrlSession
85+
private import codeql.swift.frameworks.StandardLibrary.WebView
8586
}
8687

8788
/**
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import swift
2+
private import codeql.swift.dataflow.DataFlow
3+
private import codeql.swift.dataflow.ExternalFlow
4+
private import codeql.swift.dataflow.FlowSources
5+
private import codeql.swift.dataflow.FlowSteps
6+
7+
private class WKScriptMessageSource extends SourceModelCsv {
8+
override predicate row(string row) {
9+
row = ";WKScriptMessageHandler;true;userContentController(_:didReceive:);;;Parameter[1];remote"
10+
}
11+
}
12+
13+
/** The class `WKScriptMessage`. */
14+
private class WKScriptMessageDecl extends ClassDecl {
15+
WKScriptMessageDecl() { this.getName() = "WKScriptMessage" }
16+
}
17+
18+
/**
19+
* A content implying that, if a `WKScriptMessage` is tainted, its `body` field is tainted.
20+
*/
21+
private class WKScriptMessageBodyInheritsTaint extends TaintInheritingContent,
22+
DataFlow::Content::FieldContent {
23+
WKScriptMessageBodyInheritsTaint() {
24+
exists(FieldDecl f | this.getField() = f |
25+
f.getEnclosingDecl() instanceof WKScriptMessageDecl and
26+
f.getName() = "body"
27+
)
28+
}
29+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
| url.swift:53:15:53:19 | .resourceBytes | external |
99
| url.swift:60:15:60:19 | .lines | external |
1010
| url.swift:67:16:67:22 | .lines | external |
11+
| webview.swift:11:82:11:102 | message | external |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
// --- stubs ---
3+
class WKUserContentController {}
4+
class WKScriptMessage {}
5+
protocol WKScriptMessageHandler {
6+
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
7+
}
8+
9+
// --- tests ---
10+
class TestMessageHandler: WKScriptMessageHandler {
11+
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { // SOURCE
12+
}
13+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,4 @@
161161
| url.swift:100:12:100:54 | ...! | url.swift:100:12:100:56 | .standardizedFileURL |
162162
| url.swift:101:15:101:57 | ...! | url.swift:101:15:101:59 | .user |
163163
| url.swift:102:15:102:57 | ...! | url.swift:102:15:102:59 | .password |
164+
| webview.swift:12:13:12:20 | call to source() | webview.swift:12:13:12:22 | .body |

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ edges
119119
| url.swift:117:28:117:28 | tainted : | url.swift:117:16:117:35 | call to init(string:) : |
120120
| url.swift:120:46:120:46 | urlTainted : | url.swift:43:2:46:55 | [summary param] 0 in dataTask(with:completionHandler:) : |
121121
| url.swift:120:61:120:61 | data : | url.swift:121:15:121:19 | ...! |
122+
| webview.swift:12:13:12:20 | call to source() : | webview.swift:12:13:12:22 | .body |
122123
nodes
123124
| 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:) : |
124125
| file://:0:0:0:0 | [summary] to write: return (return) in init(string:) : | semmle.label | [summary] to write: return (return) in init(string:) : |
@@ -231,6 +232,8 @@ nodes
231232
| url.swift:120:46:120:46 | urlTainted : | semmle.label | urlTainted : |
232233
| url.swift:120:61:120:61 | data : | semmle.label | data : |
233234
| url.swift:121:15:121:19 | ...! | semmle.label | ...! |
235+
| webview.swift:12:13:12:20 | call to source() : | semmle.label | call to source() : |
236+
| webview.swift:12:13:12:22 | .body | semmle.label | .body |
234237
subpaths
235238
| url.swift:59:31:59: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:59:19:59:38 | call to init(string:) : |
236239
| url.swift:83:24:83:24 | tainted : | url.swift:9:2:9:43 | [summary param] 0 in init(string:relativeTo:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(string:relativeTo:) : | url.swift:83:12:83:48 | call to init(string:relativeTo:) : |
@@ -306,3 +309,4 @@ subpaths
306309
| url.swift:102:15:102:67 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:102:15:102:67 | ...! | result |
307310
| url.swift:118:12:118:12 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:118:12:118:12 | ...! | result |
308311
| url.swift:121:15:121:19 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:121:15:121:19 | ...! | result |
312+
| webview.swift:12:13:12:22 | .body | webview.swift:12:13:12:20 | call to source() : | webview.swift:12:13:12:22 | .body | result |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
// --- stubs ---
3+
class WKScriptMessage {
4+
open var body: Any { get { return "" } }
5+
}
6+
7+
// --- tests ---
8+
func source() -> WKScriptMessage { return WKScriptMessage() }
9+
func sink(s: Any) {}
10+
11+
func testInheritBodyTaint() {
12+
sink(s: source().body) // $ tainted=12
13+
}

0 commit comments

Comments
 (0)