Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import swift
private import codeql.swift.dataflow.DataFlow
private import codeql.swift.dataflow.ExternalFlow
private import codeql.swift.dataflow.FlowSteps

private class StringSource extends SourceModelCsv {
override predicate row(string row) {
Expand All @@ -16,3 +18,15 @@ private class StringSource extends SourceModelCsv {
]
}
}

/**
* A content implying that, if a `String` is tainted, then all its fields are tainted.
*/
private class StringFieldsInheritTaint extends TaintInheritingContent,
DataFlow::Content::FieldContent {
StringFieldsInheritTaint() {
this.getField().getEnclosingDecl().(ClassOrStructDecl).getFullName() = "String" or
this.getField().getEnclosingDecl().(ExtensionDecl).getExtendedTypeDecl().getFullName() =
"String"
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be a sensible approach, but I will note a few rough edges in the case of String: String.count, String.isEmpty, String.first and String.last. These things can't contain a lot of data (especially String.isEmpty which is a Bool) so it would be very difficult for an attacker to utilize a theoretical taint path through any of them. In CPP in particular we've found taint flow through strlen (equivalent to String.count) usually produces many more false positive results than useful ones.

I'm not sure what the right solution should be. We could try to exclude the ones we don't want from this TaintInheritingContent, or switch to an explicit modelling approach. We could potentially block all taint through 'small' types everywhere, solving the problem for good (but would this limit some uses of taint?). Or we could stick to our principles that these are taint flows and expect queries to sanitize on an ad-hoc basis if they tend to find false positive results?

Copy link
Copy Markdown
Contributor

@d10c d10c Nov 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the one hand, taint flow through small types is irrelevant for most "code injection" type queries. On the other hand, there was Heartbleed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, there have been plenty of real bugs related to tainted integers (malicious image width/height bugs spring to mind as a second example) - and as you suggest our recent focus on code injection queries may be biasing my viewpoint.

I remain somewhat nervous of taint flow through strlen / .count. In CPP we've seen a lot of code like this:

char *buffer = (char *)malloc(sizeof(char) * strlen(inputString));

which is usually a reasonable thing to do, even if inputString is tainted. There were other similar patterns, and in the end we blocked taint through strlen. This particular example ought to be uncommon in Swift, because you don't need to explicitly allocate like this when you're using a proper String class. I suppose we could take a wait-and-see approach on whether flow through .count is actually a problem (or a positive) on Swift?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may also be worth asking other language teams about this. Experience from C/C++ might not apply very well to this judgment call, but experience from Java/C#/JavaScript/Python and related languages might be a better indication of which direction which should go for Swift.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Java, we usually (we aren't 100% consistent) don't consider things like length to be propagating taint, because there are few opportunities in a memory-safe language where a tainted integer could be a problem. Although IMHO, I think we should have those models as well, because some queries actually look for tainted integers. Other queries not interested in that (like code injection) can always add a type-based sanitizer that filters out uninteresting types.

In Swift, where memory management can be a thing, I think modeling these kind of methods makes even more sense. Maybe String.count should be a specific sanitizer for overflow-like vulnerabilities instead of not modeling it at all?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we opt for leaving .count et al as taint propagating steps, maybe we could have a library predicate like isConversionToSmallType(DataFlow::Node), so that queries that don't want this behavior can sanitize it out without reinventing the wheel.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say we keep all those fields/members as potential sources of taint until proven otherwise. As folks have mentioned here, even integers can be sources of taint in some cases. I'm wondering though if there's a way to implement @d10c suggestion without the query writer doing too much work here.

17 changes: 17 additions & 0 deletions swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,13 @@
| data.swift:80:6:80:6 | SSA def(dataClean) | data.swift:84:12:84:12 | dataClean |
| data.swift:80:18:80:18 | Data.Type | data.swift:80:18:80:18 | call to init(_:) |
| data.swift:80:18:80:36 | call to init(_:) | data.swift:80:6:80:6 | SSA def(dataClean) |
| data.swift:80:23:80:23 | 123456 | data.swift:80:23:80:32 | .utf8 |
| data.swift:80:23:80:32 | .utf8 | data.swift:80:18:80:36 | call to init(_:) |
| data.swift:81:6:81:6 | SSA def(dataTainted) | data.swift:82:26:82:26 | dataTainted |
| data.swift:81:20:81:20 | Data.Type | data.swift:81:20:81:20 | call to init(_:) |
| data.swift:81:20:81:51 | call to init(_:) | data.swift:81:6:81:6 | SSA def(dataTainted) |
| data.swift:81:25:81:47 | .utf8 | data.swift:81:20:81:51 | call to init(_:) |
| data.swift:81:26:81:33 | call to source() | data.swift:81:25:81:47 | .utf8 |
| data.swift:82:6:82:6 | SSA def(dataTainted2) | data.swift:86:12:86:12 | dataTainted2 |
| data.swift:82:21:82:21 | Data.Type | data.swift:82:21:82:21 | call to init(_:) |
| data.swift:82:21:82:37 | call to init(_:) | data.swift:82:6:82:6 | SSA def(dataTainted2) |
Expand Down Expand Up @@ -898,9 +900,13 @@
| string.swift:81:31:81:31 | clean | string.swift:84:13:84:13 | clean |
| string.swift:82:31:82:31 | tainted | string.swift:85:13:85:13 | tainted |
| string.swift:84:13:84:13 | [post] clean | string.swift:87:13:87:13 | clean |
| string.swift:84:13:84:13 | clean | string.swift:84:13:84:19 | .description |
| string.swift:84:13:84:13 | clean | string.swift:87:13:87:13 | clean |
| string.swift:85:13:85:13 | [post] tainted | string.swift:88:13:88:13 | tainted |
| string.swift:85:13:85:13 | tainted | string.swift:85:13:85:21 | .description |
| string.swift:85:13:85:13 | tainted | string.swift:88:13:88:13 | tainted |
| string.swift:87:13:87:13 | clean | string.swift:87:13:87:19 | .debugDescription |
| string.swift:88:13:88:13 | tainted | string.swift:88:13:88:21 | .debugDescription |
| string.swift:91:7:91:7 | SSA def(self) | string.swift:91:7:91:7 | self[return] |
| string.swift:91:7:91:7 | self | string.swift:91:7:91:7 | SSA def(self) |
| string.swift:93:5:93:5 | SSA def(self) | string.swift:93:5:93:29 | self[return] |
Expand All @@ -923,6 +929,17 @@
| string.swift:109:23:109:77 | call to init(data:encoding:) | string.swift:109:7:109:7 | SSA def(stringTainted) |
| string.swift:111:12:111:12 | stringClean | string.swift:111:12:111:23 | ...! |
| string.swift:112:12:112:12 | stringTainted | string.swift:112:12:112:25 | ...! |
| string.swift:120:7:120:7 | SSA def(clean) | string.swift:125:13:125:13 | clean |
| string.swift:120:15:120:15 | | string.swift:120:7:120:7 | SSA def(clean) |
| string.swift:121:7:121:7 | SSA def(tainted) | string.swift:126:13:126:13 | tainted |
| string.swift:121:17:121:25 | call to source2() | string.swift:121:17:121:27 | .utf8 |
| string.swift:121:17:121:27 | .utf8 | string.swift:121:7:121:7 | SSA def(tainted) |
| string.swift:122:7:122:7 | SSA def(taintedCString) | string.swift:127:13:127:13 | taintedCString |
| string.swift:122:24:122:32 | call to source2() | string.swift:122:24:122:34 | .utf8CString |
| string.swift:122:24:122:34 | .utf8CString | string.swift:122:7:122:7 | SSA def(taintedCString) |
| string.swift:123:7:123:7 | SSA def(taintedUnicodeScalars) | string.swift:128:13:128:13 | taintedUnicodeScalars |
| string.swift:123:31:123:39 | call to source2() | string.swift:123:31:123:41 | .unicodeScalars |
| string.swift:123:31:123:41 | .unicodeScalars | string.swift:123:7:123:7 | SSA def(taintedUnicodeScalars) |
| subscript.swift:1:7:1:7 | SSA def(self) | subscript.swift:1:7:1:7 | self[return] |
| subscript.swift:1:7:1:7 | SSA def(self) | subscript.swift:1:7:1:7 | self[return] |
| subscript.swift:1:7:1:7 | self | subscript.swift:1:7:1:7 | SSA def(self) |
Expand Down
41 changes: 41 additions & 0 deletions swift/ql/test/library-tests/dataflow/taint/Taint.expected
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
edges
| data.swift:24:5:24:29 | [summary param] 0 in init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(_:) : |
| data.swift:25:2:25:66 | [summary param] 0 in init(base64Encoded:options:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(base64Encoded:options:) : |
| data.swift:26:2:26:61 | [summary param] 0 in init(buffer:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(buffer:) : |
| data.swift:27:2:27:62 | [summary param] 0 in init(buffer:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(buffer:) : |
Expand Down Expand Up @@ -34,6 +35,14 @@ edges
| data.swift:62:2:62:58 | [summary param] this in shuffled(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in shuffled(using:) : |
| data.swift:63:2:63:123 | [summary param] this in trimmingPrefix(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in trimmingPrefix(_:) : |
| data.swift:64:2:64:72 | [summary param] this in trimmingPrefix(while:) : | file://:0:0:0:0 | [summary] to write: return (return) in trimmingPrefix(while:) : |
| data.swift:81:20:81:51 | call to init(_:) : | data.swift:82:26:82:26 | dataTainted : |
| data.swift:81:20:81:51 | call to init(_:) : | data.swift:85:12:85:12 | dataTainted |
| data.swift:81:25:81:47 | .utf8 : | data.swift:24:5:24:29 | [summary param] 0 in init(_:) : |
| data.swift:81:25:81:47 | .utf8 : | data.swift:81:20:81:51 | call to init(_:) : |
| data.swift:81:26:81:33 | call to source() : | data.swift:81:25:81:47 | .utf8 : |
| data.swift:82:21:82:37 | call to init(_:) : | data.swift:86:12:86:12 | dataTainted2 |
| data.swift:82:26:82:26 | dataTainted : | data.swift:24:5:24:29 | [summary param] 0 in init(_:) : |
| data.swift:82:26:82:26 | dataTainted : | data.swift:82:21:82:37 | call to init(_:) : |
| data.swift:89:21:89:71 | call to init(base64Encoded:options:) : | data.swift:90:12:90:12 | dataTainted3 |
| data.swift:89:41:89:48 | call to source() : | data.swift:25:2:25:66 | [summary param] 0 in init(base64Encoded:options:) : |
| data.swift:89:41:89:48 | call to source() : | data.swift:89:21:89:71 | call to init(base64Encoded:options:) : |
Expand Down Expand Up @@ -301,6 +310,11 @@ edges
| string.swift:28:17:28:25 | call to source2() : | string.swift:35:13:35:23 | ... .+(_:_:) ... |
| string.swift:28:17:28:25 | call to source2() : | string.swift:36:13:36:23 | ... .+(_:_:) ... |
| string.swift:28:17:28:25 | call to source2() : | string.swift:39:13:39:29 | ... .+(_:_:) ... |
| string.swift:74:17:74:25 | call to source2() : | string.swift:85:13:85:21 | .description |
| string.swift:74:17:74:25 | call to source2() : | string.swift:88:13:88:21 | .debugDescription |
| string.swift:121:17:121:25 | call to source2() : | string.swift:126:13:126:13 | tainted |
| string.swift:122:24:122:32 | call to source2() : | string.swift:127:13:127:13 | taintedCString |
| string.swift:123:31:123:39 | call to source2() : | string.swift:128:13:128:13 | taintedUnicodeScalars |
| subscript.swift:13:15:13:22 | call to source() : | subscript.swift:13:15:13:25 | ...[...] |
| subscript.swift:14:15:14:23 | call to source2() : | subscript.swift:14:15:14:26 | ...[...] |
| try.swift:9:17:9:24 | call to source() : | try.swift:9:13:9:24 | try ... |
Expand Down Expand Up @@ -541,6 +555,7 @@ edges
| webview.swift:137:34:137:41 | call to source() : | webview.swift:66:5:66:126 | [summary param] 0 in init(source:injectionTime:forMainFrameOnly:in:) : |
| webview.swift:137:34:137:41 | call to source() : | webview.swift:137:13:137:113 | call to init(source:injectionTime:forMainFrameOnly:in:) : |
nodes
| data.swift:24:5:24:29 | [summary param] 0 in init(_:) : | semmle.label | [summary param] 0 in init(_:) : |
| data.swift:25:2:25:66 | [summary param] 0 in init(base64Encoded:options:) : | semmle.label | [summary param] 0 in init(base64Encoded:options:) : |
| data.swift:26:2:26:61 | [summary param] 0 in init(buffer:) : | semmle.label | [summary param] 0 in init(buffer:) : |
| data.swift:27:2:27:62 | [summary param] 0 in init(buffer:) : | semmle.label | [summary param] 0 in init(buffer:) : |
Expand Down Expand Up @@ -576,6 +591,13 @@ nodes
| data.swift:62:2:62:58 | [summary param] this in shuffled(using:) : | semmle.label | [summary param] this in shuffled(using:) : |
| data.swift:63:2:63:123 | [summary param] this in trimmingPrefix(_:) : | semmle.label | [summary param] this in trimmingPrefix(_:) : |
| data.swift:64:2:64:72 | [summary param] this in trimmingPrefix(while:) : | semmle.label | [summary param] this in trimmingPrefix(while:) : |
| data.swift:81:20:81:51 | call to init(_:) : | semmle.label | call to init(_:) : |
| data.swift:81:25:81:47 | .utf8 : | semmle.label | .utf8 : |
| data.swift:81:26:81:33 | call to source() : | semmle.label | call to source() : |
| data.swift:82:21:82:37 | call to init(_:) : | semmle.label | call to init(_:) : |
| data.swift:82:26:82:26 | dataTainted : | semmle.label | dataTainted : |
| data.swift:85:12:85:12 | dataTainted | semmle.label | dataTainted |
| data.swift:86:12:86:12 | dataTainted2 | semmle.label | dataTainted2 |
| data.swift:89:21:89:71 | call to init(base64Encoded:options:) : | semmle.label | call to init(base64Encoded:options:) : |
| data.swift:89:41:89:48 | call to source() : | semmle.label | call to source() : |
| data.swift:90:12:90:12 | dataTainted3 | semmle.label | dataTainted3 |
Expand Down Expand Up @@ -734,6 +756,7 @@ nodes
| file://:0:0:0:0 | [summary] to write: return (return) in flatMap(_:) : | semmle.label | [summary] to write: return (return) in flatMap(_:) : |
| file://:0:0:0:0 | [summary] to write: return (return) in flatMap(_:) : | semmle.label | [summary] to write: return (return) in flatMap(_:) : |
| file://:0:0:0:0 | [summary] to write: return (return) in forProperty(_:) : | semmle.label | [summary] to write: return (return) in forProperty(_:) : |
| file://:0:0:0:0 | [summary] to write: return (return) in init(_:) : | semmle.label | [summary] to write: return (return) in init(_:) : |
| file://:0:0:0:0 | [summary] to write: return (return) in init(base64Encoded:options:) : | semmle.label | [summary] to write: return (return) in init(base64Encoded:options:) : |
| file://:0:0:0:0 | [summary] to write: return (return) in init(base64Encoded:options:) : | semmle.label | [summary] to write: return (return) in init(base64Encoded:options:) : |
| file://:0:0:0:0 | [summary] to write: return (return) in init(base64Encoded:options:) : | semmle.label | [summary] to write: return (return) in init(base64Encoded:options:) : |
Expand Down Expand Up @@ -940,6 +963,15 @@ nodes
| string.swift:35:13:35:23 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... |
| string.swift:36:13:36:23 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... |
| string.swift:39:13:39:29 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... |
| string.swift:74:17:74:25 | call to source2() : | semmle.label | call to source2() : |
| string.swift:85:13:85:21 | .description | semmle.label | .description |
| string.swift:88:13:88:21 | .debugDescription | semmle.label | .debugDescription |
| string.swift:121:17:121:25 | call to source2() : | semmle.label | call to source2() : |
| string.swift:122:24:122:32 | call to source2() : | semmle.label | call to source2() : |
| string.swift:123:31:123:39 | call to source2() : | semmle.label | call to source2() : |
| string.swift:126:13:126:13 | tainted | semmle.label | tainted |
| string.swift:127:13:127:13 | taintedCString | semmle.label | taintedCString |
| string.swift:128:13:128:13 | taintedUnicodeScalars | semmle.label | taintedUnicodeScalars |
| subscript.swift:13:15:13:22 | call to source() : | semmle.label | call to source() : |
| subscript.swift:13:15:13:25 | ...[...] | semmle.label | ...[...] |
| subscript.swift:14:15:14:23 | call to source2() : | semmle.label | call to source2() : |
Expand Down Expand Up @@ -1139,6 +1171,8 @@ nodes
| webview.swift:138:10:138:10 | c | semmle.label | c |
| webview.swift:139:10:139:12 | .source | semmle.label | .source |
subpaths
| data.swift:81:25:81:47 | .utf8 : | data.swift:24:5:24:29 | [summary param] 0 in init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(_:) : | data.swift:81:20:81:51 | call to init(_:) : |
| data.swift:82:26:82:26 | dataTainted : | data.swift:24:5:24:29 | [summary param] 0 in init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(_:) : | data.swift:82:21:82:37 | call to init(_:) : |
| data.swift:89:41:89:48 | call to source() : | data.swift:25:2:25:66 | [summary param] 0 in init(base64Encoded:options:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(base64Encoded:options:) : | data.swift:89:21:89:71 | call to init(base64Encoded:options:) : |
| data.swift:93:34:93:41 | call to source() : | data.swift:26:2:26:61 | [summary param] 0 in init(buffer:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(buffer:) : | data.swift:93:21:93:73 | call to init(buffer:) : |
| data.swift:95:34:95:41 | call to source() : | data.swift:27:2:27:62 | [summary param] 0 in init(buffer:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(buffer:) : | data.swift:95:21:95:74 | call to init(buffer:) : |
Expand Down Expand Up @@ -1260,6 +1294,8 @@ subpaths
| webview.swift:132:34:132:41 | call to source() : | webview.swift:65:5:65:93 | [summary param] 0 in init(source:injectionTime:forMainFrameOnly:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(source:injectionTime:forMainFrameOnly:) : | webview.swift:132:13:132:102 | call to init(source:injectionTime:forMainFrameOnly:) : |
| webview.swift:137:34:137:41 | call to source() : | webview.swift:66:5:66:126 | [summary param] 0 in init(source:injectionTime:forMainFrameOnly:in:) : | file://:0:0:0:0 | [summary] to write: return (return) in init(source:injectionTime:forMainFrameOnly:in:) : | webview.swift:137:13:137:113 | call to init(source:injectionTime:forMainFrameOnly:in:) : |
#select
| data.swift:85:12:85:12 | dataTainted | data.swift:81:26:81:33 | call to source() : | data.swift:85:12:85:12 | dataTainted | result |
| data.swift:86:12:86:12 | dataTainted2 | data.swift:81:26:81:33 | call to source() : | data.swift:86:12:86:12 | dataTainted2 | result |
| data.swift:90:12:90:12 | dataTainted3 | data.swift:89:41:89:48 | call to source() : | data.swift:90:12:90:12 | dataTainted3 | result |
| data.swift:94:12:94:12 | dataTainted4 | data.swift:93:34:93:41 | call to source() : | data.swift:94:12:94:12 | dataTainted4 | result |
| data.swift:96:12:96:12 | dataTainted5 | data.swift:95:34:95:41 | call to source() : | data.swift:96:12:96:12 | dataTainted5 | result |
Expand Down Expand Up @@ -1340,6 +1376,11 @@ subpaths
| string.swift:35:13:35:23 | ... .+(_:_:) ... | string.swift:28:17:28:25 | call to source2() : | string.swift:35:13:35:23 | ... .+(_:_:) ... | result |
| string.swift:36:13:36:23 | ... .+(_:_:) ... | string.swift:28:17:28:25 | call to source2() : | string.swift:36:13:36:23 | ... .+(_:_:) ... | result |
| string.swift:39:13:39:29 | ... .+(_:_:) ... | string.swift:28:17:28:25 | call to source2() : | string.swift:39:13:39:29 | ... .+(_:_:) ... | result |
| string.swift:85:13:85:21 | .description | string.swift:74:17:74:25 | call to source2() : | string.swift:85:13:85:21 | .description | result |
| string.swift:88:13:88:21 | .debugDescription | string.swift:74:17:74:25 | call to source2() : | string.swift:88:13:88:21 | .debugDescription | result |
| string.swift:126:13:126:13 | tainted | string.swift:121:17:121:25 | call to source2() : | string.swift:126:13:126:13 | tainted | result |
| string.swift:127:13:127:13 | taintedCString | string.swift:122:24:122:32 | call to source2() : | string.swift:127:13:127:13 | taintedCString | result |
| string.swift:128:13:128:13 | taintedUnicodeScalars | string.swift:123:31:123:39 | call to source2() : | string.swift:128:13:128:13 | taintedUnicodeScalars | result |
| subscript.swift:13:15:13:25 | ...[...] | subscript.swift:13:15:13:22 | call to source() : | subscript.swift:13:15:13:25 | ...[...] | result |
| subscript.swift:14:15:14:26 | ...[...] | subscript.swift:14:15:14:23 | call to source2() : | subscript.swift:14:15:14:26 | ...[...] | result |
| try.swift:9:13:9:24 | try ... | try.swift:9:17:9:24 | call to source() : | try.swift:9:13:9:24 | try ... | result |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| data.swift:85:12:85:12 | dataTainted | Fixed missing result:tainted=81 |
| data.swift:86:12:86:12 | dataTainted2 | Fixed missing result:tainted=81 |
20 changes: 18 additions & 2 deletions swift/ql/test/library-tests/dataflow/taint/string.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ func taintThroughStringOperations() {
sink(arg: String(repeating: tainted, count: 2)) // $ MISSING: tainted=74

sink(arg: clean.description)
sink(arg: tainted.description) // $ MISSING: tainted=74
sink(arg: tainted.description) // $ tainted=74

sink(arg: clean.debugDescription)
sink(arg: tainted.debugDescription) // $ MISSING: tainted=74
sink(arg: tainted.debugDescription) // $ tainted=74
}

class Data
Expand All @@ -111,3 +111,19 @@ func taintThroughData() {
sink(arg: stringClean!)
sink(arg: stringTainted!) // $ MISSING: tainted=100
}

func sink(arg: String.UTF8View) {}
func sink(arg: ContiguousArray<CChar>) {}
func sink(arg: String.UnicodeScalarView) {}

func taintThroughStringFields() {
let clean = ""
let tainted = source2().utf8
let taintedCString = source2().utf8CString
let taintedUnicodeScalars = source2().unicodeScalars

sink(arg: clean)
sink(arg: tainted) // $ tainted=121
sink(arg: taintedCString) // $ tainted=122
sink(arg: taintedUnicodeScalars) // $ tainted=123
}
Loading