mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Java/Dataflow: Propagate MaD-id/model-id to PathGraph.
This commit is contained in:
@@ -208,7 +208,7 @@ signature module InputSig<LocationSig Location> {
|
||||
* Holds if there is a simple local flow step from `node1` to `node2`. These
|
||||
* are the value-preserving intra-callable flow steps.
|
||||
*/
|
||||
predicate simpleLocalFlowStep(Node node1, Node node2);
|
||||
predicate simpleLocalFlowStep(Node node1, Node node2, string model);
|
||||
|
||||
/**
|
||||
* Holds if the data-flow step from `node1` to `node2` can be used to
|
||||
@@ -289,6 +289,10 @@ signature module InputSig<LocationSig Location> {
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue);
|
||||
|
||||
predicate knownSourceModel(Node sink, string model);
|
||||
|
||||
predicate knownSinkModel(Node sink, string model);
|
||||
|
||||
/**
|
||||
* Holds if `n` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
@@ -585,6 +589,10 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = ""
|
||||
}
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
@@ -603,6 +611,10 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = ""
|
||||
}
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
|
||||
@@ -21,7 +21,7 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
|
||||
* Holds if the additional step from `src` to `sink` should be included in all
|
||||
* global taint flow configurations.
|
||||
*/
|
||||
predicate defaultAdditionalTaintStep(Lang::Node src, Lang::Node sink);
|
||||
predicate defaultAdditionalTaintStep(Lang::Node src, Lang::Node sink, string model);
|
||||
|
||||
/**
|
||||
* Holds if taint flow configurations should allow implicit reads of `c` at sinks
|
||||
@@ -51,9 +51,9 @@ module TaintFlowMake<
|
||||
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlowLang::Node node1, DataFlowLang::Node node2) {
|
||||
Config::isAdditionalFlowStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
predicate isAdditionalFlowStep(DataFlowLang::Node node1, DataFlowLang::Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2, model) or
|
||||
defaultAdditionalTaintStep(node1, node2, model)
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlowLang::Node node, DataFlowLang::ContentSet c) {
|
||||
@@ -62,7 +62,7 @@ module TaintFlowMake<
|
||||
(
|
||||
Config::isSink(node) or
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
@@ -76,6 +76,12 @@ module TaintFlowMake<
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = ""
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
@@ -96,6 +102,12 @@ module TaintFlowMake<
|
||||
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = ""
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
|
||||
@@ -67,7 +67,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2);
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model);
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -332,11 +332,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStepEx(NodeEx node1, NodeEx node2) {
|
||||
private predicate localFlowStepEx(NodeEx node1, NodeEx node2, string model) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model) and
|
||||
stepFilter(node1, node2)
|
||||
)
|
||||
or
|
||||
@@ -344,18 +344,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
Config::allowImplicitRead(n, _) and
|
||||
node1.asNode() = n and
|
||||
node2.isImplicitReadNode(n, false) and
|
||||
not fullBarrier(node1)
|
||||
not fullBarrier(node1) and
|
||||
model = ""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2) {
|
||||
private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, string model) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
Config::isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
Config::isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2)
|
||||
)
|
||||
@@ -364,7 +365,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
Config::allowImplicitRead(n, _) and
|
||||
node1.isImplicitReadNode(n, true) and
|
||||
node2.asNode() = n and
|
||||
not fullBarrier(node2)
|
||||
not fullBarrier(node2) and
|
||||
model = ""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -396,11 +398,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
/**
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(NodeEx node1, NodeEx node2) {
|
||||
private predicate additionalJumpStep(NodeEx node1, NodeEx node2, string model) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
Config::isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
Config::isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2) and
|
||||
not Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -538,14 +540,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
if hasSourceCallCtx() then cc = true else cc = false
|
||||
or
|
||||
exists(NodeEx mid | fwdFlow(mid, cc) |
|
||||
localFlowStepEx(mid, node) or
|
||||
additionalLocalFlowStep(mid, node) or
|
||||
localFlowStepEx(mid, node, _) or
|
||||
additionalLocalFlowStep(mid, node, _) or
|
||||
additionalLocalStateStep(mid, _, node, _)
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid | fwdFlow(mid, _) and cc = false |
|
||||
jumpStepEx(mid, node) or
|
||||
additionalJumpStep(mid, node) or
|
||||
additionalJumpStep(mid, node, _) or
|
||||
additionalJumpStateStep(mid, _, node, _)
|
||||
)
|
||||
or
|
||||
@@ -731,14 +733,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
if hasSinkCallCtx() then toReturn = true else toReturn = false
|
||||
or
|
||||
exists(NodeEx mid | revFlow(mid, toReturn) |
|
||||
localFlowStepEx(node, mid) or
|
||||
additionalLocalFlowStep(node, mid) or
|
||||
localFlowStepEx(node, mid, _) or
|
||||
additionalLocalFlowStep(node, mid, _) or
|
||||
additionalLocalStateStep(node, _, mid, _)
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid | revFlow(mid, _) and toReturn = false |
|
||||
jumpStepEx(node, mid) or
|
||||
additionalJumpStep(node, mid) or
|
||||
additionalJumpStep(node, mid, _) or
|
||||
additionalJumpStateStep(node, _, mid, _)
|
||||
)
|
||||
or
|
||||
@@ -1018,16 +1020,49 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
private predicate sinkNode = Stage1::sinkNode/2;
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2) {
|
||||
Stage1::revFlow(node2) and
|
||||
localFlowStepEx(node1, node2)
|
||||
private predicate sourceLabel(NodeEx node, string label) {
|
||||
sourceNode(node, _) and
|
||||
exists(Node n | n = node.asNode() |
|
||||
exists(string model | knownSourceModel(n, model) and label = model)
|
||||
or
|
||||
not knownSourceModel(n, _) and label = ""
|
||||
)
|
||||
}
|
||||
|
||||
private predicate sinkLabel(NodeEx node, string label) {
|
||||
sinkNode(node, _) and
|
||||
exists(Node n | n = node.asNode() |
|
||||
exists(string model | knownSinkModel(n, model) and label = model)
|
||||
or
|
||||
not knownSinkModel(n, _) and label = ""
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[label1, label2]
|
||||
pragma[inline_late]
|
||||
private string mergeLabels(string label1, string label2) {
|
||||
// Big-step, hidden nodes, and summaries all may need to merge labels.
|
||||
// These cases are expected to involve at most one non-empty label, so
|
||||
// we'll just discard the 2nd+ label for now.
|
||||
if label1 = "" then result = label2 else result = label1
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2) {
|
||||
Stage1::revFlow(node2) and
|
||||
additionalLocalFlowStep(node1, node2)
|
||||
private predicate localFlowStepNodeCand1(NodeEx node1, NodeEx node2, string label) {
|
||||
exists(string model |
|
||||
Stage1::revFlow(node2) and
|
||||
localFlowStepEx(node1, node2, model) and
|
||||
label = model
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand1(NodeEx node1, NodeEx node2, string label) {
|
||||
exists(string model |
|
||||
Stage1::revFlow(node2) and
|
||||
additionalLocalFlowStep(node1, node2, model) and
|
||||
label = model
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1416,7 +1451,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, state, _, _, _, _, _, ap, apa) and
|
||||
additionalJumpStep(mid, node) and
|
||||
additionalJumpStep(mid, node, _) and
|
||||
t = getNodeTyp(node) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
@@ -2044,7 +2079,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
additionalJumpStep(node, mid) and
|
||||
additionalJumpStep(node, mid, _) and
|
||||
revFlow(pragma[only_bind_into](mid), state, _, _, ap) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
@@ -2565,11 +2600,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
) {
|
||||
(
|
||||
preservesValue = true and
|
||||
localFlowStepNodeCand1(node1, node2) and
|
||||
localFlowStepNodeCand1(node1, node2, _) and
|
||||
state1 = state2
|
||||
or
|
||||
preservesValue = false and
|
||||
additionalLocalFlowStepNodeCand1(node1, node2) and
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, _) and
|
||||
state1 = state2
|
||||
or
|
||||
preservesValue = false and
|
||||
@@ -2654,7 +2689,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
or
|
||||
jumpStepEx(_, node)
|
||||
or
|
||||
additionalJumpStep(_, node)
|
||||
additionalJumpStep(_, node, _)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state)
|
||||
or
|
||||
@@ -2682,7 +2717,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private predicate localFlowExit(NodeEx node, FlowState state) {
|
||||
exists(NodeEx next | Stage2::revFlow(next, state) |
|
||||
jumpStepEx(node, next) or
|
||||
additionalJumpStep(node, next) or
|
||||
additionalJumpStep(node, next, _) or
|
||||
flowIntoCallNodeCand2(_, node, next, _) or
|
||||
flowOutOfCallNodeCand2(_, node, _, next, _) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, _) or
|
||||
@@ -2704,14 +2739,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, string label
|
||||
) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2) and
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, label) and
|
||||
state1 = state2 and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](state1), false) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), false)
|
||||
or
|
||||
additionalLocalStateStep(node1, state1, node2, state2) and
|
||||
label = "" and
|
||||
Stage2::revFlow(node1, state1, false) and
|
||||
Stage2::revFlow(node2, state2, false)
|
||||
}
|
||||
@@ -2726,7 +2762,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
LocalCallContext cc
|
||||
LocalCallContext cc, string label
|
||||
) {
|
||||
not isUnreachableInCall1(node2, cc) and
|
||||
not inBarrier(node2, state) and
|
||||
@@ -2734,12 +2770,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2) and
|
||||
localFlowStepNodeCand1(node1, node2, label) and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state))
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, label) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
@@ -2748,21 +2784,24 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
not isUnreachableInCall1(node1, cc) and
|
||||
not outBarrier(node1, state)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t, cc) and
|
||||
localFlowStepNodeCand1(mid, node2) and
|
||||
exists(NodeEx mid, string label1, string label2 |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t, cc,
|
||||
label1) and
|
||||
localFlowStepNodeCand1(mid, node2, label2) and
|
||||
not outBarrier(mid, state) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state)) and
|
||||
label = mergeLabels(label1, label2)
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state) and
|
||||
exists(NodeEx mid, string label1, string label2 |
|
||||
localFlowStepPlus(node1, state, mid, _, _, cc, label1) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, label2) and
|
||||
not outBarrier(mid, state) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
label = mergeLabels(label1, label2)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -2774,13 +2813,13 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pragma[nomagic]
|
||||
predicate localFlowBigStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCallContext callContext
|
||||
DataFlowType t, LocalCallContext callContext, string label
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, t, callContext) and
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, t, callContext, label) and
|
||||
localFlowExit(node2, state1) and
|
||||
state1 = state2
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, label) and
|
||||
state1 != state2 and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType() and
|
||||
@@ -2847,7 +2886,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
Typ t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _, _) and
|
||||
exists(lcc)
|
||||
}
|
||||
|
||||
@@ -2934,7 +2973,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
Typ t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state2), _) and
|
||||
exists(lcc)
|
||||
@@ -3239,7 +3278,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
Typ t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
PrevStage::revFlow(node2, pragma[only_bind_into](state2), _)
|
||||
}
|
||||
@@ -3446,7 +3485,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
private newtype TPathNode =
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap,
|
||||
string summaryLabel
|
||||
) {
|
||||
// A PathNode is introduced by a source ...
|
||||
Stage5::revFlow(node, state) and
|
||||
@@ -3454,14 +3494,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
sourceCallCtx(cc) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
t = node.getDataFlowType() and
|
||||
ap = TAccessPathNil()
|
||||
ap = TAccessPathNil() and
|
||||
summaryLabel = ""
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
pathStep(_, node, state, cc, sc, t, ap)
|
||||
pathStep(_, node, state, cc, sc, t, ap, summaryLabel, _)
|
||||
} or
|
||||
TPathNodeSink(NodeEx node, FlowState state) {
|
||||
exists(PathNodeMid sink |
|
||||
sink.isAtSink() and
|
||||
sink.isAtSink(_) and
|
||||
node = sink.getNodeEx() and
|
||||
state = sink.getState()
|
||||
)
|
||||
@@ -3644,24 +3685,27 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
abstract predicate isSource();
|
||||
abstract predicate isSource(string label);
|
||||
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
abstract PathNodeImpl getASuccessorImpl(string label);
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
private PathNodeImpl getASuccessorIfHidden(string label) {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
result = this.getASuccessorImpl(label)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
private PathNodeImpl getASuccessorFromNonHidden(string label) {
|
||||
result = this.getASuccessorImpl(label) and
|
||||
not this.isHidden()
|
||||
or
|
||||
exists(string l1, string l2 |
|
||||
result = this.getASuccessorFromNonHidden(l1).getASuccessorIfHidden(l2) and
|
||||
label = mergeLabels(l1, l2)
|
||||
)
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor(string label) {
|
||||
result = this.getASuccessorFromNonHidden(label) and not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
@@ -3670,7 +3714,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
not Config::includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this.isSource(_) and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
@@ -3678,12 +3722,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.isSource(_) and
|
||||
Config::sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
this.isSource(_) and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
@@ -3743,7 +3787,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
directReach(n.getANonHiddenSuccessor(_))
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3751,7 +3795,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
n1.getANonHiddenSuccessor(_) = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3796,10 +3840,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor(_) }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
final predicate isSource() { super.isSource(_) }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group) }
|
||||
@@ -3814,9 +3858,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b, string key, string val) {
|
||||
a.getASuccessor() = b and
|
||||
key = "provenance" and
|
||||
val = ""
|
||||
exists(string label |
|
||||
a.(PathNodeImpl).getANonHiddenSuccessor(label) = b and
|
||||
key = "provenance" and
|
||||
val = label
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
@@ -3845,8 +3891,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
SummaryCtx sc;
|
||||
DataFlowType t;
|
||||
AccessPath ap;
|
||||
string summaryLabel;
|
||||
|
||||
PathNodeMid() { this = TPathNodeMid(node, state, cc, sc, t, ap) }
|
||||
PathNodeMid() { this = TPathNodeMid(node, state, cc, sc, t, ap, summaryLabel) }
|
||||
|
||||
override NodeEx getNodeEx() { result = node }
|
||||
|
||||
@@ -3863,29 +3910,56 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
AccessPath getAp() { result = ap }
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
string getSummaryLabel() { result = summaryLabel }
|
||||
|
||||
private PathNodeMid getSuccMid(string label) {
|
||||
pathStep(this, result.getNodeEx(), result.getState(), result.getCallContext(),
|
||||
result.getSummaryCtx(), result.getType(), result.getAp())
|
||||
result.getSummaryCtx(), result.getType(), result.getAp(), _, label)
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
private predicate isSourceWithLabel(string labelprefix) {
|
||||
exists(string label |
|
||||
this.isSource(label) and
|
||||
label != "" and
|
||||
labelprefix = "Src:" + label + " "
|
||||
)
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl(string label) {
|
||||
// an intermediate step to another intermediate node
|
||||
result = this.getSuccMid()
|
||||
exists(string l2 | result = this.getSuccMid(l2) |
|
||||
not this.isSourceWithLabel(_) and label = l2
|
||||
or
|
||||
exists(string l1 |
|
||||
this.isSourceWithLabel(l1) and
|
||||
label = l1 + l2
|
||||
)
|
||||
)
|
||||
or
|
||||
// a final step to a sink
|
||||
result = this.getSuccMid().projectToSink()
|
||||
exists(string l2, string l3 | result = this.getSuccMid(l2).projectToSink(l3) |
|
||||
not this.isSourceWithLabel(_) and
|
||||
if l3 != "" then label = l2 + " Sink:" + l3 else label = l2
|
||||
or
|
||||
exists(string l1 |
|
||||
this.isSourceWithLabel(l1) and
|
||||
if l3 != "" then label = l1 + l2 + " Sink:" + l3 else label = l1 + l2
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSource() {
|
||||
override predicate isSource(string label) {
|
||||
sourceNode(node, state) and
|
||||
sourceLabel(node, label) and
|
||||
sourceCallCtx(cc) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
t = node.getDataFlowType() and
|
||||
ap = TAccessPathNil()
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
predicate isAtSink(string label) {
|
||||
sinkNode(node, state) and
|
||||
sinkLabel(node, label) and
|
||||
ap instanceof AccessPathNil and
|
||||
if hasSinkCallCtx()
|
||||
then
|
||||
@@ -3904,8 +3978,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
else any()
|
||||
}
|
||||
|
||||
PathNodeSink projectToSink() {
|
||||
this.isAtSink() and
|
||||
PathNodeSink projectToSink(string label) {
|
||||
this.isAtSink(label) and
|
||||
result.getNodeEx() = node and
|
||||
result.getState() = state
|
||||
}
|
||||
@@ -3926,9 +4000,13 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
override FlowState getState() { result = state }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { result = TPathNodeSinkGroup(this.getSinkGroup()) }
|
||||
override PathNodeImpl getASuccessorImpl(string label) {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup()) and label = ""
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state) }
|
||||
override predicate isSource(string label) {
|
||||
sourceNode(node, state) and sourceLabel(node, label)
|
||||
}
|
||||
|
||||
string getSinkGroup() { Config::sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
@@ -3942,9 +4020,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { result.getSourceGroup() = sourceGroup }
|
||||
override PathNodeImpl getASuccessorImpl(string label) {
|
||||
result.getSourceGroup() = sourceGroup and label = ""
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
override predicate isSource(string label) { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
@@ -3960,9 +4040,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl(string label) { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
override predicate isSource(string label) { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
@@ -3971,7 +4051,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
private predicate pathNode(
|
||||
PathNodeMid mid, NodeEx midnode, FlowState state, CallContext cc, SummaryCtx sc,
|
||||
DataFlowType t, AccessPath ap, LocalCallContext localCC
|
||||
DataFlowType t, AccessPath ap, string summaryLabel, LocalCallContext localCC
|
||||
) {
|
||||
midnode = mid.getNodeEx() and
|
||||
state = mid.getState() and
|
||||
@@ -3981,16 +4061,17 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
midnode.getEnclosingCallable()) and
|
||||
t = mid.getType() and
|
||||
ap = mid.getAp()
|
||||
ap = mid.getAp() and
|
||||
summaryLabel = mid.getSummaryLabel()
|
||||
}
|
||||
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
AccessPath ap, string summaryLabel, string label
|
||||
) {
|
||||
exists(DataFlowType t0, boolean isStoreStep |
|
||||
pathStep0(mid, pragma[only_bind_into](node), pragma[only_bind_into](state), cc, sc, t0, ap,
|
||||
isStoreStep) and
|
||||
isStoreStep, summaryLabel, label) and
|
||||
Stage5::revFlow(pragma[only_bind_into](node), pragma[only_bind_into](state), ap.getApprox()) and
|
||||
strengthenType(node, t0, t) and
|
||||
not inBarrier(node, state) and
|
||||
@@ -4005,19 +4086,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pragma[nomagic]
|
||||
private predicate pathStep0(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap, boolean isStoreStep
|
||||
AccessPath ap, boolean isStoreStep, string summaryLabel, string label
|
||||
) {
|
||||
exists(NodeEx midnode, FlowState state0, LocalCallContext localCC |
|
||||
pathNode(mid, midnode, state0, cc, sc, t, ap, localCC) and
|
||||
localFlowBigStep(midnode, state0, node, state, true, _, localCC) and
|
||||
isStoreStep = false
|
||||
exists(NodeEx midnode, FlowState state0, string sl, LocalCallContext localCC |
|
||||
pathNode(mid, midnode, state0, cc, sc, t, ap, sl, localCC) and
|
||||
localFlowBigStep(midnode, state0, node, state, true, _, localCC, label) and
|
||||
isStoreStep = false and
|
||||
summaryLabel = mergeLabels(sl, label)
|
||||
)
|
||||
or
|
||||
exists(NodeEx midnode, FlowState state0, LocalCallContext localCC |
|
||||
pathNode(mid, midnode, state0, cc, sc, _, ap, localCC) and
|
||||
localFlowBigStep(midnode, state0, node, state, false, t, localCC) and
|
||||
exists(NodeEx midnode, FlowState state0, string sl, LocalCallContext localCC |
|
||||
pathNode(mid, midnode, state0, cc, sc, _, ap, sl, localCC) and
|
||||
localFlowBigStep(midnode, state0, node, state, false, t, localCC, label) and
|
||||
ap instanceof AccessPathNil and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = mergeLabels(sl, label)
|
||||
)
|
||||
or
|
||||
jumpStepEx(mid.getNodeExOutgoing(), node) and
|
||||
@@ -4026,16 +4109,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
sc instanceof SummaryCtxNone and
|
||||
t = mid.getType() and
|
||||
ap = mid.getAp() and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = "" and
|
||||
label = ""
|
||||
or
|
||||
additionalJumpStep(mid.getNodeExOutgoing(), node) and
|
||||
additionalJumpStep(mid.getNodeExOutgoing(), node, label) and
|
||||
state = mid.getState() and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
t = node.getDataFlowType() and
|
||||
ap = TAccessPathNil() and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = ""
|
||||
or
|
||||
additionalJumpStateStep(mid.getNodeExOutgoing(), mid.getState(), node, state) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -4043,36 +4129,47 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
t = node.getDataFlowType() and
|
||||
ap = TAccessPathNil() and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = "" and
|
||||
label = ""
|
||||
or
|
||||
exists(Content c, DataFlowType t0, AccessPath ap0 |
|
||||
pathStoreStep(mid, node, state, t0, ap0, c, t, cc) and
|
||||
ap.isCons(c, t0, ap0) and
|
||||
sc = mid.getSummaryCtx() and
|
||||
isStoreStep = true
|
||||
isStoreStep = true and
|
||||
summaryLabel = mid.getSummaryLabel() and
|
||||
label = ""
|
||||
)
|
||||
or
|
||||
exists(Content c, AccessPath ap0 |
|
||||
pathReadStep(mid, node, state, ap0, c, cc) and
|
||||
ap0.isCons(c, t, ap) and
|
||||
sc = mid.getSummaryCtx() and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = mid.getSummaryLabel() and
|
||||
label = ""
|
||||
)
|
||||
or
|
||||
pathIntoCallable(mid, node, state, _, cc, sc, _) and
|
||||
t = mid.getType() and
|
||||
ap = mid.getAp() and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = "" and
|
||||
label = ""
|
||||
or
|
||||
pathOutOfCallable(mid, node, state, cc) and
|
||||
t = mid.getType() and
|
||||
ap = mid.getAp() and
|
||||
sc instanceof SummaryCtxNone and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = "" and
|
||||
label = ""
|
||||
or
|
||||
pathThroughCallable(mid, node, state, cc, t, ap) and
|
||||
pathThroughCallable(mid, node, state, cc, t, ap, label) and
|
||||
sc = mid.getSummaryCtx() and
|
||||
isStoreStep = false
|
||||
isStoreStep = false and
|
||||
summaryLabel = mid.getSummaryLabel()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -4178,7 +4275,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
DataFlowType t, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgNodeEx arg, ArgumentPosition apos |
|
||||
pathNode(mid, arg, state, cc, _, t, ap, _) and
|
||||
pathNode(mid, arg, state, cc, _, t, ap, _, _) and
|
||||
not outBarrier(arg, state) and
|
||||
arg.asNode().(ArgNode).argumentOf(call, apos) and
|
||||
apa = ap.getApprox() and
|
||||
@@ -4244,10 +4341,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pragma[nomagic]
|
||||
private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, DataFlowType t,
|
||||
AccessPath ap, AccessPathApprox apa
|
||||
AccessPath ap, AccessPathApprox apa, string summaryLabel
|
||||
) {
|
||||
exists(RetNodeEx ret |
|
||||
pathNode(_, ret, state, cc, sc, t, ap, _) and
|
||||
pathNode(_, ret, state, cc, sc, t, ap, summaryLabel, _) and
|
||||
kind = ret.getKind() and
|
||||
apa = ap.getApprox() and
|
||||
parameterFlowThroughAllowed(sc.getParamNode(), kind) and
|
||||
@@ -4258,11 +4355,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pragma[nomagic]
|
||||
private predicate pathThroughCallable0(
|
||||
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc,
|
||||
DataFlowType t, AccessPath ap, AccessPathApprox apa
|
||||
DataFlowType t, AccessPath ap, AccessPathApprox apa, string label
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, state, innercc, sc, t, ap, apa)
|
||||
paramFlowsThrough(kind, state, innercc, sc, t, ap, apa, label)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4272,10 +4369,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathThroughCallable(
|
||||
PathNodeMid mid, NodeEx out, FlowState state, CallContext cc, DataFlowType t, AccessPath ap
|
||||
PathNodeMid mid, NodeEx out, FlowState state, CallContext cc, DataFlowType t, AccessPath ap,
|
||||
string label
|
||||
) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, state, cc, t, ap, apa) and
|
||||
pathThroughCallable0(call, mid, kind, state, cc, t, ap, apa, label) and
|
||||
out = getAnOutNodeFlow(kind, call, apa)
|
||||
)
|
||||
}
|
||||
@@ -4291,10 +4389,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
ReturnKindExt kind, NodeEx out, FlowState sout, DataFlowType t, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, pragma[only_bind_into](sout), _, pragma[only_bind_into](t),
|
||||
pragma[only_bind_into](apout)) and
|
||||
pragma[only_bind_into](apout), _) and
|
||||
pathIntoCallable(arg, par, _, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, pragma[only_bind_into](sout), innercc, sc,
|
||||
pragma[only_bind_into](t), pragma[only_bind_into](apout), _)
|
||||
pragma[only_bind_into](t), pragma[only_bind_into](apout), _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4320,25 +4418,25 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, t, apout) and
|
||||
pathNode(ret, retnode, sout, innercc, sc, t, apout, _) and
|
||||
pathNode(ret, retnode, sout, innercc, sc, t, apout, _, _) and
|
||||
kind = retnode.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
private PathNodeImpl localStep(PathNodeImpl n) {
|
||||
n.getASuccessorImpl() = result and
|
||||
n.getASuccessorImpl(_) = result and
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _) or
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
storeEx(n1, _, n2, _, _) or
|
||||
readSetEx(n1, _, n2)
|
||||
)
|
||||
}
|
||||
|
||||
private PathNodeImpl summaryCtxStep(PathNodeImpl n) {
|
||||
n.getASuccessorImpl() = result and
|
||||
n.getASuccessorImpl(_) = result and
|
||||
exists(SummaryCtxSome sc |
|
||||
pathNode(n, _, _, _, pragma[only_bind_into](sc), _, _, _) and
|
||||
pathNode(result, _, _, _, pragma[only_bind_into](sc), _, _, _)
|
||||
pathNode(n, _, _, _, pragma[only_bind_into](sc), _, _, _, _) and
|
||||
pathNode(result, _, _, _, pragma[only_bind_into](sc), _, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4354,7 +4452,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getASuccessorImpl() and
|
||||
succ = pred.getASuccessorImpl(_) and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
@@ -4371,12 +4469,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
ParamNodeEx p, NodeEx o, FlowState sout, DataFlowType t, AccessPath apout,
|
||||
PathNodeMid out0
|
||||
|
|
||||
pragma[only_bind_into](arg).getASuccessorImpl() = pragma[only_bind_into](out0) and
|
||||
pragma[only_bind_into](arg).getASuccessorImpl(_) = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, ret, o, sout, t, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pathNode(out0, o, sout, _, _, t, apout, _)
|
||||
pathNode(out0, o, sout, _, _, t, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
out = out0 or out = out0.projectToSink(_)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4428,7 +4526,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getANonHiddenSuccessor(_) = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4454,7 +4552,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
deprecated predicate hasFlowPath = flowPath/2;
|
||||
|
||||
private predicate flowsTo(PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink) {
|
||||
flowsource.isSource() and
|
||||
flowsource.isSource(_) and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
@@ -4597,7 +4695,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
exists(NodeEx node1, NodeEx node2 |
|
||||
jumpStepEx(node1, node2)
|
||||
or
|
||||
additionalJumpStep(node1, node2)
|
||||
additionalJumpStep(node1, node2, _)
|
||||
or
|
||||
additionalJumpStateStep(node1, _, node2, _)
|
||||
or
|
||||
@@ -5031,7 +5129,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
) {
|
||||
not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStepEx(mid.getNodeEx(), node) and
|
||||
localFlowStepEx(mid.getNodeEx(), node, _) and
|
||||
state = mid.getState() and
|
||||
cc = mid.getCallContext() and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -5041,7 +5139,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
t = mid.getType() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNodeEx(), node) and
|
||||
additionalLocalFlowStep(mid.getNodeEx(), node, _) and
|
||||
state = mid.getState() and
|
||||
cc = mid.getCallContext() and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -5075,7 +5173,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
ap = mid.getAp() and
|
||||
isStoreStep = false
|
||||
or
|
||||
additionalJumpStep(mid.getNodeEx(), node) and
|
||||
additionalJumpStep(mid.getNodeEx(), node, _) and
|
||||
state = mid.getState() and
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
@@ -5347,7 +5445,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1,
|
||||
TRevSummaryCtx2 sc2, TRevSummaryCtx3 sc3, PartialAccessPath ap, boolean isStoreStep
|
||||
) {
|
||||
localFlowStepEx(node, mid.getNodeEx()) and
|
||||
localFlowStepEx(node, mid.getNodeEx(), _) and
|
||||
state = mid.getState() and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
@@ -5355,7 +5453,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
ap = mid.getAp() and
|
||||
isStoreStep = false
|
||||
or
|
||||
additionalLocalFlowStep(node, mid.getNodeEx()) and
|
||||
additionalLocalFlowStep(node, mid.getNodeEx(), _) and
|
||||
state = mid.getState() and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
@@ -5380,7 +5478,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
ap = mid.getAp() and
|
||||
isStoreStep = false
|
||||
or
|
||||
additionalJumpStep(node, mid.getNodeEx()) and
|
||||
additionalJumpStep(node, mid.getNodeEx(), _) and
|
||||
state = mid.getState() and
|
||||
sc1 = TRevSummaryCtx1None() and
|
||||
sc2 = TRevSummaryCtx2None() and
|
||||
|
||||
@@ -105,12 +105,14 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
storeContents.getAStoreContent() = loadContents.getAReadContent()
|
||||
}
|
||||
|
||||
predicate simpleLocalSmallStep = simpleLocalFlowStepExt/2;
|
||||
predicate simpleLocalSmallStep(Node node1, Node node2) {
|
||||
simpleLocalFlowStepExt(node1, node2, _)
|
||||
}
|
||||
|
||||
predicate levelStepNoCall(Node n1, LocalSourceNode n2) { none() }
|
||||
|
||||
predicate levelStepCall(Node n1, LocalSourceNode n2) {
|
||||
argumentValueFlowsThrough(n1, TReadStepTypesNone(), n2)
|
||||
argumentValueFlowsThrough(n1, TReadStepTypesNone(), n2, _)
|
||||
}
|
||||
|
||||
// TODO: support setters
|
||||
@@ -119,7 +121,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
private predicate loadStep0(Node n1, Node n2, Content f) {
|
||||
readSet(n1, f, n2)
|
||||
or
|
||||
argumentValueFlowsThrough(n1, TReadStepTypesSome(_, f, _), n2)
|
||||
argumentValueFlowsThrough(n1, TReadStepTypesSome(_, f, _), n2, _)
|
||||
}
|
||||
|
||||
predicate loadStep(Node n1, LocalSourceNode n2, Content f) { loadStep0(n1, n2, f) }
|
||||
@@ -293,7 +295,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
||||
|
|
||||
simpleLocalFlowStep(node, mid) and
|
||||
simpleLocalFlowStep(node, mid, _) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
@@ -870,7 +872,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
// local flow
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, read) and
|
||||
simpleLocalFlowStep(mid, node) and
|
||||
simpleLocalFlowStep(mid, node, _) and
|
||||
validParameterAliasStep(mid, node)
|
||||
)
|
||||
or
|
||||
@@ -970,8 +972,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
parameterValueFlow0(p, node, read) and
|
||||
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read, string model) {
|
||||
parameterValueFlow0(p, node, read, model) and
|
||||
if node instanceof CastingNode
|
||||
then
|
||||
// normal flow through
|
||||
@@ -983,60 +985,75 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[model1, model2]
|
||||
pragma[inline_late]
|
||||
private string mergeModels(string model1, string model2) {
|
||||
if model1 = "" then result = model2 else result = model1
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
private predicate parameterValueFlow0(
|
||||
ParamNode p, Node node, ReadStepTypesOption read, string model
|
||||
) {
|
||||
p = node and
|
||||
Cand::cand(p, _) and
|
||||
read = TReadStepTypesNone()
|
||||
read = TReadStepTypesNone() and
|
||||
model = ""
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, read) and
|
||||
simpleLocalFlowStep(mid, node) and
|
||||
validParameterAliasStep(mid, node)
|
||||
exists(Node mid, string model1, string model2 |
|
||||
parameterValueFlow(p, mid, read, model1) and
|
||||
simpleLocalFlowStep(mid, node, model2) and
|
||||
validParameterAliasStep(mid, node) and
|
||||
model = mergeModels(model1, model2)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, TReadStepTypesNone()) and
|
||||
parameterValueFlow(p, mid, TReadStepTypesNone(), model) and
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0_0(
|
||||
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
|
||||
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read,
|
||||
string model
|
||||
) {
|
||||
// flow through: no prior read
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, mustBeNone) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
exists(ArgNode arg, string model1, string model2 |
|
||||
parameterValueFlowArg(p, arg, mustBeNone, model1) and
|
||||
argumentValueFlowsThrough(arg, read, node, model2) and
|
||||
model = mergeModels(model1, model2)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node)
|
||||
exists(ArgNode arg, string model1, string model2 |
|
||||
parameterValueFlowArg(p, arg, read, model1) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node, model2) and
|
||||
model = mergeModels(model1, model2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
|
||||
parameterValueFlow(p, arg, read) and
|
||||
private predicate parameterValueFlowArg(
|
||||
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model
|
||||
) {
|
||||
parameterValueFlow(p, arg, read, model) and
|
||||
Cand::argumentValueFlowsThroughCand(arg, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThrough0(
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read, string model
|
||||
) {
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturn(param, kind, read)
|
||||
parameterValueFlowReturn(param, kind, read, model)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1049,9 +1066,11 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
cached
|
||||
predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
|
||||
predicate argumentValueFlowsThrough(
|
||||
ArgNode arg, ReadStepTypesOption read, Node out, string model
|
||||
) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThrough0(call, arg, kind, read) and
|
||||
argumentValueFlowsThrough0(call, arg, kind, read, model) and
|
||||
out = getAnOutNode(call, kind)
|
||||
|
|
||||
// normal flow through
|
||||
@@ -1072,7 +1091,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* This predicate is exposed for testing only.
|
||||
*/
|
||||
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1084,10 +1103,10 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
private predicate parameterValueFlowReturn(
|
||||
ParamNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model
|
||||
) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlow(p, ret, read) and
|
||||
parameterValueFlow(p, ret, read, model) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -1103,7 +1122,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* node `n`, in the same callable, using only value-preserving steps.
|
||||
*/
|
||||
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -1121,7 +1140,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1, _) // TODO
|
||||
or
|
||||
readSet(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
@@ -1152,7 +1171,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* interface.
|
||||
*/
|
||||
private predicate reverseStepThroughInputOutputAlias(
|
||||
PostUpdateNode fromNode, PostUpdateNode toNode
|
||||
PostUpdateNode fromNode, PostUpdateNode toNode, string model
|
||||
) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
@@ -1163,17 +1182,17 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
// from function input to output?
|
||||
fromPre = getAnOutNode(c, _) and
|
||||
toPre.(ArgNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgNode), fromPre)
|
||||
simpleLocalFlowStep(toPre.(ArgNode), fromPre, model)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre, model)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
predicate simpleLocalFlowStepExt(Node node1, Node node2, string model) {
|
||||
simpleLocalFlowStep(node1, node2, model) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2, model)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -86,16 +86,16 @@ module MakeConsistency<
|
||||
this instanceof ParameterNode or
|
||||
this instanceof ReturnNode or
|
||||
this = getAnOutNode(_, _) or
|
||||
simpleLocalFlowStep(this, _) or
|
||||
simpleLocalFlowStep(_, this) or
|
||||
simpleLocalFlowStep(this, _, _) or
|
||||
simpleLocalFlowStep(_, this, _) or
|
||||
jumpStep(this, _) or
|
||||
jumpStep(_, this) or
|
||||
storeStep(this, _, _) or
|
||||
storeStep(_, _, this) or
|
||||
readStep(this, _, _) or
|
||||
readStep(_, _, this) or
|
||||
defaultAdditionalTaintStep(this, _) or
|
||||
defaultAdditionalTaintStep(_, this)
|
||||
defaultAdditionalTaintStep(this, _, _) or
|
||||
defaultAdditionalTaintStep(_, this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ module MakeConsistency<
|
||||
}
|
||||
|
||||
query predicate localFlowIsLocal(Node n1, Node n2, string msg) {
|
||||
simpleLocalFlowStep(n1, n2) and
|
||||
simpleLocalFlowStep(n1, n2, _) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
@@ -247,7 +247,7 @@ module MakeConsistency<
|
||||
|
||||
query predicate postWithInFlow(PostUpdateNode n, string msg) {
|
||||
not clearsContent(n, _) and
|
||||
simpleLocalFlowStep(_, n) and
|
||||
simpleLocalFlowStep(_, n, _) and
|
||||
not Input::postWithInFlowExclude(n) and
|
||||
msg = "PostUpdateNode should not be the target of local flow."
|
||||
}
|
||||
@@ -296,7 +296,7 @@ module MakeConsistency<
|
||||
}
|
||||
|
||||
query predicate identityLocalStep(Node n, string msg) {
|
||||
simpleLocalFlowStep(n, n) and
|
||||
simpleLocalFlowStep(n, n, _) and
|
||||
not Input::identityLocalStepExclude(n) and
|
||||
msg = "Node steps to itself"
|
||||
}
|
||||
|
||||
@@ -210,9 +210,14 @@ module Make<
|
||||
* Holds if data may flow from `input` to `output` through this callable.
|
||||
*
|
||||
* `preservesValue` indicates whether this is a value-preserving step or a taint-step.
|
||||
*
|
||||
* If `model` is non-empty then it indicates the provenance of the model
|
||||
* defining this flow.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate propagatesFlow(string input, string output, boolean preservesValue);
|
||||
abstract predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if there exists a generated summary that applies to this callable.
|
||||
@@ -398,9 +403,9 @@ module Make<
|
||||
|
||||
private predicate summarySpec(string spec) {
|
||||
exists(SummarizedCallable c |
|
||||
c.propagatesFlow(spec, _, _)
|
||||
c.propagatesFlow(spec, _, _, _)
|
||||
or
|
||||
c.propagatesFlow(_, spec, _)
|
||||
c.propagatesFlow(_, spec, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -555,7 +560,7 @@ module Make<
|
||||
*
|
||||
* ```ql
|
||||
* private class CAdapter extends SummarizedCallable instanceof C {
|
||||
* override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
* override predicate propagatesFlow(string input, string output, boolean preservesValue, string model) {
|
||||
* none()
|
||||
* }
|
||||
*
|
||||
@@ -575,6 +580,9 @@ module Make<
|
||||
* `preservesValue` indicates whether this is a value-preserving step
|
||||
* or a taint-step.
|
||||
*
|
||||
* If `model` is non-empty then it indicates the provenance of the model
|
||||
* defining this flow.
|
||||
*
|
||||
* Input specifications are restricted to stacks that end with
|
||||
* `SummaryComponent::argument(_)`, preceded by zero or more
|
||||
* `SummaryComponent::return(_)` or `SummaryComponent::content(_)` components.
|
||||
@@ -591,7 +599,8 @@ module Make<
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -604,19 +613,19 @@ module Make<
|
||||
pragma[nomagic]
|
||||
private predicate summary(
|
||||
SummarizedCallableImpl c, SummaryComponentStack input, SummaryComponentStack output,
|
||||
boolean preservesValue
|
||||
boolean preservesValue, string model
|
||||
) {
|
||||
c.propagatesFlow(input, output, preservesValue)
|
||||
c.propagatesFlow(input, output, preservesValue, model)
|
||||
or
|
||||
// observe side effects of callbacks on input arguments
|
||||
c.propagatesFlow(output, input, preservesValue) and
|
||||
c.propagatesFlow(output, input, preservesValue, model) and
|
||||
preservesValue = true and
|
||||
isCallbackParameter(input) and
|
||||
isContentOfArgument(output, _)
|
||||
or
|
||||
// flow from the receiver of a callback into the instance-parameter
|
||||
exists(SummaryComponentStack s, SummaryComponentStack callbackRef |
|
||||
c.propagatesFlow(s, _, _) or c.propagatesFlow(_, s, _)
|
||||
c.propagatesFlow(s, _, _, model) or c.propagatesFlow(_, s, _, model)
|
||||
|
|
||||
callbackRef = s.drop(_) and
|
||||
(isCallbackParameter(callbackRef) or callbackRef.head() = TReturnSummaryComponent(_)) and
|
||||
@@ -626,7 +635,7 @@ module Make<
|
||||
)
|
||||
or
|
||||
exists(SummaryComponentStack arg, SummaryComponentStack return |
|
||||
derivedFluentFlow(c, input, arg, return, preservesValue)
|
||||
derivedFluentFlow(c, input, arg, return, preservesValue, model)
|
||||
|
|
||||
arg.length() = 1 and
|
||||
output = return
|
||||
@@ -638,13 +647,17 @@ module Make<
|
||||
)
|
||||
or
|
||||
// Chain together summaries where values get passed into callbacks along the way
|
||||
exists(SummaryComponentStack mid, boolean preservesValue1, boolean preservesValue2 |
|
||||
c.propagatesFlow(input, mid, preservesValue1) and
|
||||
c.propagatesFlow(mid, output, preservesValue2) and
|
||||
exists(
|
||||
SummaryComponentStack mid, boolean preservesValue1, boolean preservesValue2, string model1,
|
||||
string model2
|
||||
|
|
||||
c.propagatesFlow(input, mid, preservesValue1, model1) and
|
||||
c.propagatesFlow(mid, output, preservesValue2, model2) and
|
||||
mid.drop(mid.length() - 2) =
|
||||
SummaryComponentStack::push(TParameterSummaryComponent(_),
|
||||
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
|
||||
preservesValue = preservesValue1.booleanAnd(preservesValue2)
|
||||
preservesValue = preservesValue1.booleanAnd(preservesValue2) and
|
||||
model = mergeModels(model1, model2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -665,22 +678,33 @@ module Make<
|
||||
pragma[nomagic]
|
||||
private predicate derivedFluentFlow(
|
||||
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
|
||||
SummaryComponentStack return, boolean preservesValue
|
||||
SummaryComponentStack return, boolean preservesValue, string model
|
||||
) {
|
||||
exists(ParameterPosition pos |
|
||||
summary(c, input, arg, preservesValue) and
|
||||
exists(ParameterPosition pos, string model1, string model2 |
|
||||
summary(c, input, arg, preservesValue, model1) and
|
||||
isContentOfArgument(arg, pos) and
|
||||
summary(c, SummaryComponentStack::argument(pos), return, true) and
|
||||
return.bottom() = TReturnSummaryComponent(_)
|
||||
summary(c, SummaryComponentStack::argument(pos), return, true, model2) and
|
||||
return.bottom() = TReturnSummaryComponent(_) and
|
||||
model = mergeModels(model1, model2)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[model1, model2]
|
||||
pragma[inline_late]
|
||||
private string mergeModels(string model1, string model2) {
|
||||
model1 = "" and result = model2
|
||||
or
|
||||
model2 = "" and result = model1
|
||||
or
|
||||
model1 != "" and model2 != "" and result = model1 + "+" + model2
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate derivedFluentFlowPush(
|
||||
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
|
||||
SummaryComponent head, SummaryComponentStack tail, int i
|
||||
) {
|
||||
derivedFluentFlow(c, input, arg, tail, _) and
|
||||
derivedFluentFlow(c, input, arg, tail, _, _) and
|
||||
head = arg.drop(i).head() and
|
||||
i = arg.length() - 2
|
||||
or
|
||||
@@ -702,7 +726,7 @@ module Make<
|
||||
}
|
||||
|
||||
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
summary(c, _, s, _)
|
||||
summary(c, _, s, _, _)
|
||||
or
|
||||
exists(SummaryComponentStack out |
|
||||
outputState(c, out) and
|
||||
@@ -715,7 +739,7 @@ module Make<
|
||||
}
|
||||
|
||||
private predicate inputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
summary(c, s, _, _)
|
||||
summary(c, s, _, _, _)
|
||||
or
|
||||
exists(SummaryComponentStack inp | inputState(c, inp) and s = inp.tail())
|
||||
or
|
||||
@@ -742,7 +766,7 @@ module Make<
|
||||
*
|
||||
* ```ql
|
||||
* propagatesFlow(
|
||||
* SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
* SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue, string model
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
@@ -952,7 +976,7 @@ module Make<
|
||||
*/
|
||||
predicate summaryAllowParameterReturnInSelf(SummarizedCallable c, ParameterPosition ppos) {
|
||||
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
||||
summary(c, inputContents, outputContents, _) and
|
||||
summary(c, inputContents, outputContents, _, _) and
|
||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
|
||||
outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos))
|
||||
)
|
||||
@@ -1077,25 +1101,28 @@ module Make<
|
||||
* Holds if there is a local step from `pred` to `succ`, which is synthesized
|
||||
* from a flow summary.
|
||||
*/
|
||||
predicate summaryLocalStep(SummaryNode pred, SummaryNode succ, boolean preservesValue) {
|
||||
predicate summaryLocalStep(
|
||||
SummaryNode pred, SummaryNode succ, boolean preservesValue, string model
|
||||
) {
|
||||
exists(
|
||||
SummarizedCallable c, SummaryComponentStack inputContents,
|
||||
SummaryComponentStack outputContents
|
||||
|
|
||||
summary(c, inputContents, outputContents, preservesValue) and
|
||||
summary(c, inputContents, outputContents, preservesValue, model) and
|
||||
pred = summaryNodeInputState(pragma[only_bind_into](c), inputContents) and
|
||||
succ = summaryNodeOutputState(pragma[only_bind_into](c), outputContents)
|
||||
|
|
||||
preservesValue = true
|
||||
or
|
||||
preservesValue = false and not summary(c, inputContents, outputContents, true)
|
||||
preservesValue = false and not summary(c, inputContents, outputContents, true, _)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable c, SummaryComponentStack s |
|
||||
pred = summaryNodeInputState(c, s.tail()) and
|
||||
succ = summaryNodeInputState(c, s) and
|
||||
s.head() = [SummaryComponent::withContent(_), SummaryComponent::withoutContent(_)] and
|
||||
preservesValue = true
|
||||
preservesValue = true and
|
||||
model = ""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1202,7 +1229,7 @@ module Make<
|
||||
or
|
||||
exists(SummaryNode mid, boolean clearsOrExpectsMid |
|
||||
paramReachesLocal(p, mid, clearsOrExpectsMid) and
|
||||
summaryLocalStep(mid, n, true) and
|
||||
summaryLocalStep(mid, n, true, _) and
|
||||
if
|
||||
summaryClearsContent(n, _) or
|
||||
summaryExpectsContent(n, _)
|
||||
@@ -1260,7 +1287,7 @@ module Make<
|
||||
*/
|
||||
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
|
||||
exists(ReturnKind rk, SummaryNode ret, DataFlowCall call |
|
||||
summaryLocalStep(summaryArgParam(call, arg, sc), ret, true) and
|
||||
summaryLocalStep(summaryArgParam(call, arg, sc), ret, true, _) and
|
||||
summaryReturnNode(ret, pragma[only_bind_into](rk)) and
|
||||
out = getAnOutNode(call, pragma[only_bind_into](rk))
|
||||
)
|
||||
@@ -1275,7 +1302,7 @@ module Make<
|
||||
*/
|
||||
predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) {
|
||||
exists(SummaryNode ret |
|
||||
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false)
|
||||
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1289,7 +1316,7 @@ module Make<
|
||||
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
|
||||
exists(SummaryNode mid, SummaryNode ret |
|
||||
summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and
|
||||
summaryLocalStep(mid, ret, _)
|
||||
summaryLocalStep(mid, ret, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1302,7 +1329,7 @@ module Make<
|
||||
*/
|
||||
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
|
||||
exists(SummaryNode mid, SummaryNode ret |
|
||||
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _) and
|
||||
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and
|
||||
summaryStoreStep(mid, c, ret)
|
||||
)
|
||||
}
|
||||
@@ -1425,10 +1452,11 @@ module Make<
|
||||
private class SummarizedCallableImplAdapter extends SummarizedCallableImpl instanceof SummarizedCallable
|
||||
{
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
) {
|
||||
exists(AccessPath inSpec, AccessPath outSpec |
|
||||
SummarizedCallable.super.propagatesFlow(inSpec, outSpec, preservesValue) and
|
||||
SummarizedCallable.super.propagatesFlow(inSpec, outSpec, preservesValue, model) and
|
||||
interpretSpec(inSpec, input) and
|
||||
interpretSpec(outSpec, output)
|
||||
)
|
||||
@@ -1470,13 +1498,17 @@ module Make<
|
||||
* Holds if an external source specification exists for `n` with output specification
|
||||
* `output` and kind `kind`.
|
||||
*/
|
||||
predicate sourceElement(Element n, string output, string kind, Provenance provenance);
|
||||
predicate sourceElement(
|
||||
Element n, string output, string kind, Provenance provenance, string model
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if an external sink specification exists for `n` with input specification
|
||||
* `input` and kind `kind`.
|
||||
*/
|
||||
predicate sinkElement(Element n, string input, string kind, Provenance provenance);
|
||||
predicate sinkElement(
|
||||
Element n, string input, string kind, Provenance provenance, string model
|
||||
);
|
||||
|
||||
class SourceOrSinkElement extends Element;
|
||||
|
||||
@@ -1530,8 +1562,8 @@ module Make<
|
||||
private import SourceSinkInterpretationInput
|
||||
|
||||
private predicate sourceSinkSpec(string spec) {
|
||||
sourceElement(_, spec, _, _) or
|
||||
sinkElement(_, spec, _, _)
|
||||
sourceElement(_, spec, _, _, _) or
|
||||
sinkElement(_, spec, _, _, _)
|
||||
}
|
||||
|
||||
private module AccessPath = AccessPathSyntax::AccessPath<sourceSinkSpec/1>;
|
||||
@@ -1560,10 +1592,10 @@ module Make<
|
||||
}
|
||||
|
||||
private predicate sourceElementRef(
|
||||
InterpretNode ref, SourceSinkAccessPath output, string kind
|
||||
InterpretNode ref, SourceSinkAccessPath output, string kind, string model
|
||||
) {
|
||||
exists(SourceOrSinkElement e |
|
||||
sourceElement(e, output, kind, _) and
|
||||
sourceElement(e, output, kind, _, model) and
|
||||
if outputNeedsReferenceExt(output.getToken(0))
|
||||
then e = ref.getCallTarget()
|
||||
else e = ref.asElement()
|
||||
@@ -1575,9 +1607,11 @@ module Make<
|
||||
inputNeedsReference(c)
|
||||
}
|
||||
|
||||
private predicate sinkElementRef(InterpretNode ref, SourceSinkAccessPath input, string kind) {
|
||||
private predicate sinkElementRef(
|
||||
InterpretNode ref, SourceSinkAccessPath input, string kind, string model
|
||||
) {
|
||||
exists(SourceOrSinkElement e |
|
||||
sinkElement(e, input, kind, _) and
|
||||
sinkElement(e, input, kind, _, model) and
|
||||
if inputNeedsReferenceExt(input.getToken(0))
|
||||
then e = ref.getCallTarget()
|
||||
else e = ref.asElement()
|
||||
@@ -1588,7 +1622,7 @@ module Make<
|
||||
private predicate interpretOutput(
|
||||
SourceSinkAccessPath output, int n, InterpretNode ref, InterpretNode node
|
||||
) {
|
||||
sourceElementRef(ref, output, _) and
|
||||
sourceElementRef(ref, output, _, _) and
|
||||
n = 0 and
|
||||
(
|
||||
if output = ""
|
||||
@@ -1638,7 +1672,7 @@ module Make<
|
||||
private predicate interpretInput(
|
||||
SourceSinkAccessPath input, int n, InterpretNode ref, InterpretNode node
|
||||
) {
|
||||
sinkElementRef(ref, input, _) and
|
||||
sinkElementRef(ref, input, _, _) and
|
||||
n = 0 and
|
||||
(
|
||||
if input = ""
|
||||
@@ -1675,9 +1709,9 @@ module Make<
|
||||
* Holds if `node` is specified as a source with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
predicate isSourceNode(InterpretNode node, string kind) {
|
||||
predicate isSourceNode(InterpretNode node, string kind, string model) {
|
||||
exists(InterpretNode ref, SourceSinkAccessPath output |
|
||||
sourceElementRef(ref, output, kind) and
|
||||
sourceElementRef(ref, output, kind, model) and
|
||||
interpretOutput(output, output.getNumToken(), ref, node)
|
||||
)
|
||||
}
|
||||
@@ -1686,9 +1720,9 @@ module Make<
|
||||
* Holds if `node` is specified as a sink with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
predicate isSinkNode(InterpretNode node, string kind) {
|
||||
predicate isSinkNode(InterpretNode node, string kind, string model) {
|
||||
exists(InterpretNode ref, SourceSinkAccessPath input |
|
||||
sinkElementRef(ref, input, kind) and
|
||||
sinkElementRef(ref, input, kind, model) and
|
||||
interpretInput(input, input.getNumToken(), ref, node)
|
||||
)
|
||||
}
|
||||
@@ -1711,7 +1745,7 @@ module Make<
|
||||
*/
|
||||
query predicate source(string csv) {
|
||||
exists(RelevantSource s, string output, string kind, Provenance provenance |
|
||||
sourceElement(s, output, kind, provenance) and
|
||||
sourceElement(s, output, kind, provenance, _) and
|
||||
csv =
|
||||
s.getCallableCsv() // Callable information
|
||||
+ output + ";" // output
|
||||
@@ -1728,7 +1762,7 @@ module Make<
|
||||
*/
|
||||
query predicate sink(string csv) {
|
||||
exists(RelevantSink s, string input, string kind, Provenance provenance |
|
||||
sinkElement(s, input, kind, provenance) and
|
||||
sinkElement(s, input, kind, provenance, _) and
|
||||
csv =
|
||||
s.getCallableCsv() // Callable information
|
||||
+ input + ";" // input
|
||||
@@ -1883,7 +1917,7 @@ module Make<
|
||||
|
||||
private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) {
|
||||
exists(boolean preservesValue |
|
||||
PrivateSteps::summaryLocalStep(a.asNode(), b.asNode(), preservesValue) and
|
||||
PrivateSteps::summaryLocalStep(a.asNode(), b.asNode(), preservesValue, _) and
|
||||
if preservesValue = true then value = "value" else value = "taint"
|
||||
)
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user