Skip to content

Commit e266132

Browse files
committed
Swift: Replace sinks with (extendable) CSV.
1 parent 4c0d02a commit e266132

File tree

4 files changed

+66
-97
lines changed

4 files changed

+66
-97
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
* 1. The `namespace` column selects a package.
1717
* 2. The `type` column selects a type within that package.
1818
* 3. The `subtypes` is a boolean that indicates whether to jump to an
19-
* arbitrary subtype of that type.
19+
* arbitrary subtype of that type. Set this to `false` if leaving the `type`
20+
* blank (for example, a free function).
2021
* 4. The `name` column optionally selects a specific named member of the type.
2122
* 5. The `signature` column optionally restricts the named member. If
2223
* `signature` is blank then no such filtering is done. The format of the

swift/ql/lib/codeql/swift/security/StringLengthConflationExtensions.qll

Lines changed: 61 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import swift
77
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.ExternalFlow
89

910
/**
1011
* A type of Swift string encoding. This class is used as a flow state for
@@ -13,31 +14,50 @@ import codeql.swift.dataflow.DataFlow
1314
class StringType extends string {
1415
string singular;
1516
string equivClass;
17+
string csvLabel;
1618

1719
StringType() {
18-
this = "String" and singular = "a String" and equivClass = "String"
20+
this = "String" and
21+
singular = "a String" and
22+
equivClass = "String" and
23+
csvLabel = "string-length"
1924
or
20-
this = "NSString" and singular = "an NSString" and equivClass = "NSString"
25+
this = "NSString" and
26+
singular = "an NSString" and
27+
equivClass = "NSString" and
28+
csvLabel = "nsstring-length"
2129
or
22-
this = "String.utf8" and singular = "a String.utf8" and equivClass = "String.utf8"
30+
this = "String.utf8" and
31+
singular = "a String.utf8" and
32+
equivClass = "String.utf8" and
33+
csvLabel = "string-utf8-length"
2334
or
24-
this = "String.utf16" and singular = "a String.utf16" and equivClass = "NSString"
35+
this = "String.utf16" and
36+
singular = "a String.utf16" and
37+
equivClass = "NSString" and
38+
csvLabel = "string-utf16-length"
2539
or
2640
this = "String.unicodeScalars" and
2741
singular = "a String.unicodeScalars" and
28-
equivClass = "String.unicodeScalars"
42+
equivClass = "String.unicodeScalars" and
43+
csvLabel = "string-unicodescalars-length"
2944
}
3045

3146
/**
32-
* Gets the equivalence class for this flow state. If these are equal,
47+
* Gets the equivalence class for this string type. If these are equal,
3348
* they should be treated as equivalent.
3449
*/
3550
string getEquivClass() { result = equivClass }
3651

3752
/**
38-
* Gets text for the singular form of this flow state.
53+
* Gets text for the singular form of this string type.
3954
*/
4055
string getSingular() { result = singular }
56+
57+
/**
58+
* Gets the label for this string type in CSV models.
59+
*/
60+
string getCsvLabel() { result = csvLabel }
4161
}
4262

