mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
Data flow: Sync files
This commit is contained in:
@@ -613,11 +613,28 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[p, kind]
|
||||
private predicate parameterFlowThroughAllowed(ParamNode p, ReturnKindExt kind) {
|
||||
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
|
||||
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
|
||||
not kind.(ParamUpdateReturnKind).getPosition() = pos
|
||||
or
|
||||
allowParameterReturnInSelfCached(p)
|
||||
allowParameterReturnInSelfCached(p.asNode())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
||||
* kind `kind` is allowed.
|
||||
*
|
||||
* We don't expect a parameter to return stored in itself, unless
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[c, pos, kind]
|
||||
private predicate parameterFlowThroughAllowed(
|
||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
p.isParameterOf(c, pos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1000,14 +1017,14 @@ private module Stage1 implements StageSig {
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
exists(ap) and
|
||||
parameterFlowThroughAllowed(p.asNode(), kind)
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
throughFlowNodeCand(ret, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1066,13 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, Configuration config
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
exists(ReturnPosition pos |
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
kind = pos.getKind() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1102,6 +1122,7 @@ private predicate flowIntoCallNodeCand1(
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int branch(NodeEx n1, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1114,6 +1135,7 @@ private int branch(NodeEx n1, Configuration conf) {
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int join(NodeEx n2, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1130,10 +1152,10 @@ private int join(NodeEx n2, Configuration conf) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, ret, pos, out, pragma[only_bind_into](config)) and
|
||||
flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(ret, pragma[only_bind_into](config)) and
|
||||
j = join(out, pragma[only_bind_into](config)) and
|
||||
@@ -1152,10 +1174,10 @@ pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
flowIntoCallNodeCand1(call, arg, p, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(arg, config) and
|
||||
j = join(p, config) and
|
||||
b = branch(arg, pragma[only_bind_into](config)) and
|
||||
j = join(p, pragma[only_bind_into](config)) and
|
||||
if b.minimum(j) <= config.fieldFlowBranchLimit()
|
||||
then allowsFieldFlow = true
|
||||
else allowsFieldFlow = false
|
||||
@@ -1174,7 +1196,7 @@ private signature module StageSig {
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config);
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
||||
|
||||
predicate storeStepCand(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||
@@ -1240,7 +1262,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
);
|
||||
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
);
|
||||
|
||||
@@ -1266,16 +1288,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, NodeEx out,
|
||||
boolean allowsFieldFlow, Configuration config
|
||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
kind = pos.getKind() and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, pos, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call) and
|
||||
c = ret.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1284,12 +1304,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `summaryCtx` and `argAp` record the
|
||||
* corresponding parameter and access path of that argument, respectively.
|
||||
* corresponding parameter position and access path of that argument, respectively.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
||||
@@ -1298,13 +1318,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
ap = getApNil(node)
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
@@ -1322,7 +1342,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1330,7 +1350,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1339,7 +1359,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1362,17 +1382,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
apa = getApprox(ap) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and argAp = apSome(ap)
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOutNotFromArg(node, state, cc, summaryCtx, argAp, ap, config)
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
cc = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParamNode summaryCtx0, Ap argAp0 |
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
)
|
||||
@@ -1381,7 +1411,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
||||
@@ -1406,7 +1436,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1416,7 +1446,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
||||
@@ -1427,32 +1457,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutNotFromArg(
|
||||
NodeEx out, FlowState state, Cc ccOut, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
ccOut = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParamNode summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc |
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(summaryCtx), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, kind, out, allowsFieldFlow, config) and
|
||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
||||
config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(summaryCtx, kind)
|
||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1462,13 +1479,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ParamNode p, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
||||
p = param.asNode()
|
||||
pos = param.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1489,23 +1506,41 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNode p, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate returnFlowsThrough0(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(p), apSome(argAp), ap, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
exists(boolean allowsFieldFlow |
|
||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, _, pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p.asNode(), _, _, pragma[only_bind_into](config))
|
||||
exists(Ap argAp |
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1591,21 +1626,25 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowInNotToReturn(node, state, returnAp, ap, config) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnPosition returnPos0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1638,37 +1677,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInNotToReturn(
|
||||
ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnPosition returnPos, Ap returnAp,
|
||||
Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(returnPos), apSome(returnAp), ap, config) and
|
||||
revFlow(pragma[only_bind_into](p), state,
|
||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1679,12 +1708,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1757,37 +1786,37 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnPosition returnPos, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(returnPos), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
exists(ParamNodeEx p, Ap ap |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(
|
||||
ReturnPosition returnPos0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
|
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturn(call, arg, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1829,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -1992,10 +2020,10 @@ private module Stage2 implements StageSig {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -2511,11 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
exists(FlowState state |
|
||||
flowOutOfCallNodeCand2(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||
pragma[only_bind_into](config))
|
||||
@@ -2552,12 +2580,13 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(p, _, _) and
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2566,9 +2595,10 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3501,7 +3531,7 @@ private predicate paramFlowsThrough(
|
||||
pathNode(mid, ret, state, cc, sc, ap, config, _) and
|
||||
kind = ret.getKind() and
|
||||
apa = ap.getApprox() and
|
||||
parameterFlowThroughAllowed(sc.getParamNode().asNode(), kind)
|
||||
parameterFlowThroughAllowed(sc.getParamNode(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -613,11 +613,28 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[p, kind]
|
||||
private predicate parameterFlowThroughAllowed(ParamNode p, ReturnKindExt kind) {
|
||||
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
|
||||
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
|
||||
not kind.(ParamUpdateReturnKind).getPosition() = pos
|
||||
or
|
||||
allowParameterReturnInSelfCached(p)
|
||||
allowParameterReturnInSelfCached(p.asNode())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
||||
* kind `kind` is allowed.
|
||||
*
|
||||
* We don't expect a parameter to return stored in itself, unless
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[c, pos, kind]
|
||||
private predicate parameterFlowThroughAllowed(
|
||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
p.isParameterOf(c, pos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1000,14 +1017,14 @@ private module Stage1 implements StageSig {
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
exists(ap) and
|
||||
parameterFlowThroughAllowed(p.asNode(), kind)
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
throughFlowNodeCand(ret, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1066,13 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, Configuration config
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
exists(ReturnPosition pos |
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
kind = pos.getKind() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1102,6 +1122,7 @@ private predicate flowIntoCallNodeCand1(
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int branch(NodeEx n1, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1114,6 +1135,7 @@ private int branch(NodeEx n1, Configuration conf) {
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int join(NodeEx n2, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1130,10 +1152,10 @@ private int join(NodeEx n2, Configuration conf) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, ret, pos, out, pragma[only_bind_into](config)) and
|
||||
flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(ret, pragma[only_bind_into](config)) and
|
||||
j = join(out, pragma[only_bind_into](config)) and
|
||||
@@ -1152,10 +1174,10 @@ pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
flowIntoCallNodeCand1(call, arg, p, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(arg, config) and
|
||||
j = join(p, config) and
|
||||
b = branch(arg, pragma[only_bind_into](config)) and
|
||||
j = join(p, pragma[only_bind_into](config)) and
|
||||
if b.minimum(j) <= config.fieldFlowBranchLimit()
|
||||
then allowsFieldFlow = true
|
||||
else allowsFieldFlow = false
|
||||
@@ -1174,7 +1196,7 @@ private signature module StageSig {
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config);
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
||||
|
||||
predicate storeStepCand(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||
@@ -1240,7 +1262,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
);
|
||||
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
);
|
||||
|
||||
@@ -1266,16 +1288,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, NodeEx out,
|
||||
boolean allowsFieldFlow, Configuration config
|
||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
kind = pos.getKind() and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, pos, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call) and
|
||||
c = ret.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1284,12 +1304,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `summaryCtx` and `argAp` record the
|
||||
* corresponding parameter and access path of that argument, respectively.
|
||||
* corresponding parameter position and access path of that argument, respectively.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
||||
@@ -1298,13 +1318,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
ap = getApNil(node)
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
@@ -1322,7 +1342,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1330,7 +1350,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1339,7 +1359,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1362,17 +1382,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
apa = getApprox(ap) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and argAp = apSome(ap)
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOutNotFromArg(node, state, cc, summaryCtx, argAp, ap, config)
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
cc = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParamNode summaryCtx0, Ap argAp0 |
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
)
|
||||
@@ -1381,7 +1411,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
||||
@@ -1406,7 +1436,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1416,7 +1446,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
||||
@@ -1427,32 +1457,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutNotFromArg(
|
||||
NodeEx out, FlowState state, Cc ccOut, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
ccOut = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParamNode summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc |
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(summaryCtx), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, kind, out, allowsFieldFlow, config) and
|
||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
||||
config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(summaryCtx, kind)
|
||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1462,13 +1479,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ParamNode p, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
||||
p = param.asNode()
|
||||
pos = param.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1489,23 +1506,41 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNode p, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate returnFlowsThrough0(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(p), apSome(argAp), ap, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
exists(boolean allowsFieldFlow |
|
||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, _, pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p.asNode(), _, _, pragma[only_bind_into](config))
|
||||
exists(Ap argAp |
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1591,21 +1626,25 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowInNotToReturn(node, state, returnAp, ap, config) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnPosition returnPos0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1638,37 +1677,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInNotToReturn(
|
||||
ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnPosition returnPos, Ap returnAp,
|
||||
Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(returnPos), apSome(returnAp), ap, config) and
|
||||
revFlow(pragma[only_bind_into](p), state,
|
||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1679,12 +1708,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1757,37 +1786,37 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnPosition returnPos, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(returnPos), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
exists(ParamNodeEx p, Ap ap |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(
|
||||
ReturnPosition returnPos0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
|
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturn(call, arg, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1829,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -1992,10 +2020,10 @@ private module Stage2 implements StageSig {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -2511,11 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
exists(FlowState state |
|
||||
flowOutOfCallNodeCand2(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||
pragma[only_bind_into](config))
|
||||
@@ -2552,12 +2580,13 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(p, _, _) and
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2566,9 +2595,10 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3501,7 +3531,7 @@ private predicate paramFlowsThrough(
|
||||
pathNode(mid, ret, state, cc, sc, ap, config, _) and
|
||||
kind = ret.getKind() and
|
||||
apa = ap.getApprox() and
|
||||
parameterFlowThroughAllowed(sc.getParamNode().asNode(), kind)
|
||||
parameterFlowThroughAllowed(sc.getParamNode(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -613,11 +613,28 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[p, kind]
|
||||
private predicate parameterFlowThroughAllowed(ParamNode p, ReturnKindExt kind) {
|
||||
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
|
||||
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
|
||||
not kind.(ParamUpdateReturnKind).getPosition() = pos
|
||||
or
|
||||
allowParameterReturnInSelfCached(p)
|
||||
allowParameterReturnInSelfCached(p.asNode())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
||||
* kind `kind` is allowed.
|
||||
*
|
||||
* We don't expect a parameter to return stored in itself, unless
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[c, pos, kind]
|
||||
private predicate parameterFlowThroughAllowed(
|
||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
p.isParameterOf(c, pos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1000,14 +1017,14 @@ private module Stage1 implements StageSig {
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
exists(ap) and
|
||||
parameterFlowThroughAllowed(p.asNode(), kind)
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
throughFlowNodeCand(ret, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1066,13 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, Configuration config
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
exists(ReturnPosition pos |
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
kind = pos.getKind() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1102,6 +1122,7 @@ private predicate flowIntoCallNodeCand1(
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int branch(NodeEx n1, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1114,6 +1135,7 @@ private int branch(NodeEx n1, Configuration conf) {
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int join(NodeEx n2, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1130,10 +1152,10 @@ private int join(NodeEx n2, Configuration conf) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, ret, pos, out, pragma[only_bind_into](config)) and
|
||||
flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(ret, pragma[only_bind_into](config)) and
|
||||
j = join(out, pragma[only_bind_into](config)) and
|
||||
@@ -1152,10 +1174,10 @@ pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
flowIntoCallNodeCand1(call, arg, p, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(arg, config) and
|
||||
j = join(p, config) and
|
||||
b = branch(arg, pragma[only_bind_into](config)) and
|
||||
j = join(p, pragma[only_bind_into](config)) and
|
||||
if b.minimum(j) <= config.fieldFlowBranchLimit()
|
||||
then allowsFieldFlow = true
|
||||
else allowsFieldFlow = false
|
||||
@@ -1174,7 +1196,7 @@ private signature module StageSig {
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config);
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
||||
|
||||
predicate storeStepCand(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||
@@ -1240,7 +1262,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
);
|
||||
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
);
|
||||
|
||||
@@ -1266,16 +1288,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, NodeEx out,
|
||||
boolean allowsFieldFlow, Configuration config
|
||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
kind = pos.getKind() and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, pos, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call) and
|
||||
c = ret.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1284,12 +1304,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `summaryCtx` and `argAp` record the
|
||||
* corresponding parameter and access path of that argument, respectively.
|
||||
* corresponding parameter position and access path of that argument, respectively.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
||||
@@ -1298,13 +1318,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
ap = getApNil(node)
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
@@ -1322,7 +1342,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1330,7 +1350,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1339,7 +1359,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1362,17 +1382,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
apa = getApprox(ap) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and argAp = apSome(ap)
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOutNotFromArg(node, state, cc, summaryCtx, argAp, ap, config)
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
cc = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParamNode summaryCtx0, Ap argAp0 |
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
)
|
||||
@@ -1381,7 +1411,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
||||
@@ -1406,7 +1436,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1416,7 +1446,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
||||
@@ -1427,32 +1457,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutNotFromArg(
|
||||
NodeEx out, FlowState state, Cc ccOut, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
ccOut = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParamNode summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc |
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(summaryCtx), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, kind, out, allowsFieldFlow, config) and
|
||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
||||
config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(summaryCtx, kind)
|
||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1462,13 +1479,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ParamNode p, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
||||
p = param.asNode()
|
||||
pos = param.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1489,23 +1506,41 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNode p, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate returnFlowsThrough0(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(p), apSome(argAp), ap, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
exists(boolean allowsFieldFlow |
|
||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, _, pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p.asNode(), _, _, pragma[only_bind_into](config))
|
||||
exists(Ap argAp |
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1591,21 +1626,25 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowInNotToReturn(node, state, returnAp, ap, config) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnPosition returnPos0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1638,37 +1677,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInNotToReturn(
|
||||
ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnPosition returnPos, Ap returnAp,
|
||||
Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(returnPos), apSome(returnAp), ap, config) and
|
||||
revFlow(pragma[only_bind_into](p), state,
|
||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1679,12 +1708,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1757,37 +1786,37 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnPosition returnPos, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(returnPos), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
exists(ParamNodeEx p, Ap ap |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(
|
||||
ReturnPosition returnPos0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
|
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturn(call, arg, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1829,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -1992,10 +2020,10 @@ private module Stage2 implements StageSig {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -2511,11 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
exists(FlowState state |
|
||||
flowOutOfCallNodeCand2(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||
pragma[only_bind_into](config))
|
||||
@@ -2552,12 +2580,13 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(p, _, _) and
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2566,9 +2595,10 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3501,7 +3531,7 @@ private predicate paramFlowsThrough(
|
||||
pathNode(mid, ret, state, cc, sc, ap, config, _) and
|
||||
kind = ret.getKind() and
|
||||
apa = ap.getApprox() and
|
||||
parameterFlowThroughAllowed(sc.getParamNode().asNode(), kind)
|
||||
parameterFlowThroughAllowed(sc.getParamNode(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -613,11 +613,28 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[p, kind]
|
||||
private predicate parameterFlowThroughAllowed(ParamNode p, ReturnKindExt kind) {
|
||||
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
|
||||
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
|
||||
not kind.(ParamUpdateReturnKind).getPosition() = pos
|
||||
or
|
||||
allowParameterReturnInSelfCached(p)
|
||||
allowParameterReturnInSelfCached(p.asNode())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
||||
* kind `kind` is allowed.
|
||||
*
|
||||
* We don't expect a parameter to return stored in itself, unless
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[c, pos, kind]
|
||||
private predicate parameterFlowThroughAllowed(
|
||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
p.isParameterOf(c, pos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1000,14 +1017,14 @@ private module Stage1 implements StageSig {
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
exists(ap) and
|
||||
parameterFlowThroughAllowed(p.asNode(), kind)
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
throughFlowNodeCand(ret, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1066,13 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, Configuration config
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
exists(ReturnPosition pos |
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
kind = pos.getKind() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1102,6 +1122,7 @@ private predicate flowIntoCallNodeCand1(
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int branch(NodeEx n1, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1114,6 +1135,7 @@ private int branch(NodeEx n1, Configuration conf) {
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int join(NodeEx n2, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1130,10 +1152,10 @@ private int join(NodeEx n2, Configuration conf) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, ret, pos, out, pragma[only_bind_into](config)) and
|
||||
flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(ret, pragma[only_bind_into](config)) and
|
||||
j = join(out, pragma[only_bind_into](config)) and
|
||||
@@ -1152,10 +1174,10 @@ pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
flowIntoCallNodeCand1(call, arg, p, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(arg, config) and
|
||||
j = join(p, config) and
|
||||
b = branch(arg, pragma[only_bind_into](config)) and
|
||||
j = join(p, pragma[only_bind_into](config)) and
|
||||
if b.minimum(j) <= config.fieldFlowBranchLimit()
|
||||
then allowsFieldFlow = true
|
||||
else allowsFieldFlow = false
|
||||
@@ -1174,7 +1196,7 @@ private signature module StageSig {
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config);
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
||||
|
||||
predicate storeStepCand(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||
@@ -1240,7 +1262,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
);
|
||||
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
);
|
||||
|
||||
@@ -1266,16 +1288,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, NodeEx out,
|
||||
boolean allowsFieldFlow, Configuration config
|
||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
kind = pos.getKind() and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, pos, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call) and
|
||||
c = ret.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1284,12 +1304,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `summaryCtx` and `argAp` record the
|
||||
* corresponding parameter and access path of that argument, respectively.
|
||||
* corresponding parameter position and access path of that argument, respectively.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
||||
@@ -1298,13 +1318,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
ap = getApNil(node)
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
@@ -1322,7 +1342,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1330,7 +1350,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1339,7 +1359,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1362,17 +1382,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
apa = getApprox(ap) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and argAp = apSome(ap)
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOutNotFromArg(node, state, cc, summaryCtx, argAp, ap, config)
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
cc = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParamNode summaryCtx0, Ap argAp0 |
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
)
|
||||
@@ -1381,7 +1411,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
||||
@@ -1406,7 +1436,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1416,7 +1446,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
||||
@@ -1427,32 +1457,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutNotFromArg(
|
||||
NodeEx out, FlowState state, Cc ccOut, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
ccOut = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParamNode summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc |
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(summaryCtx), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, kind, out, allowsFieldFlow, config) and
|
||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
||||
config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(summaryCtx, kind)
|
||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1462,13 +1479,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ParamNode p, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
||||
p = param.asNode()
|
||||
pos = param.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1489,23 +1506,41 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNode p, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate returnFlowsThrough0(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(p), apSome(argAp), ap, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
exists(boolean allowsFieldFlow |
|
||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, _, pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p.asNode(), _, _, pragma[only_bind_into](config))
|
||||
exists(Ap argAp |
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1591,21 +1626,25 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowInNotToReturn(node, state, returnAp, ap, config) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnPosition returnPos0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1638,37 +1677,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInNotToReturn(
|
||||
ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnPosition returnPos, Ap returnAp,
|
||||
Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(returnPos), apSome(returnAp), ap, config) and
|
||||
revFlow(pragma[only_bind_into](p), state,
|
||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1679,12 +1708,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1757,37 +1786,37 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnPosition returnPos, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(returnPos), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
exists(ParamNodeEx p, Ap ap |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(
|
||||
ReturnPosition returnPos0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
|
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturn(call, arg, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1829,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -1992,10 +2020,10 @@ private module Stage2 implements StageSig {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -2511,11 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
exists(FlowState state |
|
||||
flowOutOfCallNodeCand2(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||
pragma[only_bind_into](config))
|
||||
@@ -2552,12 +2580,13 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(p, _, _) and
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2566,9 +2595,10 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3501,7 +3531,7 @@ private predicate paramFlowsThrough(
|
||||
pathNode(mid, ret, state, cc, sc, ap, config, _) and
|
||||
kind = ret.getKind() and
|
||||
apa = ap.getApprox() and
|
||||
parameterFlowThroughAllowed(sc.getParamNode().asNode(), kind)
|
||||
parameterFlowThroughAllowed(sc.getParamNode(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -916,15 +916,15 @@ private module Cached {
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TParamNodeOption =
|
||||
TParamNodeNone() or
|
||||
TParamNodeSome(ParamNode p)
|
||||
newtype TParameterPositionOption =
|
||||
TParameterPositionNone() or
|
||||
TParameterPositionSome(ParameterPosition pos)
|
||||
|
||||
cached
|
||||
newtype TReturnCtx =
|
||||
TReturnCtxNone() or
|
||||
TReturnCtxNoFlowThrough() or
|
||||
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
|
||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
@@ -1315,15 +1315,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `ParamNode`. */
|
||||
class ParamNodeOption extends TParamNodeOption {
|
||||
/** An optional `ParameterPosition`. */
|
||||
class ParameterPositionOption extends TParameterPositionOption {
|
||||
string toString() {
|
||||
this = TParamNodeNone() and
|
||||
this = TParameterPositionNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(ParamNode p |
|
||||
this = TParamNodeSome(p) and
|
||||
result = p.toString()
|
||||
exists(ParameterPosition pos |
|
||||
this = TParameterPositionSome(pos) and
|
||||
result = pos.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1335,7 +1335,7 @@ class ParamNodeOption extends TParamNodeOption {
|
||||
*
|
||||
* - `TReturnCtxNone()`: no return flow.
|
||||
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
|
||||
* flow through may be possible.
|
||||
*/
|
||||
class ReturnCtx extends TReturnCtx {
|
||||
@@ -1346,9 +1346,9 @@ class ReturnCtx extends TReturnCtx {
|
||||
this = TReturnCtxNoFlowThrough() and
|
||||
result = "(no flow through)"
|
||||
or
|
||||
exists(ReturnPosition pos |
|
||||
this = TReturnCtxMaybeFlowThrough(pos) and
|
||||
result = pos.toString()
|
||||
exists(ReturnKindExt kind |
|
||||
this = TReturnCtxMaybeFlowThrough(kind) and
|
||||
result = kind.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,11 +613,28 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[p, kind]
|
||||
private predicate parameterFlowThroughAllowed(ParamNode p, ReturnKindExt kind) {
|
||||
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
|
||||
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
|
||||
not kind.(ParamUpdateReturnKind).getPosition() = pos
|
||||
or
|
||||
allowParameterReturnInSelfCached(p)
|
||||
allowParameterReturnInSelfCached(p.asNode())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
||||
* kind `kind` is allowed.
|
||||
*
|
||||
* We don't expect a parameter to return stored in itself, unless
|
||||
* explicitly allowed
|
||||
*/
|
||||
bindingset[c, pos, kind]
|
||||
private predicate parameterFlowThroughAllowed(
|
||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
p.isParameterOf(c, pos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1000,14 +1017,14 @@ private module Stage1 implements StageSig {
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
exists(ap) and
|
||||
parameterFlowThroughAllowed(p.asNode(), kind)
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
throughFlowNodeCand(ret, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1066,13 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, Configuration config
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
exists(ReturnPosition pos |
|
||||
viableReturnPosOutNodeCand1(call, pos, out, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
kind = pos.getKind() and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1102,6 +1122,7 @@ private predicate flowIntoCallNodeCand1(
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int branch(NodeEx n1, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1114,6 +1135,7 @@ private int branch(NodeEx n1, Configuration conf) {
|
||||
* edge in the graph of paths between sources and sinks that ignores call
|
||||
* contexts.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int join(NodeEx n2, Configuration conf) {
|
||||
result =
|
||||
strictcount(NodeEx n |
|
||||
@@ -1130,10 +1152,10 @@ private int join(NodeEx n2, Configuration conf) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand1(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, ret, pos, out, pragma[only_bind_into](config)) and
|
||||
flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(ret, pragma[only_bind_into](config)) and
|
||||
j = join(out, pragma[only_bind_into](config)) and
|
||||
@@ -1152,10 +1174,10 @@ pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
flowIntoCallNodeCand1(call, arg, p, pragma[only_bind_into](config)) and
|
||||
exists(int b, int j |
|
||||
b = branch(arg, config) and
|
||||
j = join(p, config) and
|
||||
b = branch(arg, pragma[only_bind_into](config)) and
|
||||
j = join(p, pragma[only_bind_into](config)) and
|
||||
if b.minimum(j) <= config.fieldFlowBranchLimit()
|
||||
then allowsFieldFlow = true
|
||||
else allowsFieldFlow = false
|
||||
@@ -1174,7 +1196,7 @@ private signature module StageSig {
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config);
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
||||
|
||||
predicate storeStepCand(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||
@@ -1240,7 +1262,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
);
|
||||
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
);
|
||||
|
||||
@@ -1266,16 +1288,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, NodeEx out,
|
||||
boolean allowsFieldFlow, Configuration config
|
||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
kind = pos.getKind() and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, pos, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
||||
matchesCall(ccc, call) and
|
||||
c = ret.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1284,12 +1304,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `summaryCtx` and `argAp` record the
|
||||
* corresponding parameter and access path of that argument, respectively.
|
||||
* corresponding parameter position and access path of that argument, respectively.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
||||
@@ -1298,13 +1318,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
ap = getApNil(node)
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
@@ -1322,7 +1342,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1330,7 +1350,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1339,7 +1359,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node)
|
||||
)
|
||||
@@ -1362,17 +1382,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
apa = getApprox(ap) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and argAp = apSome(ap)
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOutNotFromArg(node, state, cc, summaryCtx, argAp, ap, config)
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
cc = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParamNode summaryCtx0, Ap argAp0 |
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
)
|
||||
@@ -1381,7 +1411,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
||||
@@ -1406,7 +1436,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1416,7 +1446,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
||||
@@ -1427,32 +1457,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutNotFromArg(
|
||||
NodeEx out, FlowState state, Cc ccOut, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(
|
||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||
DataFlowCallable inner
|
||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
||||
|
|
||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, _, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
ccOut = getCallContextReturn(inner, call, innercc) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParamNode summaryCtx, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc |
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(summaryCtx), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, kind, out, allowsFieldFlow, config) and
|
||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
||||
config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(summaryCtx, kind)
|
||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1462,13 +1479,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ParamNode p, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
||||
p = param.asNode()
|
||||
pos = param.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1489,23 +1506,41 @@ private module MkStage<StageSig PrevStage> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNode p, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate returnFlowsThrough0(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow(ret, state, ccc, TParamNodeSome(p), apSome(argAp), ap, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
exists(boolean allowsFieldFlow |
|
||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, _, pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p.asNode(), _, _, pragma[only_bind_into](config))
|
||||
exists(Ap argAp |
|
||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1591,21 +1626,25 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowInNotToReturn(node, state, returnAp, ap, config) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
returnCtx = TReturnCtxNone()
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnPosition returnPos0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1638,37 +1677,27 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCall(call, ret, pos, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInNotToReturn(
|
||||
ArgNodeEx arg, FlowState state, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
|
||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnPosition returnPos, Ap returnAp,
|
||||
Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(returnPos), apSome(returnAp), ap, config) and
|
||||
revFlow(pragma[only_bind_into](p), state,
|
||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1679,12 +1708,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1757,37 +1786,37 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnPosition returnPos, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(returnPos), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p.asNode(), returnPos.getKind())
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnPosition pos, Configuration config) {
|
||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
||||
exists(ParamNodeEx p, Ap ap |
|
||||
returnFlowsThrough(ret, pos, _, _, p.asNode(), ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, config)
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(
|
||||
ReturnPosition returnPos0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
|
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturn(call, arg, state, returnPos0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnPos0, returnAp0, config)
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1829,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -1992,10 +2020,10 @@ private module Stage2 implements StageSig {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -2511,11 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate flowOutOfCall(
|
||||
DataFlowCall call, RetNodeEx node1, ReturnPosition pos, NodeEx node2, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
) {
|
||||
exists(FlowState state |
|
||||
flowOutOfCallNodeCand2(call, node1, pos, node2, allowsFieldFlow, config) and
|
||||
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||
pragma[only_bind_into](config))
|
||||
@@ -2552,12 +2580,13 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(p, _, _) and
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2566,9 +2595,10 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3501,7 +3531,7 @@ private predicate paramFlowsThrough(
|
||||
pathNode(mid, ret, state, cc, sc, ap, config, _) and
|
||||
kind = ret.getKind() and
|
||||
apa = ap.getApprox() and
|
||||
parameterFlowThroughAllowed(sc.getParamNode().asNode(), kind)
|
||||
parameterFlowThroughAllowed(sc.getParamNode(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user