mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
JavaScript: Track flow into (simple) higher-order function calls.
The only case we support for now are functions that invoke one of their arguments, passing another argument as input.
This commit is contained in:
@@ -441,7 +441,8 @@ private predicate exploratoryFlowStep(
|
||||
) {
|
||||
basicFlowStep(pred, succ, _, cfg) or
|
||||
basicStoreStep(pred, succ, _) or
|
||||
loadStep(pred, succ, _)
|
||||
loadStep(pred, succ, _) or
|
||||
approximateCallbackStep(pred, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -618,6 +619,26 @@ private predicate flowThroughProperty(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` is passed as an argument to a function `f` which also takes a
|
||||
* callback parameter `cb` and then invokes `cb`, passing `pred` into parameter `succ`
|
||||
* of `cb`.
|
||||
*/
|
||||
private predicate flowIntoHigherOrderCall(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration cfg, PathSummary summary
|
||||
) {
|
||||
exists(
|
||||
Function f, DataFlow::InvokeNode fCall, DataFlow::Node fArg, DataFlow::FunctionNode cb,
|
||||
DataFlow::InvokeNode cbCall, int i, PathSummary oldSummary
|
||||
|
|
||||
reachableFromInput(f, fCall, pred, cbCall.getArgument(i), cfg, oldSummary) and
|
||||
argumentPassing(fCall, fArg, f, cbCall.getCalleeNode().getALocalSource()) and
|
||||
cb = fArg.getALocalSource() and
|
||||
succ = cb.getParameter(i) and
|
||||
summary = oldSummary.append(PathSummary::call())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a flow step from `pred` to `succ` described by `summary`
|
||||
* under configuration `cfg`.
|
||||
@@ -634,6 +655,9 @@ private predicate flowStep(
|
||||
or
|
||||
// Flow through a property write/read pair
|
||||
flowThroughProperty(pred, succ, cfg, summary)
|
||||
or
|
||||
// Flow into higher-order call
|
||||
flowIntoHigherOrderCall(pred, succ, cfg, summary)
|
||||
) and
|
||||
not cfg.isBarrier(succ) and
|
||||
not cfg.isBarrier(pred, succ) and
|
||||
|
||||
@@ -100,6 +100,8 @@ private module NodeTracking {
|
||||
basicStoreStep(mid, nd, _)
|
||||
or
|
||||
loadStep(mid, nd, _)
|
||||
or
|
||||
approximateCallbackStep(mid, nd)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -203,6 +205,26 @@ private module NodeTracking {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` is passed as an argument to a function `f` which also takes a
|
||||
* callback parameter `cb` and then invokes `cb`, passing `pred` into parameter `succ`
|
||||
* of `cb`.
|
||||
*/
|
||||
private predicate flowIntoHigherOrderCall(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PathSummary summary
|
||||
) {
|
||||
exists(
|
||||
Function f, DataFlow::InvokeNode fCall, DataFlow::Node fArg, DataFlow::FunctionNode cb,
|
||||
DataFlow::InvokeNode cbCall, int i, PathSummary oldSummary
|
||||
|
|
||||
reachableFromInput(f, fCall, pred, cbCall.getArgument(i), oldSummary) and
|
||||
argumentPassing(fCall, fArg, f, cbCall.getCalleeNode().getALocalSource()) and
|
||||
cb = fArg.getALocalSource() and
|
||||
succ = cb.getParameter(i) and
|
||||
summary = oldSummary.append(PathSummary::call())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a flow step from `pred` to `succ` described by `summary`.
|
||||
*/
|
||||
@@ -216,6 +238,9 @@ private module NodeTracking {
|
||||
or
|
||||
// Flow through a property write/read pair
|
||||
flowThroughProperty(pred, succ, summary)
|
||||
or
|
||||
// Flow into higher-order call
|
||||
flowIntoHigherOrderCall(pred, succ, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -235,6 +235,21 @@ predicate loadStep(DataFlow::Node pred, DataFlow::PropRead succ, string prop) {
|
||||
succ.accesses(pred, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a call with arguments `cb` and `pred`, and `succ` is
|
||||
* a parameter of a function that may flow into `cb`.
|
||||
*
|
||||
* This is an over-approximation of a possible data flow step through a callback
|
||||
* invocation.
|
||||
*/
|
||||
predicate approximateCallbackStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists (DataFlow::InvokeNode invk, DataFlow::FunctionNode cb |
|
||||
pred = invk.getAnArgument() and
|
||||
cb.flowsTo(invk.getAnArgument()) and
|
||||
succ = cb.getAParameter()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility class that is equivalent to `boolean` but does not require type joining.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user