4363
/**
@@ -115,83 +135,41 @@ private class DefaultStringLengthConflationSource extends StringLengthConflation
115135
override StringType getStringType() { result = stringType }
116136
}
117137

138+
/**
139+
* A sink defined in a CSV model.
140+
*/
118141
private class DefaultStringLengthConflationSink extends StringLengthConflationSink {
119-
StringType correctStringType;
142+
StringType stringType;
120143

121-
DefaultStringLengthConflationSink() {
122-
exists(AbstractFunctionDecl funcDecl, CallExpr call, string funcName, int arg |
123-
(
124-
// arguments to method calls...
125-
exists(string className, ClassOrStructDecl c |
126-
(
127-
// `NSRange.init`
128-
className = "NSRange" and
129-
funcName = "init(location:length:)" and
130-
arg = [0, 1]
131-
or
132-
// `NSString.character`
133-
className = ["NSString", "NSMutableString"] and
134-
funcName = "character(at:)" and
135-
arg = 0
136-
or
137-
// `NSString.character`
138-
className = ["NSString", "NSMutableString"] and
139-
funcName = "substring(from:)" and
140-
arg = 0
141-
or
142-
// `NSString.character`
143-
className = ["NSString", "NSMutableString"] and
144-
funcName = "substring(to:)" and
145-
arg = 0
146-
or
147-
// `NSMutableString.insert`
148-
className = "NSMutableString" and
149-
funcName = "insert(_:at:)" and
150-
arg = 1
151-
) and
152-
c.getName() = className and
153-
c.getABaseTypeDecl*().(ClassOrStructDecl).getAMember() = funcDecl and
154-
call.getStaticTarget() = funcDecl and
155-
correctStringType = "NSString"
156-
)
157-
or
158-
// arguments to function calls...
159-
// `NSMakeRange`
160-
funcName = "NSMakeRange(_:_:)" and
161-
arg = [0, 1] and
162-
call.getStaticTarget() = funcDecl and
163-
correctStringType = "NSString"
164-
or
165-
// arguments to method calls...
166-
(
167-
// `String.dropFirst`, `String.dropLast`, `String.removeFirst`, `String.removeLast`
168-
funcName = ["dropFirst(_:)", "dropLast(_:)", "removeFirst(_:)", "removeLast(_:)"] and
169-
arg = 0
170-
or
171-
// `String.prefix`, `String.suffix`
172-
funcName = ["prefix(_:)", "suffix(_:)"] and
173-
arg = 0
174-
or
175-
// `String.Index.init`
176-
funcName = "init(encodedOffset:)" and
177-
arg = 0
178-
or
179-
// `String.index`
180-
funcName = ["index(_:offsetBy:)", "index(_:offsetBy:limitBy:)"] and
181-
arg = [0, 1]
182-
or
183-
// `String.formIndex`
184-
funcName = ["formIndex(_:offsetBy:)", "formIndex(_:offsetBy:limitBy:)"] and
185-
arg = [0, 1]
186-
) and
187-
call.getStaticTarget() = funcDecl and
188-
correctStringType = "String"
189-
) and
190-
// match up `funcName`, `arg`, `node`.
191-
funcDecl.getName() = funcName and
192-
call.getArgument(arg).getExpr() = this.asExpr()
193-
)
194-
}
144+
DefaultStringLengthConflationSink() { sinkNode(this, stringType.getCsvLabel()) }
195145

196-
override StringType getCorrectStringType() { result = correctStringType }
146+
override StringType getCorrectStringType() { result = stringType }
147+
}
148+
149+
private class StringLengthConflationSinks extends SinkModelCsv {
150+
override predicate row(string row) {
151+
row =
152+
[
153+
";Sequence;true;dropFirst(_:);;;Argument[0];string-length",
154+
";Sequence;true;dropLast(_:);;;Argument[0];string-length",
155+
";Sequence;true;prefix(_:);;;Argument[0];string-length",
156+
";Sequence;true;suffix(_:);;;Argument[0];string-length",
157+
";Collection;true;formIndex(_:offsetBy:);;;Argument[0..1];string-length",
158+
";Collection;true;formIndex(_:offsetBy:limitBy:);;;Argument[0..1];string-length",
159+
";Collection;true;removeFirst(_:);;;Argument[0];string-length",
160+
";RangeReplaceableCollection;true;removeLast(_:);;;Argument[0];string-length",
161+
";String;true;index(_:offsetBy:);;;Argument[0..1];string-length",
162+
";String;true;index(_:offsetBy:limitBy:);;;Argument[0..1];string-length",
163+
";String.Index;true;init(encodedOffset:);;;Argument[0];string-length",
164+
";NSRange;true;init(location:length:);;;Argument[0..1];nsstring-length",
165+
";NSString;true;character(at:);;;Argument[0];nsstring-length",
166+
";NSString;true;substring(from:);;;Argument[0];nsstring-length",
167+
";NSString;true;substring(to:);;;Argument[0];nsstring-length",
168+
";NSMutableString;true;character(at:);;;Argument[0];nsstring-length",
169+
";NSMutableString;true;substring(from:);;;Argument[0];nsstring-length",
170+
";NSMutableString;true;substring(to:);;;Argument[0];nsstring-length",
171+
";NSMutableString;true;insert(_:at:);;;Argument[1];nsstring-length",
172+
";;false;NSMakeRange(_:_:);;;Argument[0..1];nsstring-length",
173+
]
174+
}
197175
}

