Merge remote-tracking branch 'upstream/master' into mergeback-20181217

This commit is contained in:
Jonas Jensen
2018-12-17 13:42:45 +01:00
12 changed files with 262 additions and 41 deletions

View File

@@ -1,11 +1,12 @@
/**
* Provides classes for working with regular expression literals.
* Provides classes for working with regular expressions.
*
* Regular expressions are represented as an abstract syntax tree of regular expression
* Regular expression literals are represented as an abstract syntax tree of regular expression
* terms.
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
/**
* An element containing a regular expression term, that is, either
@@ -484,3 +485,41 @@ class RegExpParseError extends Error, @regexp_parse_error {
result = getMessage()
}
}
/**
* Holds if `source` may be interpreted as a regular expression.
*/
predicate isInterpretedAsRegExp(DataFlow::Node source) {
// The first argument to an invocation of `RegExp` (with or without `new`).
source = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
or
// The argument of a call that coerces the argument to a regular expression.
exists(MethodCallExpr mce, string methodName |
mce.getReceiver().analyze().getAType() = TTString() and
mce.getMethodName() = methodName
|
(methodName = "match" and source.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1)
or
(
methodName = "search" and
source.asExpr() = mce.getArgument(0) and
mce.getNumArgument() = 1 and
// "search" is a common method name, and so we exclude chained accesses
// because `String.prototype.search` returns a number
not exists(PropAccess p | p.getBase() = mce)
)
)
}
/**
* Provides regular expression patterns.
*/
module RegExpPatterns {
/**
* Gets a pattern that matches common top-level domain names.
*/
string commonTLD() {
// according to ranking by http://google.com/search?q=site:.<<TLD>>
result = "com|org|edu|gov|uk|net|io"
}
}

View File

@@ -4,7 +4,6 @@
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
module RegExpInjection {
/**
@@ -51,36 +50,14 @@ module RegExpInjection {
}
/**
* The first argument to an invocation of `RegExp` (with or without `new`).
* The source string of a regular expression.
*/
class RegExpObjectCreationSink extends Sink, DataFlow::ValueNode {
RegExpObjectCreationSink() {
this = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
class RegularExpressionSourceAsSink extends Sink {
RegularExpressionSourceAsSink() {
isInterpretedAsRegExp(this)
}
}
/**
* The argument of a call that coerces the argument to a regular expression.
*/
class RegExpObjectCoercionSink extends Sink {
RegExpObjectCoercionSink() {
exists (MethodCallExpr mce, string methodName |
mce.getReceiver().analyze().getAType() = TTString() and
mce.getMethodName() = methodName |
(methodName = "match" and this.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1) or
(
methodName = "search" and
this.asExpr() = mce.getArgument(0) and
mce.getNumArgument() = 1 and
// `String.prototype.search` returns a number, so exclude chained accesses
not exists(PropAccess p | p.getBase() = mce)
)
)
}
}
/**
* A call to a function whose name suggests that it escapes regular
* expression meta-characters.