mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
JS: UriLibraryStep
This commit is contained in:
@@ -217,13 +217,23 @@ module TaintTracking {
|
||||
* Note: For performance reasons, all subclasses of this class should be part
|
||||
* of the standard library. Override `Configuration::isAdditionalTaintStep`
|
||||
* for analysis-specific taint steps.
|
||||
*
|
||||
* This class has multiple kinds of `step` predicates; these all have the same
|
||||
* effect on taint-tracking configurations. However, the categorization of steps
|
||||
* allows some data-flow configurations to opt in to specific kinds of taint steps.
|
||||
*/
|
||||
class SharedTaintStep extends Unit {
|
||||
/**
|
||||
* Holds if `pred` → `succ` should be considered a taint-propagating
|
||||
* data flow edge.
|
||||
*/
|
||||
abstract predicate step(DataFlow::Node pred, DataFlow::Node succ);
|
||||
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `pred` → `succ` should be considered a taint-propagating
|
||||
* data flow edge, in the URI category.
|
||||
*/
|
||||
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,6 +243,12 @@ module TaintTracking {
|
||||
any(SharedTaintStep step).step(pred, succ)
|
||||
or
|
||||
any(AdditionalTaintStep step).step(pred, succ)
|
||||
or
|
||||
uriStep(pred, succ)
|
||||
}
|
||||
|
||||
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(SharedTaintStep step).uriStep(pred, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `TaintTracking::SharedTaintStep` or `TaintTracking::uriStep` instead.
|
||||
*
|
||||
* A taint propagating data flow edge arising from an operation in a URI library.
|
||||
*/
|
||||
abstract class UriLibraryStep extends DataFlow::ValueNode, TaintTracking::AdditionalTaintStep { }
|
||||
deprecated abstract class UriLibraryStep extends DataFlow::ValueNode, TaintTracking::AdditionalTaintStep { }
|
||||
|
||||
/**
|
||||
* Provides classes for working with [urijs](http://medialize.github.io/URI.js/) code.
|
||||
@@ -56,26 +58,22 @@ module urijs {
|
||||
/**
|
||||
* A taint step in the urijs library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// flow through "constructors" (`new` is optional)
|
||||
exists(DataFlow::InvokeNode invk | invk = this and invk = invocation() |
|
||||
src = invk.getAnArgument()
|
||||
exists(DataFlow::InvokeNode invk | invk = succ and invk = invocation() |
|
||||
pred = invk.getAnArgument()
|
||||
)
|
||||
or
|
||||
// flow through chained calls
|
||||
exists(DataFlow::MethodCallNode mc | mc = this and this = chainCall() |
|
||||
src = mc.getReceiver() or
|
||||
src = mc.getAnArgument()
|
||||
exists(DataFlow::MethodCallNode mc | mc = succ and succ = chainCall() |
|
||||
pred = mc.getReceiver() or
|
||||
pred = mc.getAnArgument()
|
||||
)
|
||||
or
|
||||
// flow through getter calls
|
||||
exists(DataFlow::MethodCallNode mc | mc = this and this = getter() | src = mc.getReceiver())
|
||||
exists(DataFlow::MethodCallNode mc | mc = succ and succ = getter() | pred = mc.getReceiver())
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,22 +91,19 @@ module uridashjs {
|
||||
/**
|
||||
* A taint step in the urijs library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(string name |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "serialize" or
|
||||
name = "resolve" or
|
||||
name = "normalize"
|
||||
|
|
||||
this = uridashjsMember(name).getACall() and
|
||||
src = getAnArgument()
|
||||
call = uridashjsMember(name).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,22 +121,19 @@ module punycode {
|
||||
/**
|
||||
* A taint step in the punycode library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(string name |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "decode" or
|
||||
name = "encode" or
|
||||
name = "toUnicode" or
|
||||
name = "toASCII"
|
||||
|
|
||||
this = punycodeMember(name).getACall() and
|
||||
src = getAnArgument()
|
||||
call = punycodeMember(name).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,24 +154,23 @@ module urlParse {
|
||||
/**
|
||||
* A taint step in the url-parse library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
// parse(src)
|
||||
this = call() and
|
||||
src = getAnArgument()
|
||||
or
|
||||
exists(DataFlow::MethodCallNode mc | this = mc and mc = call().getAMethodCall("set") |
|
||||
// src = parse(...); src.set(x, y)
|
||||
src = mc.getReceiver()
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call | succ = call |
|
||||
// parse(pred)
|
||||
call = call() and
|
||||
pred = call.getAnArgument()
|
||||
or
|
||||
// parse(x).set(y, src)
|
||||
src = mc.getArgument(1)
|
||||
call = call().getAMethodCall("set") and
|
||||
(
|
||||
// pred = parse(...); pred.set(x, y)
|
||||
pred = call.getReceiver()
|
||||
or
|
||||
// parse(x).set(y, pred)
|
||||
pred = call.getArgument(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,20 +188,17 @@ module querystringify {
|
||||
/**
|
||||
* A taint step in the querystringify library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(string name |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "stringify"
|
||||
|
|
||||
this = querystringifyMember(name).getACall() and
|
||||
src = getAnArgument()
|
||||
call = querystringifyMember(name).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,22 +216,19 @@ module querydashstring {
|
||||
/**
|
||||
* A taint step in the query-string library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(string name |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "extract" or
|
||||
name = "parseUrl" or
|
||||
name = "stringify"
|
||||
|
|
||||
this = querydashstringMember(name).getACall() and
|
||||
src = getAnArgument()
|
||||
call = querydashstringMember(name).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,21 +244,18 @@ module url {
|
||||
/**
|
||||
* A taint step in the url library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(string name |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "format" or
|
||||
name = "resolve"
|
||||
|
|
||||
this = urlMember(name).getACall() and
|
||||
src = getAnArgument()
|
||||
call = urlMember(name).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,22 +273,19 @@ module querystring {
|
||||
/**
|
||||
* A taint step in the querystring library.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(string name |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "escape" or
|
||||
name = "unescape" or
|
||||
name = "parse" or
|
||||
name = "stringify"
|
||||
|
|
||||
this = querystringMember(name).getACall() and
|
||||
src = getAnArgument()
|
||||
call = querystringMember(name).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = src and succ = this }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,56 +296,51 @@ private module ClosureLibraryUri {
|
||||
/**
|
||||
* Taint step from an argument of a `goog.Uri` call to the return value.
|
||||
*/
|
||||
private class ArgumentStep extends UriLibraryStep, DataFlow::InvokeNode {
|
||||
int arg;
|
||||
|
||||
ArgumentStep() {
|
||||
// goog.Uri constructor
|
||||
this = Closure::moduleImport("goog.Uri").getAnInstantiation() and arg = 0
|
||||
or
|
||||
// static methods on goog.Uri
|
||||
exists(string name | this = Closure::moduleImport("goog.Uri." + name).getACall() |
|
||||
name = "parse" and arg = 0
|
||||
private class ArgumentStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::InvokeNode invoke, int arg | pred = invoke.getArgument(arg) and succ = invoke |
|
||||
// goog.Uri constructor
|
||||
invoke = Closure::moduleImport("goog.Uri").getAnInstantiation() and arg = 0
|
||||
or
|
||||
name = "create" and
|
||||
(arg = 0 or arg = 2 or arg = 4)
|
||||
// static methods on goog.Uri
|
||||
exists(string name | invoke = Closure::moduleImport("goog.Uri." + name).getACall() |
|
||||
name = "parse" and arg = 0
|
||||
or
|
||||
name = "create" and
|
||||
(arg = 0 or arg = 2 or arg = 4)
|
||||
or
|
||||
name = "resolve" and
|
||||
(arg = 0 or arg = 1)
|
||||
)
|
||||
or
|
||||
name = "resolve" and
|
||||
(arg = 0 or arg = 1)
|
||||
// static methods in goog.uri.utils
|
||||
arg = 0 and
|
||||
exists(string name | invoke = Closure::moduleImport("goog.uri.utils." + name).getACall() |
|
||||
name = "appendParam" or // preserve taint from the original URI, but not from the appended param
|
||||
name = "appendParams" or
|
||||
name = "appendParamsFromMap" or
|
||||
name = "appendPath" or
|
||||
name = "getParamValue" or
|
||||
name = "getParamValues" or
|
||||
name = "getPath" or
|
||||
name = "getPathAndAfter" or
|
||||
name = "getQueryData" or
|
||||
name = "parseQueryData" or
|
||||
name = "removeFragment" or
|
||||
name = "removeParam" or
|
||||
name = "setParam" or
|
||||
name = "setParamsFromMap" or
|
||||
name = "setPath" or
|
||||
name = "split"
|
||||
)
|
||||
or
|
||||
// static methods in goog.string
|
||||
arg = 0 and
|
||||
exists(string name | invoke = Closure::moduleImport("goog.string." + name).getACall() |
|
||||
name = "urlDecode" or
|
||||
name = "urlEncode"
|
||||
)
|
||||
)
|
||||
or
|
||||
// static methods in goog.uri.utils
|
||||
arg = 0 and
|
||||
exists(string name | this = Closure::moduleImport("goog.uri.utils." + name).getACall() |
|
||||
name = "appendParam" or // preserve taint from the original URI, but not from the appended param
|
||||
name = "appendParams" or
|
||||
name = "appendParamsFromMap" or
|
||||
name = "appendPath" or
|
||||
name = "getParamValue" or
|
||||
name = "getParamValues" or
|
||||
name = "getPath" or
|
||||
name = "getPathAndAfter" or
|
||||
name = "getQueryData" or
|
||||
name = "parseQueryData" or
|
||||
name = "removeFragment" or
|
||||
name = "removeParam" or
|
||||
name = "setParam" or
|
||||
name = "setParamsFromMap" or
|
||||
name = "setPath" or
|
||||
name = "split"
|
||||
)
|
||||
or
|
||||
// static methods in goog.string
|
||||
arg = 0 and
|
||||
exists(string name | this = Closure::moduleImport("goog.string." + name).getACall() |
|
||||
name = "urlDecode" or
|
||||
name = "urlEncode"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getArgument(arg) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +349,7 @@ private module ClosureLibraryUri {
|
||||
*
|
||||
* Setters mutate the URI object and return the same instance.
|
||||
*/
|
||||
private class SetterCall extends DataFlow::MethodCallNode, UriLibraryStep {
|
||||
private class SetterCall extends DataFlow::MethodCallNode {
|
||||
DataFlow::NewNode uri;
|
||||
string name;
|
||||
|
||||
@@ -393,12 +367,19 @@ private module ClosureLibraryUri {
|
||||
|
||||
DataFlow::NewNode getUri() { result = uri }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getReceiver() and succ = this
|
||||
or
|
||||
(name = "setDomain" or name = "setPath" or name = "setScheme") and
|
||||
pred = getArgument(0) and
|
||||
succ = uri
|
||||
string getName() { result = name }
|
||||
}
|
||||
|
||||
/** A taint step derived from a setter call on a `goog.Uri` object. */
|
||||
private class SetterCallStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(SetterCall call |
|
||||
pred = call.getReceiver() and succ = call
|
||||
or
|
||||
(call.getName() = "setDomain" or call.getName() = "setPath" or call.getName() = "setScheme") and
|
||||
pred = call.getArgument(0) and
|
||||
succ = call.getUri()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,25 +390,20 @@ private module ClosureLibraryUri {
|
||||
/**
|
||||
* A taint step in the path module.
|
||||
*/
|
||||
private class Step extends UriLibraryStep, DataFlow::CallNode {
|
||||
DataFlow::Node src;
|
||||
|
||||
Step() {
|
||||
exists(DataFlow::SourceNode ref |
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::SourceNode ref, DataFlow::CallNode call |
|
||||
ref = NodeJSLib::Path::moduleMember("parse") or
|
||||
// a ponyfill: https://www.npmjs.com/package/path-parse
|
||||
ref = DataFlow::moduleImport("path-parse") or
|
||||
ref = DataFlow::moduleMember("path-parse", "posix") or
|
||||
ref = DataFlow::moduleMember("path-parse", "win32")
|
||||
|
|
||||
this = ref.getACall() and
|
||||
src = getAnArgument()
|
||||
call = ref.getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = src and succ = this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ module TaintedPath {
|
||||
srclabel instanceof Label::PosixPath and
|
||||
dstlabel instanceof Label::PosixPath and
|
||||
(
|
||||
any(UriLibraryStep step).step(src, dst)
|
||||
TaintTracking::uriStep(src, dst)
|
||||
or
|
||||
exists(DataFlow::CallNode decode |
|
||||
decode.getCalleeName() = "decodeURIComponent" or decode.getCalleeName() = "decodeURI"
|
||||
|
||||
Reference in New Issue
Block a user