swift/ql/test/query-tests/Security/CWE-135/StringLengthConflation.expected

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
edges
2-
| StringLengthConflation2.swift:35:36:35:38 | .count : | StringLengthConflation2.swift:35:36:35:46 | ... .-(_:_:) ... |
32
| StringLengthConflation2.swift:37:34:37:36 | .count : | StringLengthConflation2.swift:37:34:37:44 | ... .-(_:_:) ... |
43
| StringLengthConflation.swift:36:30:36:37 | len : | StringLengthConflation.swift:36:93:36:93 | len |
54
| StringLengthConflation.swift:60:47:60:50 | .length : | StringLengthConflation.swift:60:47:60:59 | ... ./(_:_:) ... |
@@ -28,8 +27,6 @@ edges
2827
| file://:0:0:0:0 | .length : | StringLengthConflation.swift:114:23:114:26 | .length : |
2928
| file://:0:0:0:0 | .length : | StringLengthConflation.swift:120:22:120:25 | .length : |
3029
nodes
31-
| StringLengthConflation2.swift:35:36:35:38 | .count : | semmle.label | .count : |
32-
| StringLengthConflation2.swift:35:36:35:46 | ... .-(_:_:) ... | semmle.label | ... .-(_:_:) ... |
3330
| StringLengthConflation2.swift:37:34:37:36 | .count : | semmle.label | .count : |
3431
| StringLengthConflation2.swift:37:34:37:44 | ... .-(_:_:) ... | semmle.label | ... .-(_:_:) ... |
3532
| StringLengthConflation.swift:36:30:36:37 | len : | semmle.label | len : |
@@ -74,15 +71,11 @@ nodes
7471
| StringLengthConflation.swift:144:28:144:30 | .count : | semmle.label | .count : |
7572
| StringLengthConflation.swift:144:28:144:38 | ... .-(_:_:) ... | semmle.label | ... .-(_:_:) ... |
7673
| StringLengthConflation.swift:151:45:151:53 | .count | semmle.label | .count |
77-
| StringLengthConflation.swift:152:57:152:65 | .count | semmle.label | .count |
7874
| StringLengthConflation.swift:156:45:156:52 | .count | semmle.label | .count |
79-
| StringLengthConflation.swift:157:55:157:62 | .count | semmle.label | .count |
8075
| StringLengthConflation.swift:161:45:161:53 | .count | semmle.label | .count |
81-
| StringLengthConflation.swift:162:57:162:65 | .count | semmle.label | .count |
8276
| file://:0:0:0:0 | .length : | semmle.label | .length : |
8377
subpaths
8478
#select
85-
| StringLengthConflation2.swift:35:36:35:46 | ... .-(_:_:) ... | StringLengthConflation2.swift:35:36:35:38 | .count : | StringLengthConflation2.swift:35:36:35:46 | ... .-(_:_:) ... | This String length is used in an NSString, but it may not be equivalent. |
8679
| StringLengthConflation2.swift:37:34:37:44 | ... .-(_:_:) ... | StringLengthConflation2.swift:37:34:37:36 | .count : | StringLengthConflation2.swift:37:34:37:44 | ... .-(_:_:) ... | This String length is used in an NSString, but it may not be equivalent. |
8780
| StringLengthConflation.swift:36:93:36:93 | len | StringLengthConflation.swift:72:33:72:35 | .count : | StringLengthConflation.swift:36:93:36:93 | len | This String length is used in an NSString, but it may not be equivalent. |
8881
| StringLengthConflation.swift:53:43:53:46 | .length | StringLengthConflation.swift:53:43:53:46 | .length | StringLengthConflation.swift:53:43:53:46 | .length | This NSString length is used in a String, but it may not be equivalent. |
@@ -118,8 +111,5 @@ subpaths
118111
| StringLengthConflation.swift:138:36:138:46 | ... .-(_:_:) ... | StringLengthConflation.swift:138:36:138:38 | .count : | StringLengthConflation.swift:138:36:138:46 | ... .-(_:_:) ... | This String length is used in an NSString, but it may not be equivalent. |
119112
| StringLengthConflation.swift:144:28:144:38 | ... .-(_:_:) ... | StringLengthConflation.swift:144:28:144:30 | .count : | StringLengthConflation.swift:144:28:144:38 | ... .-(_:_:) ... | This String length is used in an NSString, but it may not be equivalent. |
120113
| StringLengthConflation.swift:151:45:151:53 | .count | StringLengthConflation.swift:151:45:151:53 | .count | StringLengthConflation.swift:151:45:151:53 | .count | This String.unicodeScalars length is used in a String, but it may not be equivalent. |
121-
| StringLengthConflation.swift:152:57:152:65 | .count | StringLengthConflation.swift:152:57:152:65 | .count | StringLengthConflation.swift:152:57:152:65 | .count | This String.unicodeScalars length is used in a String, but it may not be equivalent. |
122114
| StringLengthConflation.swift:156:45:156:52 | .count | StringLengthConflation.swift:156:45:156:52 | .count | StringLengthConflation.swift:156:45:156:52 | .count | This String.utf8 length is used in a String, but it may not be equivalent. |
123-
| StringLengthConflation.swift:157:55:157:62 | .count | StringLengthConflation.swift:157:55:157:62 | .count | StringLengthConflation.swift:157:55:157:62 | .count | This String.utf8 length is used in a String, but it may not be equivalent. |
124115
| StringLengthConflation.swift:161:45:161:53 | .count | StringLengthConflation.swift:161:45:161:53 | .count | StringLengthConflation.swift:161:45:161:53 | .count | This String.utf16 length is used in a String, but it may not be equivalent. |
125-
| StringLengthConflation.swift:162:57:162:65 | .count | StringLengthConflation.swift:162:57:162:65 | .count | StringLengthConflation.swift:162:57:162:65 | .count | This String.unicodeScalars length is used in a String, but it may not be equivalent. |

