Skip to content

Commit d37ed02

Browse files
committed
Swift: basic Data-related taint flow in query
Still TODO: a more comprehensive taint flow model for Data in the libs.
1 parent 66291d3 commit d37ed02

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

swift/ql/src/queries/Security/CWE-094/UnsafeJsEval.ql

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ class UnsafeJsEvalConfig extends TaintTracking::Configuration {
108108
])
109109
).getArgument(0)
110110
or
111+
arg =
112+
any(CallExpr ce | ce.getStaticTarget().(MethodDecl).hasQualifiedName("Data", "init(_:)"))
113+
.getArgument(0)
114+
or
115+
arg =
116+
any(CallExpr ce |
117+
ce.getStaticTarget().(MethodDecl).hasQualifiedName("String", "init(decoding:as:)")
118+
).getArgument(0)
119+
or
111120
arg =
112121
any(CallExpr ce |
113122
ce.getStaticTarget()
@@ -135,10 +144,10 @@ class UnsafeJsEvalConfig extends TaintTracking::Configuration {
135144
or
136145
exists(MemberRefExpr e, Expr self, VarDecl member |
137146
self.getType().getName() = "String" and
138-
member.getName() = ["utf16", "utf8CString"]
147+
member.getName() = ["utf8", "utf16", "utf8CString"]
139148
or
140149
self.getType().getName().matches(["Unsafe%Buffer%", "Unsafe%Pointer%"]) and
141-
member.getName() = ["baseAddress"]
150+
member.getName() = "baseAddress"
142151
|
143152
e.getBase() = self and
144153
e.getMember() = member and

swift/ql/test/query-tests/Security/CWE-094/UnsafeJsEval.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edges
55
| UnsafeJsEval.swift:164:14:164:37 | call to init(contentsOf:) : | UnsafeJsEval.swift:164:10:164:37 | try ... : |
66
| UnsafeJsEval.swift:200:21:200:35 | call to getRemoteData() : | UnsafeJsEval.swift:204:7:204:7 | remoteString : |
77
| UnsafeJsEval.swift:200:21:200:35 | call to getRemoteData() : | UnsafeJsEval.swift:207:7:207:39 | ... .+(_:_:) ... : |
8+
| UnsafeJsEval.swift:200:21:200:35 | call to getRemoteData() : | UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : |
89
| UnsafeJsEval.swift:203:7:203:21 | call to getRemoteData() : | UnsafeJsEval.swift:264:13:264:13 | string : |
910
| UnsafeJsEval.swift:203:7:203:21 | call to getRemoteData() : | UnsafeJsEval.swift:267:13:267:13 | string : |
1011
| UnsafeJsEval.swift:203:7:203:21 | call to getRemoteData() : | UnsafeJsEval.swift:275:13:275:13 | string : |
@@ -23,6 +24,12 @@ edges
2324
| UnsafeJsEval.swift:207:7:207:39 | ... .+(_:_:) ... : | UnsafeJsEval.swift:278:13:278:13 | string : |
2425
| UnsafeJsEval.swift:207:7:207:39 | ... .+(_:_:) ... : | UnsafeJsEval.swift:284:13:284:13 | string : |
2526
| UnsafeJsEval.swift:207:7:207:39 | ... .+(_:_:) ... : | UnsafeJsEval.swift:298:13:298:13 | string : |
27+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | UnsafeJsEval.swift:264:13:264:13 | string : |
28+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | UnsafeJsEval.swift:267:13:267:13 | string : |
29+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | UnsafeJsEval.swift:275:13:275:13 | string : |
30+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | UnsafeJsEval.swift:278:13:278:13 | string : |
31+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | UnsafeJsEval.swift:284:13:284:13 | string : |
32+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | UnsafeJsEval.swift:298:13:298:13 | string : |
2633
| UnsafeJsEval.swift:264:13:264:13 | string : | UnsafeJsEval.swift:265:22:265:107 | call to init(source:injectionTime:forMainFrameOnly:) |
2734
| UnsafeJsEval.swift:267:13:267:13 | string : | UnsafeJsEval.swift:268:22:268:124 | call to init(source:injectionTime:forMainFrameOnly:in:) |
2835
| UnsafeJsEval.swift:275:13:275:13 | string : | UnsafeJsEval.swift:276:26:276:26 | string |
@@ -52,6 +59,7 @@ nodes
5259
| UnsafeJsEval.swift:203:7:203:21 | call to getRemoteData() : | semmle.label | call to getRemoteData() : |
5360
| UnsafeJsEval.swift:204:7:204:7 | remoteString : | semmle.label | remoteString : |
5461
| UnsafeJsEval.swift:207:7:207:39 | ... .+(_:_:) ... : | semmle.label | ... .+(_:_:) ... : |
62+
| UnsafeJsEval.swift:213:7:213:49 | call to init(decoding:as:) : | semmle.label | call to init(decoding:as:) : |
5563
| UnsafeJsEval.swift:264:13:264:13 | string : | semmle.label | string : |
5664
| UnsafeJsEval.swift:265:22:265:107 | call to init(source:injectionTime:forMainFrameOnly:) | semmle.label | call to init(source:injectionTime:forMainFrameOnly:) |
5765
| UnsafeJsEval.swift:267:13:267:13 | string : | semmle.label | string : |

swift/ql/test/query-tests/Security/CWE-094/UnsafeJsEval.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func testAsync(_ sink: @escaping (String) async throws -> ()) {
184184
let remoteData = Data(remoteString.utf8)
185185

186186
try! await sink(String(decoding: localData, as: UTF8.self)) // GOOD: the data is local
187-
try! await sink(String(decoding: remoteData, as: UTF8.self)) // BAD [NOT DETECTED]: the data is remote (TODO: model Data taint sources)
187+
try! await sink(String(decoding: remoteData, as: UTF8.self)) // BAD: the data is remote
188188

189189
try! await sink("console.log(" + String(Int(localStringFragment) ?? 0) + ")") // GOOD: Primitive conversion
190190
try! await sink("console.log(" + String(Int(remoteString) ?? 0) + ")") // GOOD: Primitive conversion
@@ -210,7 +210,7 @@ func testSync(_ sink: @escaping (String) -> ()) {
210210
let remoteData = Data(remoteString.utf8)
211211

212212
sink(String(decoding: localData, as: UTF8.self)) // GOOD: the data is local
213-
sink(String(decoding: remoteData, as: UTF8.self)) // BAD [NOT DETECTED]: the data is remote (TODO: model Data taint sources)
213+
sink(String(decoding: remoteData, as: UTF8.self)) // BAD: the data is remote
214214

215215
sink("console.log(" + String(Int(localStringFragment) ?? 0) + ")") // GOOD: Primitive conversion
216216
sink("console.log(" + String(Int(remoteString) ?? 0) + ")") // GOOD: Primitive conversion

0 commit comments

Comments
 (0)