JavaScript: Track flow through forwarding higher-order calls.

This commit is contained in:
Max Schaefer
2019-01-11 09:15:58 +00:00
parent 59bac829b1
commit 7d2d33840a
7 changed files with 49 additions and 13 deletions

View File

@@ -442,7 +442,8 @@ private predicate exploratoryFlowStep(
basicFlowStep(pred, succ, _, cfg) or
basicStoreStep(pred, succ, _) or
loadStep(pred, succ, _) or
approximateCallbackStep(pred, succ)
approximateCallbackStep(pred, succ) or
succ = pred.(DataFlow::FunctionNode).getAParameter()
}
/**
@@ -628,9 +629,20 @@ private predicate flowThroughProperty(
private predicate higherOrderCall(
DataFlow::Node arg, DataFlow::Node cb, int i, DataFlow::Configuration cfg, PathSummary summary
) {
exists (Function f, DataFlow::InvokeNode outer, DataFlow::InvokeNode inner |
reachableFromInput(f, outer, arg, inner.getArgument(i), cfg, summary) and
argumentPassing(outer, cb, f, inner.getCalleeNode().getALocalSource())
exists (Function f, DataFlow::InvokeNode outer, DataFlow::InvokeNode inner, int j,
DataFlow::Node innerArg, DataFlow::ParameterNode cbParm, PathSummary oldSummary |
reachableFromInput(f, outer, arg, innerArg, cfg, oldSummary) and
argumentPassing(outer, cb, f, cbParm) and
innerArg = inner.getArgument(j) |
cbParm.flowsTo(inner.getCalleeNode()) and
i = j and
summary = oldSummary
or
exists (DataFlow::Node cbArg, PathSummary newSummary |
cbParm.flowsTo(cbArg) and
higherOrderCall(innerArg, cbArg, i, cfg, newSummary) and
summary = oldSummary.append(PathSummary::call()).append(newSummary)
)
)
}

View File

@@ -102,6 +102,8 @@ private module NodeTracking {
loadStep(mid, nd, _)
or
approximateCallbackStep(mid, nd)
or
nd = mid.(DataFlow::FunctionNode).getAParameter()
)
}
@@ -213,9 +215,20 @@ private module NodeTracking {
private predicate higherOrderCall(
DataFlow::Node arg, DataFlow::Node cb, int i, PathSummary summary
) {
exists (Function f, DataFlow::InvokeNode outer, DataFlow::InvokeNode inner |
reachableFromInput(f, outer, arg, inner.getArgument(i), summary) and
argumentPassing(outer, cb, f, inner.getCalleeNode().getALocalSource())
exists (Function f, DataFlow::InvokeNode outer, DataFlow::InvokeNode inner, int j,
DataFlow::Node innerArg, DataFlow::ParameterNode cbParm, PathSummary oldSummary |
reachableFromInput(f, outer, arg, innerArg, oldSummary) and
argumentPassing(outer, cb, f, cbParm) and
innerArg = inner.getArgument(j) |
cbParm.flowsTo(inner.getCalleeNode()) and
i = j and
summary = oldSummary
or
exists (DataFlow::Node cbArg, PathSummary newSummary |
cbParm.flowsTo(cbArg) and
higherOrderCall(innerArg, cbArg, i, newSummary) and
summary = oldSummary.append(PathSummary::call()).append(newSummary)
)
)
}

View File

@@ -236,17 +236,17 @@ predicate loadStep(DataFlow::Node pred, DataFlow::PropRead succ, string 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`.
* Holds if there is a call with argument `pred`, and `succ` flows into the callee
* position of that call.
*
* 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 |
predicate approximateCallbackStep(DataFlow::Node pred, DataFlow::SourceNode succ) {
exists (DataFlow::InvokeNode invk, DataFlow::ParameterNode cb |
pred = invk.getAnArgument() and
cb.flowsTo(invk.getAnArgument()) and
succ = cb.getAParameter()
cb.flowsTo(invk.getCalleeNode()) and
callStep(any(DataFlow::Node nd | succ.flowsTo(nd)), cb)
)
}