swift/ql/test/query-tests/Security/CWE-135/StringLengthConflation.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,17 @@ func test(s: String) {
149149
let scalars = s.unicodeScalars
150150
let _ = s.index(s.startIndex, offsetBy: s.count) // GOOD
151151
let _ = s.index(s.startIndex, offsetBy: scalars.count) // BAD
152-
let _ = scalars.index(scalars.startIndex, offsetBy: scalars.count) // GOOD [FALSE POSITIVE]
152+
let _ = scalars.index(scalars.startIndex, offsetBy: scalars.count) // GOOD
153153
let _ = scalars.index(scalars.startIndex, offsetBy: s.count) // BAD [NOT DETECTED]
154154

155155
let s_utf8 = s.utf8
156156
let _ = s.index(s.startIndex, offsetBy: s_utf8.count) // BAD
157-
let _ = s_utf8.index(s_utf8.startIndex, offsetBy: s_utf8.count) // GOOD [FALSE POSITIVE]
157+
let _ = s_utf8.index(s_utf8.startIndex, offsetBy: s_utf8.count) // GOOD
158158
let _ = s_utf8.index(s_utf8.startIndex, offsetBy: s.count) // BAD [NOT DETECTED]
159159

160160
let s_utf16 = s.utf16
161161
let _ = s.index(s.startIndex, offsetBy: s_utf16.count) // BAD
162-
let _ = s_utf16.index(s_utf16.startIndex, offsetBy: scalars.count) // GOOD [FALSE POSITIVE]
162+
let _ = s_utf16.index(s_utf16.startIndex, offsetBy: scalars.count) // GOOD
163163
let _ = s_utf16.index(s_utf16.startIndex, offsetBy: s.count) // BAD [NOT DETECTED]
164164
}
165165

0 commit comments

Comments
 (0)