Swift: Add more sinks.

This commit is contained in:
Geoffrey White
2023-07-03 12:34:28 +01:00
parent 315cae21ce
commit 4cdc257a06
3 changed files with 47 additions and 8 deletions

View File

@@ -31,6 +31,10 @@ class RegexInjectionAdditionalFlowStep extends Unit {
/**
* A sink that is a regular expression evaluation defined in the Regex library.
* This includes various methods that consume a regular expression string, but
* in general misses cases where a regular expression string is converted into
* an object (such as a `Regex` or `NSRegularExpression`) for later evaluation.
* These cases are modelled separately.
*/
private class EvalRegexInjectionSink extends RegexInjectionSink {
EvalRegexInjectionSink() { this.asExpr() = any(RegexEval e).getRegexInput() }
@@ -42,3 +46,14 @@ private class EvalRegexInjectionSink extends RegexInjectionSink {
private class DefaultRegexInjectionSink extends RegexInjectionSink {
DefaultRegexInjectionSink() { sinkNode(this, "regex-use") }
}
private class RegexInjectionSinks extends SinkModelCsv {
override predicate row(string row) {
row =
[
";Regex;true;init(_:);;;Argument[0];regex-use",
";Regex;true;init(_:as:);;;Argument[0];regex-use",
";NSRegularExpression;true;init(pattern:options:);;;Argument[0];regex-use",
]
}
}

View File

@@ -1,8 +1,32 @@
edges
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:99:16:99:16 | taintedString |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:102:16:102:40 | ... .+(_:_:) ... |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:104:16:104:16 | "..." |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:107:16:107:39 | ... ? ... : ... |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:108:16:108:37 | ... ? ... : ... |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:111:24:111:24 | taintedString |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:112:45:112:45 | taintedString |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:118:19:118:19 | taintedString |
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:129:39:129:39 | taintedString |
nodes
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) |
| tests.swift:99:16:99:16 | taintedString | semmle.label | taintedString |
| tests.swift:102:16:102:40 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... |
| tests.swift:104:16:104:16 | "..." | semmle.label | "..." |
| tests.swift:107:16:107:39 | ... ? ... : ... | semmle.label | ... ? ... : ... |
| tests.swift:108:16:108:37 | ... ? ... : ... | semmle.label | ... ? ... : ... |
| tests.swift:111:24:111:24 | taintedString | semmle.label | taintedString |
| tests.swift:112:45:112:45 | taintedString | semmle.label | taintedString |
| tests.swift:118:19:118:19 | taintedString | semmle.label | taintedString |
| tests.swift:129:39:129:39 | taintedString | semmle.label | taintedString |
subpaths
#select
| tests.swift:99:16:99:16 | taintedString | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:99:16:99:16 | taintedString | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:102:16:102:40 | ... .+(_:_:) ... | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:102:16:102:40 | ... .+(_:_:) ... | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:104:16:104:16 | "..." | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:104:16:104:16 | "..." | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:107:16:107:39 | ... ? ... : ... | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:107:16:107:39 | ... ? ... : ... | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:108:16:108:37 | ... ? ... : ... | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:108:16:108:37 | ... ? ... : ... | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:111:24:111:24 | taintedString | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:111:24:111:24 | taintedString | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:112:45:112:45 | taintedString | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:112:45:112:45 | taintedString | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:118:19:118:19 | taintedString | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:118:19:118:19 | taintedString | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
| tests.swift:129:39:129:39 | taintedString | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:129:39:129:39 | taintedString | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |

View File

@@ -96,20 +96,20 @@ func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws {
_ = try Regex(constString).firstMatch(in: varString)
_ = try Regex(varString).firstMatch(in: varString)
_ = try Regex(taintedString).firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try Regex(taintedString).firstMatch(in: varString) // BAD
_ = try Regex("(a|" + constString + ")").firstMatch(in: varString)
_ = try Regex("(a|" + taintedString + ")").firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try Regex("(a|" + taintedString + ")").firstMatch(in: varString) // BAD
_ = try Regex("(a|\(constString))").firstMatch(in: varString)
_ = try Regex("(a|\(taintedString))").firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try Regex("(a|\(taintedString))").firstMatch(in: varString) // BAD
_ = try Regex(cond ? constString : constString).firstMatch(in: varString)
_ = try Regex(cond ? taintedString : constString).firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try Regex(cond ? constString : taintedString).firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try Regex(cond ? taintedString : constString).firstMatch(in: varString) // BAD
_ = try Regex(cond ? constString : taintedString).firstMatch(in: varString) // BAD
_ = try (cond ? Regex(constString) : Regex(constString)).firstMatch(in: varString)
_ = try (cond ? Regex(taintedString) : Regex(constString)).firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try (cond ? Regex(constString) : Regex(taintedString)).firstMatch(in: varString) // BAD [NOT DETECTED]
_ = try (cond ? Regex(taintedString) : Regex(constString)).firstMatch(in: varString) // BAD
_ = try (cond ? Regex(constString) : Regex(taintedString)).firstMatch(in: varString) // BAD
// --- RangeReplaceableCollection ---
@@ -126,7 +126,7 @@ func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws {
// --- NSRegularExpression ---
_ = try NSRegularExpression(pattern: constString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count))
_ = try NSRegularExpression(pattern: taintedString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count)) // BAD [NOT DETECTED]
_ = try NSRegularExpression(pattern: taintedString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count)) // BAD
// --- NSString ---