diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlowStack.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlowStack.qll index d6befff5b6b8..55b3b0342e37 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlowStack.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlowStack.qll @@ -1,14 +1,15 @@ import csharp private import codeql.dataflow.DataFlow private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific -private import codeql.dataflowstack.DataFlowStack as DFS +private import codeql.dataflowstack.FlowStack as FlowStack -module LanguageDataFlowStack = DFS::LanguageDataFlow; +module LanguageFlowStack = FlowStack::LanguageDataFlow; private module FlowStackInput - implements LanguageDataFlowStack::DataFlowGroup::DataFlowStackSig> + implements LanguageFlowStack::DataFlowConfigContext::FlowInstance { private module Flow = DataFlow::Global; + class PathNode = Flow::PathNode; CsharpDataFlow::Node getNode(Flow::PathNode n) { result = n.getNode() } @@ -26,12 +27,12 @@ private module FlowStackInput } module DataFlowStackMake { - import LanguageDataFlowStack::FlowStack, Config, FlowStackInput> + import LanguageFlowStack::FlowStack> } module BiStackAnalysisMake< DataFlow::ConfigSig ConfigA, DataFlow::ConfigSig ConfigB >{ - import LanguageDataFlowStack::BiStackAnalysis, FlowStackInput, ConfigB, DataFlow::Global, FlowStackInput> + import LanguageFlowStack::BiStackAnalysis, ConfigB, FlowStackInput> } \ No newline at end of file diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTrackingStack.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTrackingStack.qll index 4c5868e2695d..22bb3705f4ad 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTrackingStack.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTrackingStack.qll @@ -2,14 +2,15 @@ import csharp private import codeql.dataflow.DataFlow private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific -private import codeql.dataflowstack.TaintTrackingStack as TTS +private import codeql.dataflowstack.FlowStack as FlowStack -module LanguageTaintTrackingStack = TTS::LanguageTaintTracking; +module LanguageFlowStack = FlowStack::LanguageDataFlow; -private module TaintTrackingStackInput - implements LanguageTaintTrackingStack::DataFlowGroup::TaintTrackingStackSig> +private module FlowStackInput + implements LanguageFlowStack::DataFlowConfigContext::FlowInstance { private module Flow = TaintTracking::Global; + class PathNode = Flow::PathNode; CsharpDataFlow::Node getNode(Flow::PathNode n) { result = n.getNode() } @@ -27,12 +28,12 @@ private module TaintTrackingStackInput } module DataFlowStackMake { - import LanguageTaintTrackingStack::FlowStack, Config, TaintTrackingStackInput> + import LanguageFlowStack::FlowStack> } module BiStackAnalysisMake< DataFlow::ConfigSig ConfigA, DataFlow::ConfigSig ConfigB >{ - import LanguageTaintTrackingStack::BiStackAnalysis, TaintTrackingStackInput, ConfigB, TaintTracking::Global, TaintTrackingStackInput> + import LanguageFlowStack::BiStackAnalysis, ConfigB, FlowStackInput> } \ No newline at end of file diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlowStack.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlowStack.qll index 1beb87ff72b6..e5f8de8cf8b3 100644 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlowStack.qll +++ b/java/ql/lib/semmle/code/java/dataflow/DataFlowStack.qll @@ -4,20 +4,21 @@ module; import java private import semmle.code.java.dataflow.DataFlow private import semmle.code.java.dataflow.internal.DataFlowImplSpecific -private import codeql.dataflowstack.DataFlowStack as DFS +private import codeql.dataflowstack.FlowStack as FlowStack -module LanguageDataFlowStack = DFS::LanguageDataFlow; +module LanguageFlowStack = FlowStack::LanguageDataFlow; private module FlowStackInput - implements LanguageDataFlowStack::DataFlowGroup::DataFlowStackSig> + implements LanguageFlowStack::DataFlowConfigContext::FlowInstance { private module Flow = DataFlow::Global; + class PathNode = Flow::PathNode; - JavaDataFlow::Node getNode(Flow::PathNode n) { result = n.getNode() } + JavaDataFlow::Node getNode(PathNode n) { result = n.getNode() } - predicate isSource(Flow::PathNode n) { n.isSource() } + predicate isSource(PathNode n) { n.isSource() } - Flow::PathNode getASuccessor(Flow::PathNode n) { result = n.getASuccessor() } + PathNode getASuccessor(PathNode n) { result = n.getASuccessor() } JavaDataFlow::DataFlowCallable getARuntimeTarget(JavaDataFlow::DataFlowCall call) { result.asCallable() = call.asCall().getCallee() @@ -29,12 +30,12 @@ private module FlowStackInput } module DataFlowStackMake { - import LanguageDataFlowStack::FlowStack, Config, FlowStackInput> + import LanguageFlowStack::FlowStack> } module BiStackAnalysisMake< DataFlow::ConfigSig ConfigA, DataFlow::ConfigSig ConfigB >{ - import LanguageDataFlowStack::BiStackAnalysis, FlowStackInput, ConfigB, DataFlow::Global, FlowStackInput> + import LanguageFlowStack::BiStackAnalysis, ConfigB, FlowStackInput> } \ No newline at end of file diff --git a/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll b/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll index b83d4fce814f..a26bb888f18c 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll @@ -6,20 +6,21 @@ private import semmle.code.java.dataflow.DataFlow private import semmle.code.java.dataflow.TaintTracking private import semmle.code.java.dataflow.internal.DataFlowImplSpecific private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific -private import codeql.dataflowstack.TaintTrackingStack as TTS +private import codeql.dataflowstack.FlowStack as FlowStack -module LanguageTaintTrackingStack = TTS::LanguageTaintTracking; +module LanguageFlowStack = FlowStack::LanguageDataFlow; -private module TaintTrackingStackInput - implements LanguageTaintTrackingStack::DataFlowGroup::TaintTrackingStackSig> +private module FlowStackInput + implements LanguageFlowStack::DataFlowConfigContext::FlowInstance { private module Flow = TaintTracking::Global; + class PathNode = Flow::PathNode; - JavaDataFlow::Node getNode(Flow::PathNode n) { result = n.getNode() } + JavaDataFlow::Node getNode(PathNode n) { result = n.getNode() } - predicate isSource(Flow::PathNode n) { n.isSource() } + predicate isSource(PathNode n) { n.isSource() } - Flow::PathNode getASuccessor(Flow::PathNode n) { result = n.getASuccessor() } + PathNode getASuccessor(PathNode n) { result = n.getASuccessor() } JavaDataFlow::DataFlowCallable getARuntimeTarget(JavaDataFlow::DataFlowCall call) { result.asCallable() = call.asCall().getCallee() @@ -31,12 +32,12 @@ private module TaintTrackingStackInput } module DataFlowStackMake { - import LanguageTaintTrackingStack::FlowStack, Config, TaintTrackingStackInput> + import LanguageFlowStack::FlowStack> } module BiStackAnalysisMake< DataFlow::ConfigSig ConfigA, DataFlow::ConfigSig ConfigB >{ - import LanguageTaintTrackingStack::BiStackAnalysis, TaintTrackingStackInput, ConfigB, TaintTracking::Global, TaintTrackingStackInput> + import LanguageFlowStack::BiStackAnalysis, ConfigB, FlowStackInput> } \ No newline at end of file diff --git a/shared/dataflowstack/codeql/dataflowstack/DataFlowStack.qll b/shared/dataflowstack/codeql/dataflowstack/FlowStack.qll similarity index 78% rename from shared/dataflowstack/codeql/dataflowstack/DataFlowStack.qll rename to shared/dataflowstack/codeql/dataflowstack/FlowStack.qll index 2598b70e8961..a8963bf76ab9 100644 --- a/shared/dataflowstack/codeql/dataflowstack/DataFlowStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/FlowStack.qll @@ -2,10 +2,11 @@ overlay[local?] module; private import codeql.dataflow.DataFlow as DF +private import codeql.dataflow.TaintTracking as TT private import codeql.util.Location /** - * A Language-initialized grouping of DataFlow types and primitives. + * A Language-initialized grouping of DataFlow/TaintFlow types and primitives. */ module LanguageDataFlow Lang>{ module AbstractDF = DF::Configs; @@ -13,48 +14,41 @@ module LanguageDataFlow Lang>{ module AbstractDataFlowOverlay = DF::DataFlowMakeOverlay; /** - * A collection of modules that are scoped to a specific DataFlow config implementation + * Signatures and modules bound by a common DataFlow Config */ - module DataFlowGroup{ + module DataFlowConfigContext{ - module MyConfig = Config; - module DataFlowGlobal = AbstractDataFlow::Global; - module DataFlowOverlayGlobal = AbstractDataFlowOverlay::Global; + signature module FlowInstance{ + class PathNode; - /** - * A Taint tracking implementation, paramaterized over a DataFlow type - */ - signature module DataFlowStackSig{ + Lang::Node getNode(PathNode n); - Lang::Node getNode(GlobalFlow::PathNode n); + predicate isSource(PathNode n); - predicate isSource(GlobalFlow::PathNode n); - - GlobalFlow::PathNode getASuccessor( - GlobalFlow::PathNode n - ); + PathNode getASuccessor(PathNode n); Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); Lang::Node getAnArgumentNode(Lang::DataFlowCall call); } + + module TaintFlowContext TTLang>{ + module AbstractTaintFlow = TT::TaintFlowMake; + module AbstractTaintFlowOverlay = TT::TaintFlowMakeOverlay; + module TaintFlowGlobal = AbstractTaintFlow::Global; + module TaintFlowOverlayGlobal = AbstractTaintFlowOverlay::Global; + } } module BiStackAnalysis< AbstractDF::ConfigSig ConfigA, - AbstractDataFlow::GlobalFlowSig GlobalFlowA, - DataFlowGroup::DataFlowStackSig TaintTrackingStackA, + DataFlowConfigContext::FlowInstance FlowA, AbstractDF::ConfigSig ConfigB, - AbstractDataFlow::GlobalFlowSig GlobalFlowB, - DataFlowGroup::DataFlowStackSig TaintTrackingStackB> + DataFlowConfigContext::FlowInstance FlowB> { - module FlowA = GlobalFlowA; - - module FlowStackA = FlowStack; + module FlowStackA = FlowStack; - module FlowB = GlobalFlowB; - - module FlowStackB = FlowStack; + module FlowStackB = FlowStack; /** * Holds if either the Stack associated with `sourceNodeA` is a subset of the stack associated with `sourceNodeB` @@ -72,10 +66,10 @@ module LanguageDataFlow Lang>{ flowStackA = FlowStackA::createFlowStack(sourceNodeA, sinkNodeA) and flowStackB = FlowStackB::createFlowStack(sourceNodeB, sinkNodeB) and ( - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, + BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, flowStackB) or - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackB, + BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackB, flowStackA) ) ) @@ -100,10 +94,10 @@ module LanguageDataFlow Lang>{ flowStackA = FlowStackA::createFlowStack(sourceNodeA, sinkNodeA) and flowStackB = FlowStackB::createFlowStack(sourceNodeB, sinkNodeB) and ( - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, + BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, flowStackB) or - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackB, + BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackB, flowStackA) ) ) @@ -116,7 +110,7 @@ module LanguageDataFlow Lang>{ * The top of stackA is in stackB and the bottom of stackA is then some successor further down stackB. */ predicate flowStackIsSubsetOf(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB) { - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, + BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, flowStackB) } @@ -128,23 +122,21 @@ module LanguageDataFlow Lang>{ predicate flowStackIsConvergingTerminatingSubsetOf( FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB ) { - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, + BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, flowStackB) } } private module BiStackAnalysisImpl< - AbstractDataFlow::GlobalFlowSig GlobalFlowA, AbstractDF::ConfigSig ConfigA, - DataFlowGroup::DataFlowStackSig DataFlowStackA, - AbstractDataFlow::GlobalFlowSig GlobalFlowB, + DataFlowConfigContext::FlowInstance FlowA, AbstractDF::ConfigSig ConfigB, - DataFlowGroup::DataFlowStackSig DataFlowStackB> + DataFlowConfigContext::FlowInstance FlowB> { - module FlowStackA = FlowStack; + module FlowStackA = FlowStack; - module FlowStackB = FlowStack; + module FlowStackB = FlowStack; /** * Holds if stackA is a subset of stackB, @@ -189,30 +181,25 @@ module LanguageDataFlow Lang>{ } module FlowStack< - AbstractDataFlow::GlobalFlowSig GlobalFlow, AbstractDF::ConfigSig Config, - DataFlowGroup::DataFlowStackSig TaintTrackingStack> - { - private module Flow = GlobalFlow; + DataFlowConfigContext::FlowInstance Flow>{ /** * Determines whether or not the given PathNode is a source - * TODO: Refactor to Flow::PathNode signature */ - predicate isSource(Flow::PathNode node) { TaintTrackingStack::isSource(node) } + predicate isSource = Flow::isSource/1; /** * Determines whether or not the given PathNode is a sink - * TODO: Refactor to Flow::PathNode signature */ - predicate isSink(Flow::PathNode node) { not exists(TaintTrackingStack::getASuccessor(node)) } + predicate isSink(Flow::PathNode node) { not exists(Flow::getASuccessor(node)) } /** A FlowStack encapsulates flows between a source and a sink, and all the pathways inbetween (possibly multiple) */ private newtype FlowStackType = TFlowStack(Flow::PathNode source, Flow::PathNode sink) { - TaintTrackingStack::isSource(source) and - not exists(TaintTrackingStack::getASuccessor(sink)) and - TaintTrackingStack::getASuccessor*(source) = sink + Flow::isSource(source) and + not exists(Flow::getASuccessor(sink)) and + Flow::getASuccessor*(source) = sink } class FlowStack extends FlowStackType, TFlowStack { @@ -261,8 +248,8 @@ module LanguageDataFlow Lang>{ TFlowStackFrame(FlowStack flowStack, CallFrame frame) { exists(Flow::PathNode source, Flow::PathNode sink | flowStack = TFlowStack(source, sink) and - frame.getPathNode() = TaintTrackingStack::getASuccessor*(source) and - TaintTrackingStack::getASuccessor*(frame.getPathNode()) = sink + frame.getPathNode() = Flow::getASuccessor*(source) and + Flow::getASuccessor*(frame.getPathNode()) = sink ) } @@ -305,7 +292,7 @@ module LanguageDataFlow Lang>{ FlowStackFrame getChildStackFrame() { exists(FlowStackFrame transitiveSuccessor | transitiveSuccessor = this.getASuccessor+() and - TaintTrackingStack::getARuntimeTarget(this.getCall()) = + Flow::getARuntimeTarget(this.getCall()) = transitiveSuccessor.getCall().getEnclosingCallable() and result = transitiveSuccessor ) @@ -338,7 +325,7 @@ module LanguageDataFlow Lang>{ private newtype TCallFrameType = TCallFrame(Flow::PathNode node) { exists(Lang::DataFlowCall c | - TaintTrackingStack::getAnArgumentNode(c) = TaintTrackingStack::getNode(node) + Flow::getAnArgumentNode(c) = Flow::getNode(node) ) } @@ -374,7 +361,7 @@ module LanguageDataFlow Lang>{ Lang::DataFlowCall getCall() { exists(Lang::DataFlowCall call, Flow::PathNode node | this = TCallFrame(node) and - TaintTrackingStack::getAnArgumentNode(call) = TaintTrackingStack::getNode(node) and + Flow::getAnArgumentNode(call) = Flow::getNode(node) and result = call ) } @@ -396,10 +383,10 @@ module LanguageDataFlow Lang>{ */ private Flow::PathNode getSuccessorCall(Flow::PathNode n) { exists(Flow::PathNode succ | - succ = TaintTrackingStack::getASuccessor(n) and + succ = Flow::getASuccessor(n) and if exists(Lang::DataFlowCall c | - TaintTrackingStack::getAnArgumentNode(c) = TaintTrackingStack::getNode(succ) + Flow::getAnArgumentNode(c) = Flow::getNode(succ) ) then result = succ else result = getSuccessorCall(succ) diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll deleted file mode 100644 index 763e4438ea79..000000000000 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ /dev/null @@ -1,458 +0,0 @@ -overlay[local?] -module; - -private import codeql.dataflow.DataFlow as DF -private import codeql.dataflow.TaintTracking as TT -private import codeql.util.Location - -/** - * A Language-initialized grouping of DataFlow types and primitives. - */ -module LanguageTaintTracking Lang, TT::InputSig TTLang>{ - module AbstractDF = DF::Configs; - module AbstractDataFlow = DF::DataFlowMake; - module AbstractTaintFlow = TT::TaintFlowMake; - module AbstractTaintFlowOverlay = TT::TaintFlowMakeOverlay; - - /** - * A collection of modules that are scoped to a specific DataFlow config implementation - */ - module DataFlowGroup{ - - module MyConfig = Config; - module TaintFlowGlobal = AbstractTaintFlow::Global; - module TaintFlowOverlayGlobal = AbstractTaintFlowOverlay::Global; - - /** - * A Taint tracking implementation, paramaterized over a DataFlow type - */ - signature module TaintTrackingStackSig{ - - Lang::Node getNode(GlobalFlow::PathNode n); - - predicate isSource(GlobalFlow::PathNode n); - - GlobalFlow::PathNode getASuccessor( - GlobalFlow::PathNode n - ); - - Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); - - Lang::Node getAnArgumentNode(Lang::DataFlowCall call); - } - } - - module BiStackAnalysis< - AbstractDF::ConfigSig ConfigA, - AbstractDataFlow::GlobalFlowSig GlobalFlowA, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStackA, - AbstractDF::ConfigSig ConfigB, - AbstractDataFlow::GlobalFlowSig GlobalFlowB, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStackB> - { - module FlowA = GlobalFlowA; - - module FlowStackA = FlowStack; - - module FlowB = GlobalFlowB; - - module FlowStackB = FlowStack; - - /** - * Holds if either the Stack associated with `sourceNodeA` is a subset of the stack associated with `sourceNodeB` - * or vice-versa. - */ - predicate eitherStackSubset( - FlowA::PathNode sourceNodeA, FlowA::PathNode sinkNodeA, FlowB::PathNode sourceNodeB, - FlowB::PathNode sinkNodeB - ) { - FlowStackA::isSource(sourceNodeA) and - FlowStackB::isSource(sourceNodeB) and - FlowStackA::isSink(sinkNodeA) and - FlowStackB::isSink(sinkNodeB) and - exists(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB | - flowStackA = FlowStackA::createFlowStack(sourceNodeA, sinkNodeA) and - flowStackB = FlowStackB::createFlowStack(sourceNodeB, sinkNodeB) and - ( - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, - flowStackB) - or - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackB, - flowStackA) - ) - ) - } - - /** - * Holds if the stack associated with path `sourceNodeA` is a subset (and shares a common stack bottom) with - * the stack associated with path `sourceNodeB`, or vice-versa. - * - * For the given pair of (source, sink) for two (potentially disparate) DataFlows, - * determine whether one Flow's Stack (at time of sink execution) is a subset of the other flow's Stack. - */ - predicate eitherStackTerminatingSubset( - FlowA::PathNode sourceNodeA, FlowA::PathNode sinkNodeA, FlowB::PathNode sourceNodeB, - FlowB::PathNode sinkNodeB - ) { - FlowStackA::isSource(sourceNodeA) and - FlowStackB::isSource(sourceNodeB) and - FlowStackA::isSink(sinkNodeA) and - FlowStackB::isSink(sinkNodeB) and - exists(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB | - flowStackA = FlowStackA::createFlowStack(sourceNodeA, sinkNodeA) and - flowStackB = FlowStackB::createFlowStack(sourceNodeB, sinkNodeB) and - ( - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, - flowStackB) - or - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackB, - flowStackA) - ) - ) - } - - /** - * Alias for BiStackAnalysisImpl::flowStackIsSubsetOf - * - * Holds if stackA is a subset of stackB, - * The top of stackA is in stackB and the bottom of stackA is then some successor further down stackB. - */ - predicate flowStackIsSubsetOf(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB) { - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, - flowStackB) - } - - /** - * Alias for BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf - * - * If the top of stackA is in stackB at any location, and the bottoms of the stack are the same call. - */ - predicate flowStackIsConvergingTerminatingSubsetOf( - FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB - ) { - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, - flowStackB) - } - } - - private module BiStackAnalysisImpl< - AbstractDataFlow::GlobalFlowSig GlobalFlowA, - AbstractDF::ConfigSig ConfigA, - DataFlowGroup::TaintTrackingStackSig DataFlowStackA, - AbstractDataFlow::GlobalFlowSig GlobalFlowB, - AbstractDF::ConfigSig ConfigB, - DataFlowGroup::TaintTrackingStackSig DataFlowStackB> - { - - module FlowStackA = FlowStack; - - module FlowStackB = FlowStack; - - /** - * Holds if stackA is a subset of stackB, - * The top of stackA is in stackB and the bottom of stackA is then some successor further down stackB. - */ - predicate flowStackIsSubsetOf(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB) { - exists( - FlowStackA::FlowStackFrame highestStackFrameA, FlowStackB::FlowStackFrame highestStackFrameB - | - highestStackFrameA = flowStackA.getTopFrame() and - highestStackFrameB = flowStackB.getTopFrame() and - // Check if some intermediary frame `intStackFrameB`of StackB is in the stack of highestStackFrameA - exists(FlowStackB::FlowStackFrame intStackFrameB | - intStackFrameB = highestStackFrameB.getASucceedingTerminalStateFrame*() and - sharesCallWith(highestStackFrameA, intStackFrameB) and - sharesCallWith(flowStackA.getTerminalFrame(), - intStackFrameB.getASucceedingTerminalStateFrame*()) - ) - ) - } - - /** - * If the top of stackA is in stackB at any location, and the bottoms of the stack are the same call. - */ - predicate flowStackIsConvergingTerminatingSubsetOf( - FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB - ) { - flowStackA.getTerminalFrame().getCall() = flowStackB.getTerminalFrame().getCall() and - exists(FlowStackB::FlowStackFrame intStackFrameB | - intStackFrameB = flowStackB.getTopFrame().getASucceedingTerminalStateFrame*() and - sharesCallWith(flowStackA.getTopFrame(), intStackFrameB) - ) - } - - /** - * Holds if the given FlowStackFrames share the same call. - * i.e. they are both arguments of the same function call. - */ - predicate sharesCallWith(FlowStackA::FlowStackFrame frameA, FlowStackB::FlowStackFrame frameB) { - frameA.getCall() = frameB.getCall() - } - } - - module FlowStack< - AbstractDataFlow::GlobalFlowSig GlobalFlow, - AbstractDF::ConfigSig Config, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> - { - private module Flow = GlobalFlow; - - /** - * Determines whether or not the given PathNode is a source - * TODO: Refactor to Flow::PathNode signature - */ - predicate isSource(Flow::PathNode node) { TaintTrackingStack::isSource(node) } - - /** - * Determines whether or not the given PathNode is a sink - * TODO: Refactor to Flow::PathNode signature - */ - predicate isSink(Flow::PathNode node) { not exists(TaintTrackingStack::getASuccessor(node)) } - - /** A FlowStack encapsulates flows between a source and a sink, and all the pathways inbetween (possibly multiple) */ - private newtype FlowStackType = - TFlowStack(Flow::PathNode source, Flow::PathNode sink) { - TaintTrackingStack::isSource(source) and - not exists(TaintTrackingStack::getASuccessor(sink)) and - TaintTrackingStack::getASuccessor*(source) = sink - } - - class FlowStack extends FlowStackType, TFlowStack { - string toString() { result = "FlowStack" } - - /** - * Get the first frame in the DataFlowStack, irregardless of whether or not it has a parent. - */ - FlowStackFrame getFirstFrame() { - exists(FlowStackFrame flowStackFrame, CallFrame frame | - flowStackFrame = TFlowStackFrame(this, frame) and - not exists(frame.getPredecessor()) and - result = flowStackFrame - ) - } - - /** - * Get the top frame in the DataFlowStack, ie the frame that is the highest in the stack for the given flow. - */ - FlowStackFrame getTopFrame() { - exists(FlowStackFrame flowStackFrame | - flowStackFrame = TFlowStackFrame(this, _) and - not exists(flowStackFrame.getParentStackFrame()) and - result = flowStackFrame - ) - } - - /** - * Get the terminal frame in the DataFlowStack, ie the frame that is the end of the flow. - */ - FlowStackFrame getTerminalFrame() { - exists(FlowStackFrame flowStackFrame, CallFrame frame | - flowStackFrame = TFlowStackFrame(this, frame) and - not exists(frame.getSuccessor()) and - result = flowStackFrame - ) - } - } - - FlowStack createFlowStack(Flow::PathNode source, Flow::PathNode sink) { - result = TFlowStack(source, sink) - } - - /** A FlowStackFrame encapsulates a Stack frame that is bound between a given source and sink. */ - private newtype FlowStackFrameType = - TFlowStackFrame(FlowStack flowStack, CallFrame frame) { - exists(Flow::PathNode source, Flow::PathNode sink | - flowStack = TFlowStack(source, sink) and - frame.getPathNode() = TaintTrackingStack::getASuccessor*(source) and - TaintTrackingStack::getASuccessor*(frame.getPathNode()) = sink - ) - } - - class FlowStackFrame extends FlowStackFrameType, TFlowStackFrame { - string toString() { result = "FlowStackFrame" } - - /** - * Get the next frame in the DataFlow Stack - */ - FlowStackFrame getASuccessor() { - exists(FlowStack flowStack, CallFrame frame, CallFrame nextFrame | - this = TFlowStackFrame(flowStack, frame) and - nextFrame = frame.getSuccessor() and - result = TFlowStackFrame(flowStack, nextFrame) - ) - } - - /** - * Gets the next FlowStackFrame from the direct descendents that is a frame in the end-state (terminal) stack. - */ - FlowStackFrame getASucceedingTerminalStateFrame() { - result = this.getChildStackFrame() and - // There are no other direct children that are further in the flow - not result.getASuccessor+() = this.getChildStackFrame() - } - - /** - * Gets a predecessor FlowStackFrame of this FlowStackFrame. - */ - FlowStackFrame getAPredecessor() { result.getASuccessor() = this } - - /** - * Gets a predecessor FlowStackFrame that is a parent in the stack. - */ - FlowStackFrame getParentStackFrame() { result.getChildStackFrame() = this } - - /** - * Gets the set of succeeding FlowStackFrame which are a direct descendant of this frame in the Stack. - */ - FlowStackFrame getChildStackFrame() { - exists(FlowStackFrame transitiveSuccessor | - transitiveSuccessor = this.getASuccessor+() and - TaintTrackingStack::getARuntimeTarget(this.getCall()) = - transitiveSuccessor.getCall().getEnclosingCallable() and - result = transitiveSuccessor - ) - } - - /** - * Unpacks the PathNode associated with this FlowStackFrame - */ - Flow::PathNode getPathNode() { - exists(CallFrame callFrame | - this = TFlowStackFrame(_, callFrame) and - result = callFrame.getPathNode() - ) - } - - /** - * Unpacks the DataFlowCall associated with this FlowStackFrame - */ - Lang::DataFlowCall getCall() { result = this.getCallFrame().getCall() } - - /** - * Unpacks the CallFrame associated with this FlowStackFrame - */ - CallFrame getCallFrame() { this = TFlowStackFrame(_, result) } - } - - /** - * A CallFrame is a PathNode that represents a (DataFlowCall/Accessor). - */ - private newtype TCallFrameType = - TCallFrame(Flow::PathNode node) { - exists(Lang::DataFlowCall c | - TaintTrackingStack::getAnArgumentNode(c) = TaintTrackingStack::getNode(node) - ) - } - - /** - * The CallFrame is a PathNode that represents an argument to a Call. - */ - private class CallFrame extends TCallFrameType, TCallFrame { - string toString() { - exists(Lang::DataFlowCall call | - call = this.getCall() and - result = call.toString() - ) - } - - /** - * Find the set of CallFrames that are immediate successors of this CallFrame. - */ - CallFrame getSuccessor() { result = TCallFrame(getSuccessorCall(this.getPathNode())) } - - /** - * Find the set of CallFrames that are an immediate predecessor of this CallFrame. - */ - CallFrame getPredecessor() { - exists(CallFrame prior | - prior.getSuccessor() = this and - result = prior - ) - } - - /** - * Unpack the CallFrame and retrieve the associated DataFlowCall. - */ - Lang::DataFlowCall getCall() { - exists(Lang::DataFlowCall call, Flow::PathNode node | - this = TCallFrame(node) and - TaintTrackingStack::getAnArgumentNode(call) = TaintTrackingStack::getNode(node) and - result = call - ) - } - - /** - * Unpack the CallFrame and retrieve the associated PathNode. - */ - Flow::PathNode getPathNode() { - exists(Flow::PathNode n | - this = TCallFrame(n) and - result = n - ) - } - } - - /** - * From the given PathNode argument, find the set of successors that are an argument in a DataFlowCall, - * and return them as the result. - */ - private Flow::PathNode getSuccessorCall(Flow::PathNode n) { - exists(Flow::PathNode succ | - succ = TaintTrackingStack::getASuccessor(n) and - if - exists(Lang::DataFlowCall c | - TaintTrackingStack::getAnArgumentNode(c) = TaintTrackingStack::getNode(succ) - ) - then result = succ - else result = getSuccessorCall(succ) - ) - } - - /** - * A user-supplied predicate which given a Stack Frame, returns some Node associated with it. - */ - signature Lang::Node extractNodeFromFrame(Flow::PathNode pathNode); - - /** - * Provides some higher-order predicates for analyzing Stacks - */ - module StackFrameAnalysis { - /** - * Find the highest stack frame that satisfies the given predicate, - * and return the Node(s) that the user-supplied predicate returns. - * - * There should be no higher stack frame that satisfies the user-supplied predicate FROM the point that the - * argument . - */ - Lang::Node extractingFromHighestStackFrame(FlowStack flowStack) { - exists(FlowStackFrame topStackFrame, FlowStackFrame someStackFrame | - topStackFrame = flowStack.getTopFrame() and - someStackFrame = topStackFrame.getASuccessor*() and - result = customFrameCond(someStackFrame.getPathNode()) and - not exists(FlowStackFrame predecessor | - predecessor = someStackFrame.getAPredecessor+() and - // The predecessor is *not* prior to the user-given 'top' of the stack frame. - not predecessor = topStackFrame.getAPredecessor+() and - exists(customFrameCond(predecessor.getPathNode())) - ) - ) - } - - /** - * Find the lowest stack frame that satisfies the given predicate, - * and return the Node(s) that the user-supplied predicate returns. - */ - Lang::Node extractingFromLowestStackFrame(FlowStack flowStack) { - exists(FlowStackFrame topStackFrame, FlowStackFrame someStackFrame | - topStackFrame = flowStack.getTopFrame() and - someStackFrame = topStackFrame.getChildStackFrame*() and - result = customFrameCond(someStackFrame.getPathNode()) and - not exists(FlowStackFrame successor | - successor = someStackFrame.getChildStackFrame+() and - exists(customFrameCond(successor.getPathNode())) - ) - ) - } - } - } -} \ No newline at end of file