Merge pull request #11087 from hvitved/dataflow/summary-ctx

Data flow: Add summary/return context to pruning stages 2-4
This commit is contained in:
Tom Hvitved
2022-11-29 10:36:53 +01:00
committed by GitHub
45 changed files with 10900 additions and 7992 deletions

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -319,8 +319,6 @@ private class ParamNodeEx extends NodeEx {
} }
ParameterPosition getPosition() { this.isParameterOf(_, result) } ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
} }
private class RetNodeEx extends NodeEx { private class RetNodeEx extends NodeEx {
@@ -608,6 +606,38 @@ private predicate hasSinkCallCtx(Configuration config) {
) )
} }
/**
* Holds if flow from `p` to a return node of kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[p, kind]
private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind) {
exists(ParameterPosition pos | p.isParameterOf(_, pos) |
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
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)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@@ -981,21 +1011,22 @@ private module Stage1 implements StageSig {
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
pragma[nomagic] pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(DataFlowCallable c, ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and p.getEnclosingCallable() = c and
exists(ap) and exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed parameterFlowThroughAllowed(p, kind)
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
) )
} }
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
throughFlowNodeCand(ret, config) and
kind = ret.getKind()
}
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, boolean toReturn | exists(ArgNodeEx arg, boolean toReturn |
@@ -1052,12 +1083,16 @@ private predicate viableReturnPosOutNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, Configuration config
) { ) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and exists(ReturnPosition pos |
viableReturnPosOutNodeCand1(call, pos, out, config) and
pos = ret.getReturnPosition() and
kind = pos.getKind() and
Stage1::revFlow(ret, config) and Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and not outBarrier(ret, config) and
not inBarrier(out, config) not inBarrier(out, config)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1087,10 +1122,11 @@ private predicate flowIntoCallNodeCand1(
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int branch(NodeEx n1, Configuration conf) { private int branch(NodeEx n1, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) flowOutOfCallNodeCand1(_, n1, _, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf)
) )
} }
@@ -1099,10 +1135,11 @@ private int branch(NodeEx n1, Configuration conf) {
* edge in the graph of paths between sources and sinks that ignores call * edge in the graph of paths between sources and sinks that ignores call
* contexts. * contexts.
*/ */
pragma[nomagic]
private int join(NodeEx n2, Configuration conf) { private int join(NodeEx n2, Configuration conf) {
result = result =
strictcount(NodeEx n | strictcount(NodeEx n |
flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) flowOutOfCallNodeCand1(_, n, _, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf)
) )
} }
@@ -1115,12 +1152,13 @@ private int join(NodeEx n2, Configuration conf) {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand1( private predicate flowOutOfCallNodeCand1(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, ret, out, config) and flowOutOfCallNodeCand1(call, ret, kind, out, pragma[only_bind_into](config)) and
exists(int b, int j | exists(int b, int j |
b = branch(ret, config) and b = branch(ret, pragma[only_bind_into](config)) and
j = join(out, config) and j = join(out, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1136,10 +1174,10 @@ pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config 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 | exists(int b, int j |
b = branch(arg, config) and b = branch(arg, pragma[only_bind_into](config)) and
j = join(p, config) and j = join(p, pragma[only_bind_into](config)) and
if b.minimum(j) <= config.fieldFlowBranchLimit() if b.minimum(j) <= config.fieldFlowBranchLimit()
then allowsFieldFlow = true then allowsFieldFlow = true
else allowsFieldFlow = false else allowsFieldFlow = false
@@ -1156,7 +1194,9 @@ private signature module StageSig {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config); predicate callMayFlowThroughRev(DataFlowCall call, Configuration config);
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@@ -1222,7 +1262,8 @@ private module MkStage<StageSig PrevStage> {
); );
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Configuration config
); );
predicate flowIntoCall( predicate flowIntoCall(
@@ -1247,14 +1288,14 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
Configuration config NodeEx out, boolean allowsFieldFlow, Configuration config
) { ) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _, PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
pragma[only_bind_into](config)) and matchesCall(ccc, call) and
matchesCall(ccc, call) c = ret.getEnclosingCallable()
} }
/** /**
@@ -1262,29 +1303,32 @@ private module MkStage<StageSig PrevStage> {
* configuration `config`. * configuration `config`.
* *
* The call context `cc` records whether the node is reached through an * The call context `cc` records whether the node is reached through an
* argument in a call, and if so, `argAp` records the access path of that * argument in a call, and if so, `summaryCtx` and `argAp` record the
* argument. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, argAp, ap, config) and fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config) filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, 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 sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
@@ -1295,65 +1339,82 @@ private module MkStage<StageSig PrevStage> {
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() argAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(mid, state, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and additionalJumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(mid, state0, _, _, nil, pragma[only_bind_into](config)) and fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, ap, config) and fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, _, apa, config) if PrevStage::parameterMayFlowThrough(node, apa, config)
then argAp = apSome(ap) then (
else argAp = apNone() summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
fwdFlowOutNotFromArg(node, state, cc, 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 or
exists(DataFlowCall call, Ap argAp0 | // flow through a callable
fwdFlowOutFromArg(call, node, state, argAp0, ap, config) and exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowIsEntered(call, cc, argAp, argAp0, config) fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowStore( private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, ApOption argAp, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType |
fwdFlow(node1, state, cc, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
@@ -1366,7 +1427,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) { private predicate fwdFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(TypedContent tc | exists(TypedContent tc |
fwdFlowStore(_, tail, tc, _, _, _, _, config) and fwdFlowStore(_, tail, tc, _, _, _, _, _, config) and
tc.getContent() = c and tc.getContent() = c and
cons = apCons(tc, tail) cons = apCons(tc, tail)
) )
@@ -1374,21 +1435,21 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, ApOption argAp, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, argAp, ap, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, ApOption argAp, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@@ -1396,29 +1457,19 @@ private module MkStage<StageSig PrevStage> {
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutNotFromArg( private predicate fwdFlowOutFromArg(
NodeEx out, FlowState state, Cc ccOut, ApOption argAp, Ap ap, Configuration config DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
) { ) {
exists( exists(
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, argAp, ap, config) and fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
inner = ret.getEnclosingCallable() and flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
ccOut = getCallContextReturn(inner, call, innercc) and config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
) parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, Ap argAp, Ap ap, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, state, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
@@ -1428,11 +1479,13 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx param |
fwdFlowIn(call, p, _, cc, _, argAp, ap, config) and fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition()
) )
} }
@@ -1440,27 +1493,40 @@ private module MkStage<StageSig PrevStage> {
private predicate storeStepFwd( private predicate storeStepFwd(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, Ap ap2, Configuration config
) { ) {
fwdFlowStore(node1, ap1, tc, node2, _, _, _, config) and fwdFlowStore(node1, ap1, tc, node2, _, _, _, _, config) and
ap2 = apCons(tc, ap1) and ap2 = apCons(tc, ap1) and
fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, config) fwdFlowRead(ap2, tc.getContent(), _, _, _, _, _, _, config)
} }
private predicate readStepFwd( private predicate readStepFwd(
NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config NodeEx n1, Ap ap1, Content c, NodeEx n2, Ap ap2, Configuration config
) { ) {
fwdFlowRead(ap1, c, n1, n2, _, _, _, config) and fwdFlowRead(ap1, c, n1, n2, _, _, _, _, config) and
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) { private predicate returnFlowsThrough0(
exists(Ap argAp0, NodeEx out, FlowState state, Cc cc, ApOption argAp, Ap ap | RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
fwdFlow(out, state, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
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 pragma[only_bind_into](config)) and
fwdFlowOutFromArg(call, out, state, argAp0, ap, config) and if allowsFieldFlow = false then ap instanceof ApNil else any()
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), )
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), }
pragma[only_bind_into](config))
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)
) )
} }
@@ -1468,118 +1534,130 @@ private module MkStage<StageSig PrevStage> {
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
) { ) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and exists(Ap argAp |
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](config)) and flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
PrevStage::parameterMayFlowThrough(p, _, _, pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config)) 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))
pragma[nomagic] )
private predicate returnNodeMayFlowThrough(
RetNodeEx ret, FlowState state, Ap ap, Configuration config
) {
fwdFlow(ret, state, any(CcCall ccc), apSome(_), ap, config)
} }
/** /**
* Holds if `node` with access path `ap` is part of a path from a source to a * Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`. * sink in the configuration `config`.
* *
* The Boolean `toReturn` records whether the node must be returned from the * The parameter `returnCtx` records whether (and how) the node must be returned
* enclosing callable in order to reach a sink, and if so, `returnAp` records * from the enclosing callable in order to reach a sink, and if so, `returnAp`
* the access path of the returned value. * records the access path of the returned value.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate revFlow( additional predicate revFlow(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
revFlow0(node, state, toReturn, returnAp, ap, config) and revFlow0(node, state, returnCtx, returnAp, ap, config) and
fwdFlow(node, state, _, _, ap, config) fwdFlow(node, state, _, _, _, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlow0( private predicate revFlow0(
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap,
Configuration config
) { ) {
fwdFlow(node, state, _, _, ap, config) and fwdFlow(node, state, _, _, _, ap, config) and
sinkNode(node, state, config) and sinkNode(node, state, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and (
if hasSinkCallCtx(config)
then returnCtx = TReturnCtxNoFlowThrough()
else returnCtx = TReturnCtxNone()
) and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
or or
exists(NodeEx mid, FlowState state0 | exists(NodeEx mid, FlowState state0 |
localStep(node, state, mid, state0, true, _, config, _) and localStep(node, state, mid, state0, true, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, ap, config) revFlow(mid, state0, returnCtx, returnAp, ap, config)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, pragma[only_bind_into](state), _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and localStep(node, pragma[only_bind_into](state), mid, state0, false, _, config, _) and
revFlow(mid, state0, toReturn, returnAp, nil, pragma[only_bind_into](config)) and revFlow(mid, state0, returnCtx, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
jumpStep(node, mid, config) and jumpStep(node, mid, config) and
revFlow(mid, state, _, _, ap, config) and revFlow(mid, state, _, _, ap, config) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() returnAp = apNone()
) )
or or
exists(NodeEx mid, ApNil nil | exists(NodeEx mid, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and additionalJumpStep(node, mid, config) and
revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and revFlow(pragma[only_bind_into](mid), state, _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
fwdFlow(node, _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(node, _, _, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStateStep(node, state, mid, state0, config) and additionalJumpStateStep(node, state, mid, state0, config) and
revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil, revFlow(pragma[only_bind_into](mid), pragma[only_bind_into](state0), _, _, nil,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
toReturn = false and returnCtx = TReturnCtxNone() and
returnAp = apNone() and returnAp = apNone() and
ap instanceof ApNil ap instanceof ApNil
) )
or or
// store // store
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
revFlowStore(ap0, c, ap, node, state, _, _, toReturn, returnAp, config) and revFlowStore(ap0, c, ap, node, state, _, _, returnCtx, returnAp, config) and
revFlowConsCand(ap0, c, ap, config) revFlowConsCand(ap0, c, ap, config)
) )
or or
// read // read
exists(NodeEx mid, Ap ap0 | exists(NodeEx mid, Ap ap0 |
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
readStepFwd(node, ap, _, mid, ap0, config) readStepFwd(node, ap, _, mid, ap0, config)
) )
or or
// flow into a callable // flow into a callable
revFlowInNotToReturn(node, state, returnAp, ap, config) and exists(ParamNodeEx p, boolean allowsFieldFlow |
toReturn = false 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 or
exists(DataFlowCall call, Ap returnAp0 | // flow through a callable
revFlowInToReturn(call, node, state, returnAp0, ap, config) and exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
or or
// flow out of a callable // flow out of a callable
revFlowOut(_, node, state, _, _, ap, config) and exists(ReturnKindExt kind |
toReturn = true and revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnNodeMayFlowThrough(node, state, ap, config) if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
then returnAp = apSome(ap) then (
else returnAp = apNone() returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
)
)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowStore( private predicate revFlowStore(
Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid, Ap ap0, Content c, Ap ap, NodeEx node, FlowState state, TypedContent tc, NodeEx mid,
boolean toReturn, ApOption returnAp, Configuration config ReturnCtx returnCtx, ApOption returnAp, Configuration config
) { ) {
revFlow(mid, state, toReturn, returnAp, ap0, config) and revFlow(mid, state, returnCtx, returnAp, ap0, config) and
storeStepFwd(node, ap, tc, mid, ap0, config) and storeStepFwd(node, ap, tc, mid, ap0, config) and
tc.getContent() = c tc.getContent() = c
} }
@@ -1599,35 +1677,27 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate revFlowOut( private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
Configuration config ApOption returnAp, Ap ap, Configuration config
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, toReturn, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and flowOutOfCall(call, ret, kind, 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, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, 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 | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, true, 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 flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@@ -1638,11 +1708,12 @@ private module MkStage<StageSig PrevStage> {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate revFlowIsReturned( private predicate revFlowIsReturned(
DataFlowCall call, boolean toReturn, ApOption returnAp, Ap ap, Configuration config DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
Configuration config
) { ) {
exists(RetNodeEx ret, FlowState state, CcCall ccc | exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, state, toReturn, returnAp, ap, config) and revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
fwdFlow(ret, state, ccc, apSome(_), ap, config) and returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
matchesCall(ccc, call) matchesCall(ccc, call)
) )
} }
@@ -1713,40 +1784,39 @@ private module MkStage<StageSig PrevStage> {
validAp(ap, config) validAp(ap, config)
} }
pragma[noinline] pragma[nomagic]
private predicate parameterFlow( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
) { ) {
revFlow(p, _, true, apSome(ap0), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
c = p.getEnclosingCallable() parameterFlowThroughAllowed(p, kind)
} }
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) { pragma[nomagic]
exists(RetNodeEx ret, FlowState state, Ap ap0, ReturnKindExt kind, ParameterPosition pos | predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
parameterFlow(p, ap, ap0, c, config) and exists(RetNodeEx ret, ReturnKindExt kind |
c = ret.getEnclosingCallable() and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
revFlow(pragma[only_bind_into](ret), pragma[only_bind_into](state), true, apSome(_), parameterFlowsThroughRev(p, ap, kind, config)
pragma[only_bind_into](ap0), pragma[only_bind_into](config)) and
fwdFlow(ret, state, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
) )
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(
Ap returnAp0, ArgNodeEx arg, FlowState state, boolean toReturn, ApOption returnAp, Ap ap ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
| |
revFlow(arg, state, toReturn, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnAp0, ap, config) and revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config) revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@@ -1754,14 +1824,13 @@ private module MkStage<StageSig PrevStage> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
) { ) {
fwd = true and fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, config)) and
fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and fields = count(TypedContent f0 | fwdConsCand(f0, _, config)) and
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, config)) and states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, Cc cc, ApOption argAp, Ap ap | count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
fwdFlow(n, state, cc, argAp, ap, config) Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
)
or or
fwd = false and fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -1769,8 +1838,8 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and conscand = count(TypedContent f0, Ap ap | consCand(f0, ap, config)) and
states = count(FlowState state | revFlow(_, state, _, _, _, config)) and states = count(FlowState state | revFlow(_, state, _, _, _, config)) and
tuples = tuples =
count(NodeEx n, FlowState state, boolean b, ApOption retAp, Ap ap | count(NodeEx n, FlowState state, ReturnCtx returnCtx, ApOption retAp, Ap ap |
revFlow(n, state, b, retAp, ap, config) revFlow(n, state, returnCtx, retAp, ap, config)
) )
} }
/* End: Stage logic. */ /* End: Stage logic. */
@@ -1915,7 +1984,7 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
exists(lcc) exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand1/5; predicate flowOutOfCall = flowOutOfCallNodeCand1/6;
predicate flowIntoCall = flowIntoCallNodeCand1/5; predicate flowIntoCall = flowIntoCallNodeCand1/5;
@@ -1951,9 +2020,10 @@ private module Stage2 implements StageSig {
pragma[nomagic] pragma[nomagic]
private predicate flowOutOfCallNodeCand2( private predicate flowOutOfCallNodeCand2(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowOutOfCallNodeCand1(call, node1, kind, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlowAlias(node1, pragma[only_bind_into](config)) Stage2::revFlowAlias(node1, pragma[only_bind_into](config))
} }
@@ -2021,8 +2091,8 @@ private module LocalFlowBigStep {
exists(NodeEx next | Stage2::revFlow(next, state, config) | exists(NodeEx next | Stage2::revFlow(next, state, config) |
jumpStep(node, next, config) or jumpStep(node, next, config) or
additionalJumpStep(node, next, config) or additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or flowIntoCallNodeCand2(_, node, next, _, config) or
flowOutOfCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand2(_, node, _, next, _, config) or
Stage2::storeStepCand(node, _, _, next, _, config) or Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config) Stage2::readStepCand(node, _, next, config)
) )
@@ -2163,7 +2233,7 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/5; predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5; predicate flowIntoCall = flowIntoCallNodeCand2/5;
@@ -2233,8 +2303,9 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, true, _, apf, config) and Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
) )
} }
@@ -2468,10 +2539,11 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
pragma[nomagic] pragma[nomagic]
predicate flowOutOfCall( predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, NodeEx node2, boolean allowsFieldFlow, Configuration config DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) { ) {
exists(FlowState state | exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, 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::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _, PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config))
@@ -2508,13 +2580,14 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic] pragma[nomagic]
private predicate nodeMayUseSummary0( private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
Stage4::parameterMayFlowThrough(_, c, _, _) and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, true, _, apa0, config) and Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
n.getEnclosingCallable() = c TAccessPathApproxSome(apa), apa0, config)
) )
} }
@@ -2522,9 +2595,10 @@ pragma[nomagic]
private predicate nodeMayUseSummary( private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(_, c, apa, config) and Stage4::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, state, apa, config) nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
) )
} }
@@ -2532,7 +2606,7 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), config) and Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage4::revFlow(p, state, _, config)
) )
} }
@@ -3453,17 +3527,11 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config AccessPathApprox apa, Configuration config
) { ) {
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos | exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and pathNode(mid, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and kind = ret.getKind() and
apa = ap.getApprox() and apa = ap.getApprox() and
pos = sc.getParameterPos() and parameterFlowThroughAllowed(sc.getParamNode(), kind)
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
) )
} }

View File

@@ -915,6 +915,17 @@ private module Cached {
TDataFlowCallNone() or TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call) TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -1304,6 +1315,44 @@ class DataFlowCallOption extends TDataFlowCallOption {
} }
} }
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
string toString() {
this = TParameterPositionNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*
* The possible values are:
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
string toString() {
this = TReturnCtxNone() and
result = "(none)"
or
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
)
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;