JS: introduce near-empty RegularExpressions.qll

This commit is contained in:
Esben Sparre Andreasen
2018-12-06 22:35:57 +01:00
parent 994fe1bea5
commit 7c6e28d917
3 changed files with 32 additions and 31 deletions

View File

@@ -11,7 +11,6 @@
*/
import javascript
import semmle.javascript.security.dataflow.RegExpInjection
module IncompleteUrlRegExpTracking {
@@ -28,7 +27,7 @@ module IncompleteUrlRegExpTracking {
override
predicate isSink(DataFlow::Node sink) {
sink instanceof RegExpInjection::Sink
isInterpretedAsRegExp(sink)
}
}

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,27 @@ 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
// `String.prototype.search` returns a number, so exclude chained accesses
not exists(PropAccess p | p.getBase() = mce)
)
)
}

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.