Skip to content

Commit 7e9d73b

Browse files
committed
Swift: Add regex sources to the library.
1 parent 1e290b4 commit 7e9d73b

2 files changed

Lines changed: 65 additions & 4 deletions

File tree

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

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,69 @@
11
/**
2-
* Provides classes and predicates for reasoning about use of regular expressions.
2+
* Provides classes and predicates for reasoning about regular expressions.
33
*/
44

55
import swift
6+
import codeql.swift.dataflow.DataFlow
7+
8+
import codeql.swift.regex.RegexTreeView // re-export
9+
private import internal.ParseRegex
10+
//private import codeql.regex.internal.RegExpTracking as RegExpTracking
11+
12+
/**
13+
* A node whose value may flow to a position where it is interpreted
14+
* as a part of a regular expression.
15+
*/
16+
abstract class RegExpPatternSource extends DataFlow::Node {
17+
/**
18+
* Gets a node where the pattern of this node is parsed as a part of
19+
* a regular expression.
20+
*/
21+
abstract DataFlow::Node getAParse();
22+
23+
/**
24+
* Gets the root term of the regular expression parsed from this pattern.
25+
*/
26+
abstract RegExpTerm getRegExpTerm();
27+
}
28+
29+
/* *
30+
* A node whose string value may flow to a position where it is interpreted
31+
* as a part of a regular expression.
32+
*
33+
private class StringRegExpPatternSource extends RegExpPatternSource {
34+
private DataFlow::Node parse;
35+
36+
StringRegExpPatternSource() {
37+
this = regExpSource(parse) and
38+
// `regExpSource()` tracks both strings and regex literals, narrow it down to strings.
39+
this.asExpr().getConstantValue().isString(_)
40+
}
41+
42+
override DataFlow::Node getAParse() { result = parse }
43+
44+
override RegExpTerm getRegExpTerm() { result.getRegExp() = this.asExpr().getExpr() }
45+
}*/
46+
47+
/**
48+
* TODO
49+
* "(a|b).*"
50+
*/
51+
private class ParsedStringRegExp extends RegExp, StringLiteralExpr {
52+
private DataFlow::Node parse;
53+
54+
ParsedStringRegExp() {
55+
//this = regExpSource(parse).asExpr().getExpr()
56+
parse.asExpr() = this
57+
}
58+
59+
DataFlow::Node getAParse() { result = parse }
60+
/*
61+
override predicate isDotAll() { none() }
62+
63+
override predicate isIgnoreCase() { none() }
64+
65+
override string getFlags() { none() }*/
66+
}
667

768
/**
869
* A call that evaluates a regular expression. For example:

swift/ql/test/library-tests/regex/redos_variants.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ func myRegexpVariantsTests(myUrl: URL) throws {
4040
_ = try Regex("a*b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted
4141
_ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted
4242
_ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted
43-
_ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted MISSING: redos-vulnerable=
44-
_ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted MISSING: redos-vulnerable=
43+
_ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted redos-vulnerable=
44+
_ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted redos-vulnerable=
4545

4646
_ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted
47-
_ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted MISSING: redos-vulnerable=
47+
_ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex<AnyRegexOutput>.init(_:)" input=tainted redos-vulnerable=
4848

4949
// TODO: test more variant expressions.
5050
}

0 commit comments

Comments
 (0)