Skip to content

Commit 86c6960

Browse files
committed
Swift: Add RegexUseFlow and modify the role of StringLiteralUseFlow.
1 parent c76d85d commit 86c6960

File tree

2 files changed

+52
-18
lines changed

2 files changed

+52
-18
lines changed

swift/ql/lib/codeql/swift/regex/Regex.qll

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,22 @@ private import internal.ParseRegex
99
private import internal.RegexTracking
1010

1111
/**
12-
* A string literal that is used as a regular expression in a regular
13-
* expression evaluation. For example the string literal `"(a|b).*"` in:
12+
* A string literal that is used as a regular expression. For example
13+
* the string literal `"(a|b).*"` in:
1414
* ```
1515
* Regex("(a|b).*").firstMatch(in: myString)
1616
* ```
1717
*/
1818
private class ParsedStringRegex extends RegExp, StringLiteralExpr {
19-
RegexEval eval;
19+
DataFlow::Node use;
2020

21-
ParsedStringRegex() {
22-
StringLiteralUseFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(eval.getRegexInput()))
23-
}
21+
ParsedStringRegex() { StringLiteralUseFlow::flow(DataFlow::exprNode(this), use) }
2422

2523
/**
26-
* Gets a call that evaluates this regular expression.
24+
* Gets a dataflow node where this string literal is used as a regular
25+
* expression.
2726
*/
28-
RegexEval getEval() { result = eval }
27+
DataFlow::Node getUse() { result = use }
2928
}
3029

3130
/**
@@ -69,7 +68,8 @@ private class StandardRegexCreation extends RegexCreation {
6968
*/
7069
abstract class RegexEval extends CallExpr {
7170
/**
72-
* Gets the input to this call that is the regular expression being evaluated.
71+
* Gets the input to this call that is the regular expression being evaluated. This may
72+
* be a regular expression object or a string literal.
7373
*/
7474
abstract Expr getRegexInput();
7575

@@ -81,7 +81,16 @@ abstract class RegexEval extends CallExpr {
8181
/**
8282
* Gets a regular expression value that is evaluated here (if any can be identified).
8383
*/
84-
RegExp getARegex() { result.(ParsedStringRegex).getEval() = this }
84+
RegExp getARegex() {
85+
// string literal used directly as a regex
86+
result.(ParsedStringRegex).getUse().asExpr() = this.getRegexInput()
87+
or
88+
// string literal -> regex object -> use
89+
exists(RegexCreation regexCreation |
90+
result.(ParsedStringRegex).getUse() = regexCreation.getStringInput() and
91+
RegexUseFlow::flow(regexCreation, DataFlow::exprNode(this.getRegexInput()))
92+
)
93+
}
8594
}
8695

8796
/**

swift/ql/lib/codeql/swift/regex/internal/RegexTracking.qll

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,46 @@ private import ParseRegex
1111
private import codeql.swift.regex.Regex
1212

1313
/**
14-
* A data flow configuration for tracking string literals that are used as
15-
* regular expressions.
14+
* A data flow configuration for tracking string literals that are used to
15+
* create regular expression objects, or are evaluated directly as regular
16+
* expressions.
1617
*/
1718
private module StringLiteralUseConfig implements DataFlow::ConfigSig {
1819
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof StringLiteralExpr }
1920

20-
predicate isSink(DataFlow::Node node) { node.asExpr() = any(RegexEval eval).getRegexInput() }
21+
predicate isSink(DataFlow::Node node) {
22+
// evaluated directly as a regular expression
23+
node.asExpr() = any(RegexEval eval).getRegexInput()
24+
or
25+
// used to create a regular expression object
26+
node = any(RegexCreation regexCreation).getStringInput()
27+
}
28+
}
2129

22-
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
23-
// flow through `Regex` initializer, i.e. from a string to a `Regex` object.
30+
module StringLiteralUseFlow = DataFlow::Global<StringLiteralUseConfig>;
31+
32+
/**
33+
* A data flow configuration for tracking regular expression objects from
34+
* creation to the point of use.
35+
*/
36+
private module RegexUseConfig implements DataFlow::ConfigSig {
37+
predicate isSource(DataFlow::Node node) {
38+
// creation of the regex
2439
exists(RegexCreation regexCreation |
25-
nodeFrom = regexCreation.getStringInput() and
26-
nodeTo = regexCreation
40+
node = regexCreation
2741
)
42+
// TODO: track parse mode flags.
43+
}
44+
45+
predicate isSink(DataFlow::Node node) {
46+
// evaluation of the regex
47+
node.asExpr() = any(RegexEval eval).getRegexInput()
48+
}
49+
50+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
51+
// TODO: flow through regex methods that return a modified regex.
52+
none()
2853
}
2954
}
3055

31-
module StringLiteralUseFlow = DataFlow::Global<StringLiteralUseConfig>;
56+
module RegexUseFlow = DataFlow::Global<RegexUseConfig>;

0 commit comments

Comments
 (0)