Skip to content

Commit 7029f14

Browse files
authored
Merge pull request github#14511 from geoffw0/substring
Swift: Model Substring
2 parents 4920c7f + 42a2ec9 commit 7029f14

File tree

4 files changed

+48
-7
lines changed

4 files changed

+48
-7
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
5+
* Added taint flow models for members of `Substring`.

swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ private class CollectionSummaries extends SummaryModelCsv {
3636
";RangeReplaceableCollection;true;removeFirst();;;Argument[-1];ReturnValue;taint",
3737
";RangeReplaceableCollection;true;removeLast();;;Argument[-1];ReturnValue;taint",
3838
";RangeReplaceableCollection;true;insert(_:at:);;;Argument[0];Argument[-1];taint",
39+
";RangeReplaceableCollection;true;replaceSubrange(_:with:);;;Argument[1];Argument[-1];taint",
40+
";RangeReplaceableCollection;true;replaceSubrange(_:with:);;;Argument[1].CollectionElement;Argument[-1].CollectionElement;value",
3941
";BidirectionalCollection;true;joined(separator:);;;Argument[-1..0];ReturnValue;taint",
4042
";BidirectionalCollection;true;last(where:);;;Argument[-1];ReturnValue;taint",
4143
";BidirectionalCollection;true;popLast();;;Argument[-1];ReturnValue;taint",

swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ private class StringSummaries extends SummaryModelCsv {
113113
";String;true;localizedStringWithFormat(_:_:);;;Argument[0];ReturnValue;taint",
114114
";String;true;localizedStringWithFormat(_:_:);;;Argument[1].CollectionElement;ReturnValue;taint",
115115
";String;true;insert(contentsOf:at:);;;Argument[0];Argument[-1];taint",
116-
";String;true;replaceSubrange(_:with:);;;Argument[1];Argument[-1];taint",
117116
";String;true;max();;;Argument[-1];ReturnValue;taint",
118117
";String;true;max(by:);;;Argument[-1];ReturnValue;taint",
119118
";String;true;min();;;Argument[-1];ReturnValue;taint",
@@ -127,6 +126,9 @@ private class StringSummaries extends SummaryModelCsv {
127126
";String;true;decodeCString(_:as:repairingInvalidCodeUnits:);;;Argument[0];ReturnValue.TupleElement[0];taint",
128127
";String;true;decodeCString(_:as:repairingInvalidCodeUnits:);;;Argument[0].CollectionElement;ReturnValue.TupleElement[0];taint",
129128
";LosslessStringConvertible;true;init(_:);;;Argument[0];ReturnValue;taint",
129+
";Substring;true;withUTF8(_:);;;Argument[-1];Argument[0].Parameter[0].CollectionElement;taint",
130+
";Substring;true;withUTF8(_:);;;Argument[0].Parameter[0].CollectionElement;Argument[-1];taint",
131+
";Substring;true;withUTF8(_:);;;Argument[0].ReturnValue;ReturnValue;value",
130132
]
131133
}
132134
}
@@ -139,23 +141,26 @@ private class StringFieldsInheritTaint extends TaintInheritingContent,
139141
DataFlow::Content::FieldContent
140142
{
141143
StringFieldsInheritTaint() {
142-
this.getField()
143-
.hasQualifiedName(["String", "StringProtocol"],
144+
exists(FieldDecl fieldDecl, Decl declaringDecl, TypeDecl namedTypeDecl |
145+
(
146+
namedTypeDecl.getFullName() = ["String", "StringProtocol"] and
147+
fieldDecl.getName() =
144148
[
145149
"unicodeScalars", "utf8", "utf16", "lazy", "utf8CString", "dataValue",
146150
"identifierValue", "capitalized", "localizedCapitalized", "localizedLowercase",
147151
"localizedUppercase", "decomposedStringWithCanonicalMapping",
148152
"decomposedStringWithCompatibilityMapping", "precomposedStringWithCanonicalMapping",
149153
"precomposedStringWithCompatibilityMapping", "removingPercentEncoding"
150-
])
151-
or
152-
exists(FieldDecl fieldDecl, Decl declaringDecl, TypeDecl namedTypeDecl |
153-
(
154+
]
155+
or
154156
namedTypeDecl.getFullName() = "CustomStringConvertible" and
155157
fieldDecl.getName() = "description"
156158
or
157159
namedTypeDecl.getFullName() = "CustomDebugStringConvertible" and
158160
fieldDecl.getName() = "debugDescription"
161+
or
162+
namedTypeDecl.getFullName() = "Substring" and
163+
fieldDecl.getName() = "base"
159164
) and
160165
declaringDecl.getAMember() = fieldDecl and
161166
declaringDecl.asNominalTypeDecl() = namedTypeDecl.getADerivedTypeDecl*() and

swift/ql/test/library-tests/dataflow/taint/libraries/string.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,3 +687,32 @@ func testDecodeCString() {
687687
sink(arg: str4) // $ tainted=669
688688
sink(arg: repaired4)
689689
}
690+
691+
func testSubstringMembers() {
692+
let clean = ""
693+
let tainted = source2()
694+
695+
let sub1 = tainted[..<tainted.index(tainted.endIndex, offsetBy: -5)]
696+
sink(arg: sub1) // $ tainted=693
697+
sink(arg: sub1.base) // $ tainted=693
698+
sink(arg: sub1.utf8) // $ tainted=693
699+
sink(arg: sub1.capitalized) // $ tainted=693
700+
sink(arg: sub1.description) // $ tainted=693
701+
702+
var sub2 = tainted[tainted.index(tainted.startIndex, offsetBy: 5)...]
703+
sink(arg: sub2) // $ tainted=693
704+
let result1 = sub2.withUTF8({
705+
buffer in
706+
sink(arg: buffer[0]) // $ tainted=693
707+
return source()
708+
})
709+
sink(arg: result1) // $ tainted=707
710+
711+
let sub3 = Substring(sub2.utf8)
712+
sink(arg: sub3) // $ tainted=693
713+
714+
var sub4 = clean.prefix(10)
715+
sink(arg: sub4)
716+
sub4.replaceSubrange(..<clean.endIndex, with: sub1)
717+
sink(arg: sub4) // $ tainted=693
718+
}

0 commit comments

Comments
 (0)