Skip to content

Commit 2593120

Browse files
authored
Merge pull request #10597 from geoffw0/swifttaintsource
Swift: URL taint sources
2 parents 42a97b2 + 1fb54ad commit 2593120

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-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
@@ -79,6 +79,7 @@ private import internal.FlowSummaryImplSpecific
7979
*/
8080
private module Frameworks {
8181
private import codeql.swift.frameworks.StandardLibrary.String
82+
private import codeql.swift.frameworks.StandardLibrary.Url
8283
}
8384

8485
/**
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import swift
2+
private import codeql.swift.dataflow.FlowSources
3+
4+
/**
5+
* A model for `URL` members that are sources of remote flow.
6+
*/
7+
class UrlRemoteFlowSource extends RemoteFlowSource {
8+
UrlRemoteFlowSource() {
9+
exists(StructDecl urlClass, ConcreteVarDecl memberDecl |
10+
urlClass.getName() = "URL" and
11+
(
12+
urlClass.getAMember() = memberDecl and
13+
memberDecl.getName() = ["resourceBytes", "lines"]
14+
or
15+
exists(StructDecl asyncBytesClass |
16+
urlClass.getAMember() = asyncBytesClass and
17+
asyncBytesClass.getName() = "AsyncBytes" and
18+
asyncBytesClass.getAMember() = memberDecl and
19+
memberDecl.getName() = "lines"
20+
)
21+
) and
22+
this.asExpr().(MemberRefExpr).getMember() = memberDecl
23+
)
24+
}
25+
26+
override string getSourceType() { result = "external" }
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| string.swift:27:21:27:21 | call to init(contentsOf:) | external |
2+
| string.swift:27:21:27:44 | call to init(contentsOf:) | external |
3+
| url.swift:53:15:53:19 | .resourceBytes | external |
4+
| url.swift:60:15:60:19 | .lines | external |
5+
| url.swift:67:16:67:22 | .lines | external |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import swift
2+
import codeql.swift.dataflow.FlowSources
3+
4+
from RemoteFlowSource source
5+
select source, concat(source.getSourceType(), ", ")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
// --- stubs ---
3+
4+
struct URL
5+
{
6+
init?(string: String) {}
7+
}
8+
9+
extension String {
10+
init(contentsOf: URL) throws {
11+
var data = ""
12+
13+
// ...
14+
15+
self.init(data)
16+
}
17+
}
18+
19+
// --- tests ---
20+
21+
func testStrings() {
22+
do
23+
{
24+
let string1 = String()
25+
let string2 = String(repeating: "abc", count: 10)
26+
let url = URL(string: "http://example.com/")
27+
let string3 = try String(contentsOf: url!) // SOURCE
28+
} catch {
29+
// ...
30+
}
31+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// --- stubs ---
2+
3+
struct URL {
4+
init?(string: String) {}
5+
6+
struct AsyncBytes : AsyncSequence, AsyncIteratorProtocol {
7+
typealias Element = UInt8
8+
9+
func makeAsyncIterator() -> AsyncBytes {
10+
return AsyncBytes()
11+
}
12+
13+
mutating func next() async -> Element? { return nil }
14+
15+
var lines: AsyncLineSequence<Self> {
16+
get {
17+
return AsyncLineSequence<Self>()
18+
}
19+
}
20+
}
21+
22+
var resourceBytes: URL.AsyncBytes {
23+
get {
24+
return AsyncBytes()
25+
}
26+
}
27+
28+
struct AsyncLineSequence<Base> : AsyncSequence, AsyncIteratorProtocol where Base : AsyncSequence, Base.Element == UInt8 {
29+
typealias Element = String
30+
31+
func makeAsyncIterator() -> AsyncLineSequence<Base> {
32+
return AsyncLineSequence<Base>()
33+
}
34+
35+
mutating func next() async -> Element? { return nil }
36+
}
37+
38+
var lines: AsyncLineSequence<URL.AsyncBytes> {
39+
get {
40+
return AsyncLineSequence<URL.AsyncBytes>()
41+
}
42+
}
43+
}
44+
45+
func print(_ items: Any...) {}
46+
47+
// --- tests ---
48+
49+
func testURLs() async {
50+
do
51+
{
52+
let url = URL(string: "http://example.com/")!
53+
let bytes = url.resourceBytes // SOURCE
54+
55+
for try await byte in bytes
56+
{
57+
print(byte)
58+
}
59+
60+
let lines = url.lines // SOURCE
61+
62+
for try await line in lines
63+
{
64+
print(line)
65+
}
66+
67+
let lines2 = bytes.lines // SOURCE
68+
69+
for try await line in lines2
70+
{
71+
print(line)
72+
}
73+
} catch {
74+
// ...
75+
}
76+
}

0 commit comments

Comments
 (0)