mirror of
https://github.com/github/codeql.git
synced 2025-12-23 20:26:32 +01:00
Merge branch 'main' into mathiasvp/replace-ast-with-ir-use-usedataflow
This commit is contained in:
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -916,15 +916,15 @@ private module Cached {
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TParameterPositionOption =
|
||||
TParameterPositionNone() or
|
||||
TParameterPositionSome(ParameterPosition pos)
|
||||
newtype TParamNodeOption =
|
||||
TParamNodeNone() or
|
||||
TParamNodeSome(ParamNode p)
|
||||
|
||||
cached
|
||||
newtype TReturnCtx =
|
||||
TReturnCtxNone() or
|
||||
TReturnCtxNoFlowThrough() or
|
||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
|
||||
|
||||
cached
|
||||
newtype TTypedContentApprox =
|
||||
@@ -1343,15 +1343,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `ParameterPosition`. */
|
||||
class ParameterPositionOption extends TParameterPositionOption {
|
||||
/** An optional `ParamNode`. */
|
||||
class ParamNodeOption extends TParamNodeOption {
|
||||
string toString() {
|
||||
this = TParameterPositionNone() and
|
||||
this = TParamNodeNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
this = TParameterPositionSome(pos) and
|
||||
result = pos.toString()
|
||||
exists(ParamNode p |
|
||||
this = TParamNodeSome(p) and
|
||||
result = p.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1363,7 +1363,7 @@ class ParameterPositionOption extends TParameterPositionOption {
|
||||
*
|
||||
* - `TReturnCtxNone()`: no return flow.
|
||||
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
|
||||
* flow through may be possible.
|
||||
*/
|
||||
class ReturnCtx extends TReturnCtx {
|
||||
@@ -1374,9 +1374,9 @@ class ReturnCtx extends TReturnCtx {
|
||||
this = TReturnCtxNoFlowThrough() and
|
||||
result = "(no flow through)"
|
||||
or
|
||||
exists(ReturnKindExt kind |
|
||||
this = TReturnCtxMaybeFlowThrough(kind) and
|
||||
result = kind.toString()
|
||||
exists(ReturnPosition pos |
|
||||
this = TReturnCtxMaybeFlowThrough(pos) and
|
||||
result = pos.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -916,15 +916,15 @@ private module Cached {
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TParameterPositionOption =
|
||||
TParameterPositionNone() or
|
||||
TParameterPositionSome(ParameterPosition pos)
|
||||
newtype TParamNodeOption =
|
||||
TParamNodeNone() or
|
||||
TParamNodeSome(ParamNode p)
|
||||
|
||||
cached
|
||||
newtype TReturnCtx =
|
||||
TReturnCtxNone() or
|
||||
TReturnCtxNoFlowThrough() or
|
||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
|
||||
|
||||
cached
|
||||
newtype TTypedContentApprox =
|
||||
@@ -1343,15 +1343,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `ParameterPosition`. */
|
||||
class ParameterPositionOption extends TParameterPositionOption {
|
||||
/** An optional `ParamNode`. */
|
||||
class ParamNodeOption extends TParamNodeOption {
|
||||
string toString() {
|
||||
this = TParameterPositionNone() and
|
||||
this = TParamNodeNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
this = TParameterPositionSome(pos) and
|
||||
result = pos.toString()
|
||||
exists(ParamNode p |
|
||||
this = TParamNodeSome(p) and
|
||||
result = p.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1363,7 +1363,7 @@ class ParameterPositionOption extends TParameterPositionOption {
|
||||
*
|
||||
* - `TReturnCtxNone()`: no return flow.
|
||||
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
|
||||
* flow through may be possible.
|
||||
*/
|
||||
class ReturnCtx extends TReturnCtx {
|
||||
@@ -1374,9 +1374,9 @@ class ReturnCtx extends TReturnCtx {
|
||||
this = TReturnCtxNoFlowThrough() and
|
||||
result = "(no flow through)"
|
||||
or
|
||||
exists(ReturnKindExt kind |
|
||||
this = TReturnCtxMaybeFlowThrough(kind) and
|
||||
result = kind.toString()
|
||||
exists(ReturnPosition pos |
|
||||
this = TReturnCtxMaybeFlowThrough(pos) and
|
||||
result = pos.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap = Unit;
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||
PrevStage::revFlow(node, state, apa, config) and
|
||||
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
) {
|
||||
sourceNode(node, state, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
argAp = apNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
|
||||
additionalJumpStateStep(mid, state0, node, state, config) and
|
||||
cc = ccNone() and
|
||||
summaryCtx = TParameterPositionNone() and
|
||||
summaryCtx = TParamNodeNone() and
|
||||
argAp = apNone() and
|
||||
ap = getApNil(node) and
|
||||
apa = getApprox(ap)
|
||||
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||
then (
|
||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||
summaryCtx = TParamNodeSome(node.asNode()) and
|
||||
argAp = apSome(ap)
|
||||
) else (
|
||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||
summaryCtx = TParamNodeNone() and argAp = apNone()
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||
exists(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
||||
|
|
||||
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowStore(
|
||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
exists(DataFlowType contentType, ApApprox apa1 |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead0(
|
||||
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ApNonNil ap, Configuration config
|
||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
||||
Configuration config
|
||||
) {
|
||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, _, _, config)
|
||||
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(
|
||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||
) {
|
||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||
PrevStage::readStepCand(node1, c, node2, config) and
|
||||
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRetFromArg(
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
|
||||
Ap ap, ApApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||
exists(ReturnKindExt kind |
|
||||
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||
getApprox(argAp) = argApa and
|
||||
c = ret.getEnclosingCallable() and
|
||||
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
|
||||
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
kind = ret.getKind() and
|
||||
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
parameterFlowThroughAllowed(summaryCtx, kind) and
|
||||
argApa = getApprox(argAp) and
|
||||
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate fwdFlowInMayFlowThrough(
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough0(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
|
||||
Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||
}
|
||||
|
||||
// dedup before joining with `flowThroughOutOfCall`
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInMayFlowThroughProj(
|
||||
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
ApApprox argApa, ApApprox apa, Configuration config
|
||||
) {
|
||||
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
|
||||
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOutFromArg(
|
||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||
ApApprox apa, Configuration config
|
||||
private predicate fwdFlowThrough(
|
||||
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
|
||||
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||
config) and
|
||||
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
)
|
||||
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
|
||||
config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
ParameterPosition pos, Ap ap, Configuration config
|
||||
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
|
||||
ParamNodeEx p, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx param |
|
||||
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||
pos = param.getPosition()
|
||||
exists(ApApprox apa |
|
||||
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||
PrevStage::parameterMayFlowThrough(p, apa, config) and
|
||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
|
||||
fwdFlowConsCand(ap1, c, ap2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough0(
|
||||
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
|
||||
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
|
||||
) {
|
||||
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
|
||||
innerArgApa, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnFlowsThrough(
|
||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||
kind = ret.getKind() and
|
||||
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
|
||||
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
|
||||
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ApApprox argApa |
|
||||
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||
pragma[only_bind_into](config)) and
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||
)
|
||||
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowOutOfCallAp(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ApApprox apa |
|
||||
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
|
||||
fwdFlow(ret, _, _, _, _, ap, apa, config) and
|
||||
pos = ret.getReturnPosition()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(DataFlowCall call, ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnKindExt kind |
|
||||
revFlowOut(_, node, kind, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
|
||||
exists(ReturnPosition pos |
|
||||
revFlowOut(_, node, pos, state, _, _, ap, config) and
|
||||
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
|
||||
then (
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
|
||||
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
|
||||
returnAp = apSome(ap)
|
||||
) else (
|
||||
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
|
||||
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowOut(
|
||||
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
|
||||
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
|
||||
ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(NodeEx out, boolean allowsFieldFlow |
|
||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||
* in the flow covered by `revFlow`, where data might flow through the target
|
||||
* callable and back out at `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowThroughIntoCall(
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||
Configuration config
|
||||
) {
|
||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||
revFlowIsReturned(call, _, _, _, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowParamToReturn(
|
||||
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
|
||||
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind()) and
|
||||
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||
Configuration config
|
||||
private predicate revFlowThrough(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
|
||||
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||
)
|
||||
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReturned(
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
|
||||
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(RetNodeEx ret, FlowState state, CcCall ccc |
|
||||
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
|
||||
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
|
||||
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
|
||||
matchesCall(ccc, call)
|
||||
)
|
||||
}
|
||||
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterFlowsThroughRev(
|
||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
|
||||
) {
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, kind)
|
||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
|
||||
parameterFlowThroughAllowed(p, pos.getKind())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||
exists(RetNodeEx ret, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, ap, _, config) and
|
||||
parameterFlowsThroughRev(p, ap, pos, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate returnMayFlowThrough(
|
||||
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos |
|
||||
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
|
||||
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
|
||||
kind = pos.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revFlowInToReturnIsReturned(
|
||||
private predicate revFlowThroughArg(
|
||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||
Ap ap, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||
exists(ParamNodeEx p, ReturnPosition pos, Ap innerReturnAp |
|
||||
revFlowThrough(call, returnCtx, p, state, pos, returnAp, ap, innerReturnAp, config) and
|
||||
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
|
||||
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
|
||||
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
|
||||
)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
|
||||
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
|
||||
Configuration config
|
||||
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
c = n.getEnclosingCallable() and
|
||||
Stage5::parameterMayFlowThrough(p, _, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
|
||||
TAccessPathApproxSome(apa), apa0, config)
|
||||
)
|
||||
}
|
||||
@@ -2838,10 +2817,9 @@ pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||
exists(ParamNodeEx p |
|
||||
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||
p.isParameterOf(c, pos)
|
||||
nodeMayUseSummary0(n, p, state, apa, config)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -916,15 +916,15 @@ private module Cached {
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TParameterPositionOption =
|
||||
TParameterPositionNone() or
|
||||
TParameterPositionSome(ParameterPosition pos)
|
||||
newtype TParamNodeOption =
|
||||
TParamNodeNone() or
|
||||
TParamNodeSome(ParamNode p)
|
||||
|
||||
cached
|
||||
newtype TReturnCtx =
|
||||
TReturnCtxNone() or
|
||||
TReturnCtxNoFlowThrough() or
|
||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
|
||||
|
||||
cached
|
||||
newtype TTypedContentApprox =
|
||||
@@ -1343,15 +1343,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `ParameterPosition`. */
|
||||
class ParameterPositionOption extends TParameterPositionOption {
|
||||
/** An optional `ParamNode`. */
|
||||
class ParamNodeOption extends TParamNodeOption {
|
||||
string toString() {
|
||||
this = TParameterPositionNone() and
|
||||
this = TParamNodeNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
this = TParameterPositionSome(pos) and
|
||||
result = pos.toString()
|
||||
exists(ParamNode p |
|
||||
this = TParamNodeSome(p) and
|
||||
result = p.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1363,7 +1363,7 @@ class ParameterPositionOption extends TParameterPositionOption {
|
||||
*
|
||||
* - `TReturnCtxNone()`: no return flow.
|
||||
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
|
||||
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
|
||||
* flow through may be possible.
|
||||
*/
|
||||
class ReturnCtx extends TReturnCtx {
|
||||
@@ -1374,9 +1374,9 @@ class ReturnCtx extends TReturnCtx {
|
||||
this = TReturnCtxNoFlowThrough() and
|
||||
result = "(no flow through)"
|
||||
or
|
||||
exists(ReturnKindExt kind |
|
||||
this = TReturnCtxMaybeFlowThrough(kind) and
|
||||
result = kind.toString()
|
||||
exists(ReturnPosition pos |
|
||||
this = TReturnCtxMaybeFlowThrough(pos) and
|
||||
result = pos.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,38 +11,6 @@
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* An allocation function such as `malloc`.
|
||||
*/
|
||||
abstract class AllocationFunction extends Function {
|
||||
/**
|
||||
* Gets the index of the argument for the allocation size, if any. The actual
|
||||
* allocation size is the value of this argument multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
int getSizeArg() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of an argument that multiplies the allocation size given by
|
||||
* `getSizeArg`, if any.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of the input pointer argument to be reallocated, if this
|
||||
* is a `realloc` function.
|
||||
*/
|
||||
int getReallocPtrArg() { none() }
|
||||
|
||||
/**
|
||||
* Whether or not this allocation requires a corresponding deallocation of
|
||||
* some sort (most do, but `alloca` for example does not). If it is unclear,
|
||||
* we default to no (for example a placement `new` allocation may or may not
|
||||
* require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An allocation expression such as call to `malloc` or a `new` expression.
|
||||
*/
|
||||
@@ -86,6 +54,41 @@ abstract class AllocationExpr extends Expr {
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An allocation function such as `malloc`.
|
||||
*
|
||||
* Note: `AllocationExpr` includes calls to allocation functions, so prefer
|
||||
* to use that class unless you specifically need to reason about functions.
|
||||
*/
|
||||
abstract class AllocationFunction extends Function {
|
||||
/**
|
||||
* Gets the index of the argument for the allocation size, if any. The actual
|
||||
* allocation size is the value of this argument multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
int getSizeArg() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of an argument that multiplies the allocation size given by
|
||||
* `getSizeArg`, if any.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of the input pointer argument to be reallocated, if this
|
||||
* is a `realloc` function.
|
||||
*/
|
||||
int getReallocPtrArg() { none() }
|
||||
|
||||
/**
|
||||
* Whether or not this allocation requires a corresponding deallocation of
|
||||
* some sort (most do, but `alloca` for example does not). If it is unclear,
|
||||
* we default to no (for example a placement `new` allocation may or may not
|
||||
* require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator new` or `operator new[]` function that may be associated with
|
||||
* `new` or `new[]` expressions. Note that `new` and `new[]` are not function
|
||||
|
||||
@@ -11,16 +11,6 @@
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* A deallocation function such as `free`.
|
||||
*/
|
||||
abstract class DeallocationFunction extends Function {
|
||||
/**
|
||||
* Gets the index of the argument that is freed by this function.
|
||||
*/
|
||||
int getFreedArg() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An deallocation expression such as call to `free` or a `delete` expression.
|
||||
*/
|
||||
@@ -31,6 +21,19 @@ abstract class DeallocationExpr extends Expr {
|
||||
Expr getFreedExpr() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A deallocation function such as `free`.
|
||||
*
|
||||
* Note: `DeallocationExpr` includes calls to deallocation functions, so prefer
|
||||
* to use that class unless you specifically need to reason about functions.
|
||||
*/
|
||||
abstract class DeallocationFunction extends Function {
|
||||
/**
|
||||
* Gets the index of the argument that is freed by this function.
|
||||
*/
|
||||
int getFreedArg() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator delete` or `operator delete[]` function that may be associated
|
||||
* with `delete` or `delete[]` expressions. Note that `delete` and `delete[]`
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import cpp
|
||||
|
||||
pragma[nomagic]
|
||||
predicate beforeArrayAccess(Variable v, ArrayExpr access, Expr before) {
|
||||
exists(LogicalAndExpr andexpr |
|
||||
access.getArrayOffset() = v.getAnAccess() and
|
||||
@@ -23,6 +24,7 @@ predicate beforeArrayAccess(Variable v, ArrayExpr access, Expr before) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate afterArrayAccess(Variable v, ArrayExpr access, Expr after) {
|
||||
exists(LogicalAndExpr andexpr |
|
||||
access.getArrayOffset() = v.getAnAccess() and
|
||||
|
||||
@@ -115,7 +115,8 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
|
||||
from ScanfOutput output, ScanfFunctionCall call, Access access
|
||||
where
|
||||
output.getCall() = call and
|
||||
output.hasGuardedAccess(access, false)
|
||||
output.hasGuardedAccess(access, false) and
|
||||
not exists(DeallocationExpr dealloc | dealloc.getFreedExpr() = access)
|
||||
select access,
|
||||
"This variable is read, but may not have been written. " +
|
||||
"It should be guarded by a check that the $@ returns at least " +
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/missing-check-scanf` query no longer reports the free'ing of `scanf` output variables as potential reads.
|
||||
@@ -1,4 +1,3 @@
|
||||
| file://:0:0:0:0 | There was an error during this compilation |
|
||||
| float128.cpp:1:39:1:39 | 128-bit floating-point types are not supported in this configuration |
|
||||
| float128.cpp:2:30:2:30 | an attribute specifies a mode incompatible with '<error-type>' |
|
||||
| float128.cpp:2:41:2:41 | invalid combination of type specifiers |
|
||||
| float128.cpp:2:30:2:30 | 128-bit floating-point types are not supported in this configuration |
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
| float128.cpp:1:50:1:60 | _Complex128 | file://:0:0:0:0 | <error-type> |
|
||||
| float128.cpp:2:41:2:49 | _Float128 | file://:0:0:0:0 | <error-type> |
|
||||
| float128.cpp:13:29:13:54 | __is_floating_point_helper<T> | float128.cpp:10:8:10:17 | false_type |
|
||||
| float128.cpp:14:19:14:51 | __is_floating_point_helper<float> | float128.cpp:11:8:11:16 | true_type |
|
||||
| float128.cpp:15:19:15:52 | __is_floating_point_helper<double> | float128.cpp:11:8:11:16 | true_type |
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
| test.cpp:30:7:30:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:29:3:29:7 | call to scanf | call to scanf |
|
||||
| test.cpp:46:7:46:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:45:3:45:7 | call to scanf | call to scanf |
|
||||
| test.cpp:63:7:63:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:62:3:62:7 | call to scanf | call to scanf |
|
||||
| test.cpp:75:7:75:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:74:3:74:7 | call to scanf | call to scanf |
|
||||
| test.cpp:87:7:87:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:86:3:86:8 | call to fscanf | call to fscanf |
|
||||
| test.cpp:94:7:94:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:93:3:93:8 | call to sscanf | call to sscanf |
|
||||
| test.cpp:143:8:143:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:141:7:141:11 | call to scanf | call to scanf |
|
||||
| test.cpp:152:8:152:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:150:7:150:11 | call to scanf | call to scanf |
|
||||
| test.cpp:184:8:184:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:183:7:183:11 | call to scanf | call to scanf |
|
||||
| test.cpp:203:8:203:8 | j | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:200:7:200:11 | call to scanf | call to scanf |
|
||||
| test.cpp:227:9:227:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:225:25:225:29 | call to scanf | call to scanf |
|
||||
| test.cpp:231:9:231:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:229:14:229:18 | call to scanf | call to scanf |
|
||||
| test.cpp:243:7:243:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:242:3:242:7 | call to scanf | call to scanf |
|
||||
| test.cpp:251:7:251:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:250:3:250:7 | call to scanf | call to scanf |
|
||||
| test.cpp:259:7:259:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:258:3:258:7 | call to scanf | call to scanf |
|
||||
| test.cpp:271:7:271:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:270:3:270:7 | call to scanf | call to scanf |
|
||||
| test.cpp:281:8:281:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:280:3:280:7 | call to scanf | call to scanf |
|
||||
| test.cpp:289:7:289:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:288:3:288:7 | call to scanf | call to scanf |
|
||||
| test.cpp:383:25:383:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:382:6:382:11 | call to sscanf | call to sscanf |
|
||||
| test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
||||
| test.cpp:51:7:51:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:50:3:50:7 | call to scanf | call to scanf |
|
||||
| test.cpp:68:7:68:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:67:3:67:7 | call to scanf | call to scanf |
|
||||
| test.cpp:80:7:80:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:79:3:79:7 | call to scanf | call to scanf |
|
||||
| test.cpp:90:8:90:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
|
||||
| test.cpp:98:8:98:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
|
||||
| test.cpp:108:7:108:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:107:3:107:8 | call to fscanf | call to fscanf |
|
||||
| test.cpp:115:7:115:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:114:3:114:8 | call to sscanf | call to sscanf |
|
||||
| test.cpp:164:8:164:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:162:7:162:11 | call to scanf | call to scanf |
|
||||
| test.cpp:173:8:173:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:171:7:171:11 | call to scanf | call to scanf |
|
||||
| test.cpp:205:8:205:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:204:7:204:11 | call to scanf | call to scanf |
|
||||
| test.cpp:224:8:224:8 | j | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:221:7:221:11 | call to scanf | call to scanf |
|
||||
| test.cpp:248:9:248:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:246:25:246:29 | call to scanf | call to scanf |
|
||||
| test.cpp:252:9:252:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:250:14:250:18 | call to scanf | call to scanf |
|
||||
| test.cpp:264:7:264:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:263:3:263:7 | call to scanf | call to scanf |
|
||||
| test.cpp:272:7:272:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:271:3:271:7 | call to scanf | call to scanf |
|
||||
| test.cpp:280:7:280:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:279:3:279:7 | call to scanf | call to scanf |
|
||||
| test.cpp:292:7:292:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:291:3:291:7 | call to scanf | call to scanf |
|
||||
| test.cpp:302:8:302:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:301:3:301:7 | call to scanf | call to scanf |
|
||||
| test.cpp:310:7:310:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:309:3:309:7 | call to scanf | call to scanf |
|
||||
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
|
||||
|
||||
@@ -19,6 +19,11 @@ FILE *get_a_stream();
|
||||
const char *get_a_string();
|
||||
extern locale_t get_a_locale();
|
||||
|
||||
typedef long size_t;
|
||||
|
||||
void *malloc(size_t size);
|
||||
void free(void *ptr);
|
||||
|
||||
int main()
|
||||
{
|
||||
// --- simple cases ---
|
||||
@@ -78,6 +83,22 @@ int main()
|
||||
use(i); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
int *i = (int*)malloc(sizeof(int)); // Allocated variable
|
||||
|
||||
scanf("%d", i);
|
||||
use(*i); // BAD
|
||||
free(i); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
int *i = new int; // Allocated variable
|
||||
|
||||
scanf("%d", i);
|
||||
use(*i); // BAD
|
||||
delete i; // GOOD
|
||||
}
|
||||
|
||||
// --- different scanf functions ---
|
||||
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user