mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #20386 from github/alexet/overlay-informed-dataflow
Dataflow: Overlay informed dataflow.
This commit is contained in:
@@ -10,6 +10,6 @@ import java
|
||||
module DataFlow {
|
||||
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<Location, JavaDataFlow>
|
||||
import DataFlowMakeOverlay<Location, JavaDataFlow>
|
||||
import Public
|
||||
}
|
||||
|
||||
@@ -13,5 +13,5 @@ module TaintTracking {
|
||||
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import codeql.dataflow.TaintTracking
|
||||
import TaintFlowMake<Location, JavaDataFlow, JavaTaintTracking>
|
||||
import TaintFlowMakeOverlay<Location, JavaDataFlow, JavaTaintTracking>
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ module;
|
||||
|
||||
private import semmle.code.Location
|
||||
private import codeql.dataflow.DataFlow
|
||||
private import semmle.code.java.Overlay
|
||||
|
||||
module Private {
|
||||
import DataFlowPrivate
|
||||
@@ -29,4 +30,6 @@ module JavaDataFlow implements InputSig<Location> {
|
||||
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
|
||||
|
||||
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
|
||||
|
||||
predicate isEvaluatingInOverlay = isOverlay/0;
|
||||
}
|
||||
|
||||
@@ -349,6 +349,18 @@ signature module InputSig<LocationSig Location> {
|
||||
|
||||
/** Holds if `fieldFlowBranchLimit` should be ignored for flow going into/out of `c`. */
|
||||
default predicate ignoreFieldFlowBranchLimit(DataFlowCallable c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the evaluator is currently evaluating with an overlay. The
|
||||
* implementation of this predicate needs to be `overlay[local]`. For a
|
||||
* language with no overlay support, `none()` is a valid implementation.
|
||||
*
|
||||
* When called from a local predicate, this predicate holds if we are in the
|
||||
* overlay-only local evaluation. When called from a global predicate, this
|
||||
* predicate holds if we are evaluating globally with overlay and base both
|
||||
* visible.
|
||||
*/
|
||||
default predicate isEvaluatingInOverlay() { none() }
|
||||
}
|
||||
|
||||
module Configs<LocationSig Location, InputSig<Location> Lang> {
|
||||
@@ -645,10 +657,8 @@ private module PathGraphSigMod {
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
|
||||
private module DataFlowMakeCore<LocationSig Location, InputSig<Location> Lang> {
|
||||
private import Lang
|
||||
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
|
||||
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
|
||||
import Configs<Location, Lang>
|
||||
|
||||
/**
|
||||
@@ -691,59 +701,6 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
|
||||
predicate flowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
}
|
||||
|
||||
private module Stage1 = ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = Impl<C, Stage1::Stage1NoState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
}
|
||||
|
||||
private module Stage1 = ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = Impl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
@@ -1141,3 +1098,135 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
|
||||
import PathGraph
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
|
||||
import DataFlowMakeCore<Location, Lang>
|
||||
private import Lang
|
||||
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
|
||||
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
private module Stage1 = ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = Impl<C, Stage1::Stage1NoState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
private module Stage1 = ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = Impl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowMakeOverlay<LocationSig Location, InputSig<Location> Lang> {
|
||||
import DataFlowMake<Location, Lang>
|
||||
private import Lang
|
||||
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
|
||||
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() {
|
||||
not Config::observeDiffInformedIncrementalMode()
|
||||
}
|
||||
}
|
||||
|
||||
private module Stage1 = ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = OverlayImpl<C, Stage1::Stage1NoState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
|
||||
predicate accessPathLimit = Config::accessPathLimit/0;
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() {
|
||||
not Config::observeDiffInformedIncrementalMode()
|
||||
}
|
||||
}
|
||||
|
||||
private module Stage1 = ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = OverlayImpl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,16 +47,16 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
|
||||
/**
|
||||
* Construct the modules for taint-tracking analyses.
|
||||
*/
|
||||
module TaintFlowMake<
|
||||
private module TaintFlowMakeCore<
|
||||
LocationSig Location, DF::InputSig<Location> DataFlowLang,
|
||||
InputSig<Location, DataFlowLang> TaintTrackingLang>
|
||||
{
|
||||
private import TaintTrackingLang
|
||||
private import DF::DataFlowMake<Location, DataFlowLang> as DataFlow
|
||||
private import MakeImpl<Location, DataFlowLang> as DataFlowInternal
|
||||
private import MakeImplStage1<Location, DataFlowLang> as DataFlowInternalStage1
|
||||
import TaintTrackingLang
|
||||
import DF::DataFlowMake<Location, DataFlowLang> as DataFlow
|
||||
import MakeImpl<Location, DataFlowLang> as DataFlowInternal
|
||||
import MakeImplStage1<Location, DataFlowLang> as DataFlowInternalStage1
|
||||
|
||||
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
import Config
|
||||
@@ -83,71 +83,9 @@ module TaintFlowMake<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation.
|
||||
*/
|
||||
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
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 = "Config"
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1NoState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation using flow state.
|
||||
*/
|
||||
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 = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
|
||||
string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
signature int speculationLimitSig();
|
||||
|
||||
private module AddSpeculativeTaintSteps<
|
||||
module AddSpeculativeTaintSteps<
|
||||
DataFlowInternal::FullStateConfigSig Config, speculationLimitSig/0 speculationLimit> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
@@ -215,6 +153,79 @@ module TaintFlowMake<
|
||||
state1.getState() = state2.getState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module TaintFlowMake<
|
||||
LocationSig Location, DF::InputSig<Location> DataFlowLang,
|
||||
InputSig<Location, DataFlowLang> TaintTrackingLang>
|
||||
{
|
||||
private import TaintFlowMakeCore<Location, DataFlowLang, TaintTrackingLang>
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation.
|
||||
*/
|
||||
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
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 = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1NoState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation using flow state.
|
||||
*/
|
||||
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 = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
|
||||
string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation that also allows a given
|
||||
@@ -232,6 +243,8 @@ module TaintFlowMake<
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
@@ -270,6 +283,8 @@ module TaintFlowMake<
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
@@ -285,3 +300,157 @@ module TaintFlowMake<
|
||||
import Flow
|
||||
}
|
||||
}
|
||||
|
||||
module TaintFlowMakeOverlay<
|
||||
LocationSig Location, DF::InputSig<Location> DataFlowLang,
|
||||
InputSig<Location, DataFlowLang> TaintTrackingLang>
|
||||
{
|
||||
private import TaintFlowMakeCore<Location, DataFlowLang, TaintTrackingLang>
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation.
|
||||
*/
|
||||
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
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 = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() {
|
||||
not Config::observeDiffInformedIncrementalMode()
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1NoState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation using flow state.
|
||||
*/
|
||||
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 = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
|
||||
string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() {
|
||||
not Config::observeDiffInformedIncrementalMode()
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation that also allows a given
|
||||
* maximum number of speculative taint steps.
|
||||
*/
|
||||
module SpeculativeGlobal<DataFlow::ConfigSig Config, speculationLimitSig/0 speculationLimit>
|
||||
implements DataFlow::GlobalFlowSig
|
||||
{
|
||||
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 = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() {
|
||||
not Config::observeDiffInformedIncrementalMode()
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<AddSpeculativeTaintSteps<Config0, speculationLimit/0>>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation using flow state that also
|
||||
* allows a given maximum number of speculative taint steps.
|
||||
*/
|
||||
module SpeculativeGlobalWithState<
|
||||
DataFlow::StateConfigSig Config, speculationLimitSig/0 speculationLimit> 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 = "Config"
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
|
||||
string model
|
||||
) {
|
||||
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
|
||||
}
|
||||
|
||||
predicate observeOverlayInformedIncrementalMode() {
|
||||
not Config::observeDiffInformedIncrementalMode()
|
||||
}
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<AddSpeculativeTaintSteps<Config0, speculationLimit/0>>
|
||||
}
|
||||
|
||||
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
|
||||
|
||||
import Stage1::PartialFlow
|
||||
|
||||
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
|
||||
|
||||
import Flow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +143,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
*/
|
||||
predicate observeDiffInformedIncrementalMode();
|
||||
|
||||
/**
|
||||
* Holds if sources and sinks should be filtered to only include those that
|
||||
* may lead to a flow path with either a source or a sink in the overlay database.
|
||||
* This only has an effect when running
|
||||
* in overlay-informed incremental mode. This should be used in conjunction
|
||||
* with the `OverlayImpl` implementation to merge the base results back in.
|
||||
*/
|
||||
predicate observeOverlayInformedIncrementalMode();
|
||||
|
||||
Location getASelectedSourceLocation(Node source);
|
||||
|
||||
Location getASelectedSinkLocation(Node sink);
|
||||
@@ -171,6 +180,56 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation given a full input configuration, and
|
||||
* an initial stage 1 pruning with merging of overlay and base results.
|
||||
*/
|
||||
module OverlayImpl<FullStateConfigSig Config, Stage1Output<Config::FlowState> Stage1> {
|
||||
private module Flow = Impl<Config, Stage1>;
|
||||
|
||||
import Flow
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* This is a local predicate that only has results local to the overlay/base database.
|
||||
*/
|
||||
private predicate flowLocal(Node source, Node sink) = forceLocal(Flow::flow/2)(source, sink)
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate flow(Node source, Node sink) {
|
||||
Flow::flow(source, sink)
|
||||
or
|
||||
// If we are overlay informed (i.e. we are not diff-informed), we
|
||||
// merge in the local results which includes the base database results.
|
||||
flowLocal(source, sink) and Config::observeOverlayInformedIncrementalMode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
* This is a local predicate that only has results local to the overlay/base database.
|
||||
*/
|
||||
predicate flowToLocal(Node sink) = forceLocal(Flow::flowTo/1)(sink)
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate flowTo(Node sink) {
|
||||
Flow::flowTo(sink)
|
||||
or
|
||||
// If we are overlay informed (i.e. we are not diff-informed), we
|
||||
// merge in the local results which includes the base database results.
|
||||
flowToLocal(sink) and Config::observeOverlayInformedIncrementalMode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate flowToExpr(Lang::DataFlowExpr sink) { flowTo(exprNode(sink)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation given a full input configuration, and
|
||||
* an initial stage 1 pruning.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Provides an implementation of a fast initial pruning of global
|
||||
* (interprocedural) data flow reachability (Stage 1).
|
||||
*/
|
||||
overlay[local?]
|
||||
overlay[local?] // when this is removed, put `overlay[local?]` on `isOverlayNode`.
|
||||
module;
|
||||
|
||||
private import codeql.util.Unit
|
||||
@@ -129,23 +129,76 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
private module AlertFiltering = AlertFilteringImpl<Location>;
|
||||
|
||||
/**
|
||||
* Holds if the given node is visible in overlay-only local evaluation.
|
||||
*
|
||||
* This predicate needs to be `overlay[local?]`, either directly or
|
||||
* through annotations from an outer scope. If `Node` is global for the
|
||||
* language under analysis, then every node is considered an overlay
|
||||
* node, which means there will effectively be no overlay-based
|
||||
* filtering of sources and sinks.
|
||||
*/
|
||||
private predicate isOverlayNode(Node node) {
|
||||
isEvaluatingInOverlay() and
|
||||
// Any local node is an overlay node if we are evaluating in overlay mode
|
||||
exists(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* The filtering if we aren't meant to be diff-informed.
|
||||
*
|
||||
* Shared between sources and sinks.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
private predicate nonDiffInformedFilter(Node node) {
|
||||
// If we are in base-only global evaluation, do not filter out any sources/sinks.
|
||||
not isEvaluatingInOverlay()
|
||||
or
|
||||
// If the configuration doesn't merge overlays, do not filter out any sources/sinks.
|
||||
not Config::observeOverlayInformedIncrementalMode()
|
||||
or
|
||||
// If we are in global evaluation with an overlay present, restrict
|
||||
// sources/sinks to those visible in the overlay.
|
||||
isOverlayNode(node)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private predicate isFilteredSource(Node source) {
|
||||
Config::isSource(source, _) and
|
||||
// Data flow is always incremental in one of two ways.
|
||||
// 1. If the configuration is diff-informed, we filter to only include nodes in the diff,
|
||||
// which gives the smallest set of nodes.
|
||||
// If diff information is not available, we do not filter at all.
|
||||
// 2. If not, in global evaluation with overlay, we filter to only
|
||||
// include nodes from files in the overlay; flow from
|
||||
// other nodes will be added back later.
|
||||
// We start by seeing if we should be in case 1.
|
||||
if Config::observeDiffInformedIncrementalMode()
|
||||
then AlertFiltering::filterByLocation(Config::getASelectedSourceLocation(source))
|
||||
else any()
|
||||
then
|
||||
// Case 1: We are meant to be diff-informed.
|
||||
// We still only filter if we have diff information.
|
||||
AlertFiltering::diffInformationAvailable()
|
||||
implies
|
||||
AlertFiltering::locationIsInDiff(Config::getASelectedSourceLocation(source))
|
||||
else nonDiffInformedFilter(source)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private predicate isFilteredSink(Node sink) {
|
||||
(
|
||||
Config::isSink(sink, _) or
|
||||
Config::isSink(sink)
|
||||
) and
|
||||
// See the comments in `isFilteredSource` for the reasoning behind the following.
|
||||
if Config::observeDiffInformedIncrementalMode()
|
||||
then AlertFiltering::filterByLocation(Config::getASelectedSinkLocation(sink))
|
||||
else any()
|
||||
then
|
||||
AlertFiltering::diffInformationAvailable()
|
||||
implies
|
||||
AlertFiltering::locationIsInDiff(Config::getASelectedSinkLocation(sink))
|
||||
else nonDiffInformedFilter(sink)
|
||||
}
|
||||
|
||||
private predicate hasFilteredSource() { isFilteredSource(_) }
|
||||
|
||||
@@ -82,6 +82,21 @@ module AlertFilteringImpl<LocationSig Location> {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if diff information is available in this evaluation. */
|
||||
predicate diffInformationAvailable() {
|
||||
restrictAlertsTo(_, _, _) or restrictAlertsToExactLocation(_, _, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if diff information is available, and `filePath` is in the diff
|
||||
* range.
|
||||
*/
|
||||
predicate fileIsInDiff(string filePath) {
|
||||
restrictAlertsTo(filePath, _, _)
|
||||
or
|
||||
restrictAlertsToExactLocation(filePath, _, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given location is a match for one of the active filtering
|
||||
* predicates in this module, or if all filtering predicates are inactive
|
||||
@@ -92,8 +107,17 @@ module AlertFilteringImpl<LocationSig Location> {
|
||||
*/
|
||||
bindingset[location]
|
||||
predicate filterByLocation(Location location) {
|
||||
not restrictAlertsTo(_, _, _) and not restrictAlertsToExactLocation(_, _, _, _, _)
|
||||
not diffInformationAvailable()
|
||||
or
|
||||
locationIsInDiff(location)
|
||||
}
|
||||
|
||||
/**
|
||||
* Like `filterByLocation`, except that if there is no diff range, this
|
||||
* predicate never holds.
|
||||
*/
|
||||
bindingset[location]
|
||||
predicate locationIsInDiff(Location location) {
|
||||
exists(string filePath |
|
||||
restrictAlertsToEntireFile(filePath) and
|
||||
location.hasLocationInfo(filePath, _, _, _, _)
|
||||
|
||||
Reference in New Issue
Block a user