mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
JS: Make ReDoS check string-based regexes
This commit is contained in:
@@ -84,16 +84,19 @@ import javascript
|
||||
* whose root node is not a disjunction.
|
||||
*/
|
||||
class RegExpRoot extends @regexpterm {
|
||||
RegExpParent parent;
|
||||
|
||||
// RegExpTerm is abstract, so do not extend it.
|
||||
RegExpRoot() {
|
||||
exists(RegExpLiteral literal, RegExpAlt alt | alt.getParent() = literal |
|
||||
this = alt.getAChild()
|
||||
exists(RegExpAlt alt |
|
||||
alt.isRootTerm() and
|
||||
this = alt.getAChild() and
|
||||
parent = alt.getParent()
|
||||
)
|
||||
or
|
||||
exists(RegExpLiteral literal |
|
||||
not exists(RegExpAlt alt | alt.getParent() = literal) and
|
||||
this.(RegExpTerm).getParent() = literal
|
||||
)
|
||||
this.(RegExpTerm).isRootTerm() and
|
||||
not this instanceof RegExpAlt and
|
||||
parent = this.(RegExpTerm).getParent()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +106,13 @@ class RegExpRoot extends @regexpterm {
|
||||
// there is at least one repetition
|
||||
exists(RegExpRepetition rep | getRoot(rep) = this) and
|
||||
// there are no lookbehinds
|
||||
not exists(RegExpLookbehind lbh | getRoot(lbh) = this)
|
||||
not exists(RegExpLookbehind lbh | getRoot(lbh) = this) and
|
||||
// is actually used as a RegExp
|
||||
(
|
||||
parent instanceof RegExpLiteral
|
||||
or
|
||||
parent.(StringLiteral).flow() instanceof RegExpPatternSource
|
||||
)
|
||||
}
|
||||
|
||||
string toString() { result = this.(RegExpTerm).toString() }
|
||||
@@ -352,10 +361,10 @@ predicate delta(State q1, EdgeLabel lbl, State q2) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(RegExpDot dot, RegExpLiteral rel |
|
||||
q1 = before(dot) and q2 = after(dot) and rel = dot.getLiteral()
|
||||
exists(RegExpDot dot |
|
||||
q1 = before(dot) and q2 = after(dot)
|
||||
|
|
||||
if rel.isDotAll() then lbl = Any() else lbl = Dot()
|
||||
if dot.getLiteral().isDotAll() then lbl = Any() else lbl = Dot()
|
||||
)
|
||||
or
|
||||
exists(RegExpCharacterClass cc |
|
||||
|
||||
@@ -105,6 +105,13 @@ abstract class RegExpTerm extends Locatable, @regexpterm {
|
||||
* it has an enclosing lookbehind assertions.
|
||||
*/
|
||||
predicate isInBackwardMatchingContext() { this = any(RegExpLookbehind lbh).getAChild+() }
|
||||
|
||||
/**
|
||||
* Holds if this is the root term of a regular expression.
|
||||
*/
|
||||
predicate isRootTerm() {
|
||||
not getParent() instanceof RegExpTerm
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,3 +49,4 @@
|
||||
| tst.js:74:14:74:21 | (b\|a?b)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'b'. |
|
||||
| tst.js:77:14:77:21 | (a\|aa?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
|
||||
| tst.js:83:14:83:20 | (.\|\\n)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\n'. |
|
||||
| tst.js:89:25:89:32 | (a\|aa?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
|
||||
|
||||
@@ -84,3 +84,9 @@ var bad16 = /(.|\n)*!/s;
|
||||
|
||||
// GOOD
|
||||
var good8 = /([\w.]+)*/;
|
||||
|
||||
// NOT GOOD
|
||||
var bad17 = new RegExp('(a|aa?)*b');
|
||||
|
||||
// GOOD - not used as regexp
|
||||
var good9 = '(a|aa?)*b';
|
||||
|
||||
Reference in New Issue
Block a user