From ab8130e7312477883613bae285a6f38aeb6028ac Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Tue, 28 Oct 2025 23:53:57 -0700 Subject: [PATCH 1/6] Reduce Type reference complexity using aliases --- .../code/java/dataflow/TaintTrackingStack.qll | 8 +- .../dataflowstack/TaintTrackingStack.qll | 727 +++++++++--------- 2 files changed, 389 insertions(+), 346 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll b/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll index 711b8dd5dbbe..f3a6db14e078 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll @@ -7,10 +7,12 @@ 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 TTS::TaintTrackingStackMake as TaintTrackingStackFactory -private module TaintTrackingStackInput - implements TTS::TaintTrackingStackSig +module TaintTrackingStack = TTS::LanguageTaintTracking; +// private import TTS::TaintTrackingStackMake<> as TaintTrackingStackFactory + +private module TaintTrackingStackInput + implements TaintTrackingStack::TaintTrackingStackSig { private module Flow = TaintTracking::Global; diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll index 202619d75bc9..668bc8af9df1 100644 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll @@ -5,435 +5,476 @@ private import codeql.dataflow.DataFlow as DF private import codeql.dataflow.TaintTracking as TT private import codeql.util.Location -signature module TaintTrackingStackSig< - LocationSig Location, DF::InputSig Lang, TT::InputSig TTLang, - DF::Configs::ConfigSig Config> +/** + * A Language-initialized grouping of DataFlow types and primitives. + */ +module LanguageTaintTracking Lang, TT::InputSig TTLang> { - Lang::Node getNode(TT::TaintFlowMake::Global::PathNode n); + module AbstractDF = DF::Configs; + module AbstractDataFlow = DF::DataFlowMake; + module AbstractTaintFlow = TT::TaintFlowMake; + module AbstractTaintFlowOverlay = TT::TaintFlowMakeOverlay; - predicate isSource(TT::TaintFlowMake::Global::PathNode n); + /** + * A collection of modules that are scoped to a specific DataFlow config implementation + */ + module DataFlowGroup{ - TT::TaintFlowMake::Global::PathNode getASuccessor( - TT::TaintFlowMake::Global::PathNode n - ); + module TaintFlowGlobal = AbstractTaintFlow::Global; + module TaintFlowOverlayGlobal = AbstractTaintFlowOverlay::Global; - Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); - - Lang::Node getAnArgumentNode(Lang::DataFlowCall call); -} - -module TaintTrackingStackMake< - LocationSig Location, DF::InputSig Lang, TT::InputSig TTLang> -{ - module DataFlow = DF::DataFlowMake; - - module TaintTracking = TT::TaintFlowMake; + /** + * A Taint tracking implementation without Overlay + */ + signature module TaintTrackingStackSig{ - module BiStackAnalysis< - DF::Configs::ConfigSig ConfigA, - TaintTrackingStackSig TaintTrackingStackA, - DF::Configs::ConfigSig ConfigB, - TaintTrackingStackSig TaintTrackingStackB> - { - module FlowA = TaintTracking::Global; + Lang::Node getNode(TaintFlowGlobal::PathNode n); - module FlowStackA = FlowStack; + predicate isSource(TaintFlowGlobal::PathNode n); - module FlowB = TaintTracking::Global; + TaintFlowGlobal::PathNode getASuccessor( + TaintFlowGlobal::PathNode n + ); - module FlowStackB = FlowStack; + Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); - /** - * 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) - ) - ) + Lang::Node getAnArgumentNode(Lang::DataFlowCall call); } /** - * 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. + * TODO: Declare a AbstractTaintFlow Signature, and allow consumer to specify either TaintFlowMake or TaintFlowMakeOverlay + * depending on the language + * + * A Taint tracking implementation with Overlay */ - 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) - ) - ) - } + signature module TaintTrackingOverlayStackSig{ - /** - * 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) - } + Lang::Node getNode(TaintFlowOverlayGlobal::PathNode n); - /** - * 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) - } - } + predicate isSource(TaintFlowOverlayGlobal::PathNode n); - private module BiStackAnalysisImpl< - DF::Configs::ConfigSig ConfigA, - TaintTrackingStackSig DataFlowStackA, - DF::Configs::ConfigSig ConfigB, - TaintTrackingStackSig DataFlowStackB> - { - module FlowStackA = FlowStack; + TaintFlowOverlayGlobal::PathNode getASuccessor( + TaintFlowOverlayGlobal::PathNode n + ); - 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) - ) - } + Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); - /** - * 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() + Lang::Node getAnArgumentNode(Lang::DataFlowCall call); } } +// } +// +// module TaintTrackingStackMake< +// LocationSig Location, DF::InputSig Lang, TT::InputSig TTLang> +// { - module FlowStack< - DF::Configs::ConfigSig Config, - TaintTrackingStackSig TaintTrackingStack> - { - private module Flow = TT::TaintFlowMake::Global; + // module TaintTracking = TT::TaintFlowMake; - /** - * Determines whether or not the given PathNode is a source - * TODO: Refactor to Flow::PathNode signature - */ - predicate isSource(Flow::PathNode node) { TaintTrackingStack::isSource(node) } + module BiStackAnalysis< + AbstractDF::ConfigSig ConfigA, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStackA, + AbstractDF::ConfigSig ConfigB, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStackB> + { + module FlowA = AbstractTaintFlow::Global; - /** - * 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 - } + module FlowStackA = FlowStack; + + module FlowB = AbstractTaintFlow::Global; - class FlowStack extends FlowStackType, TFlowStack { - string toString() { result = "FlowStack" } + module FlowStackB = FlowStack; /** - * Get the first frame in the DataFlowStack, irregardless of whether or not it has a parent. + * Holds if either the Stack associated with `sourceNodeA` is a subset of the stack associated with `sourceNodeB` + * or vice-versa. */ - FlowStackFrame getFirstFrame() { - exists(FlowStackFrame flowStackFrame, CallFrame frame | - flowStackFrame = TFlowStackFrame(this, frame) and - not exists(frame.getPredecessor()) and - result = flowStackFrame + 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) + ) ) } /** - * Get the top frame in the DataFlowStack, ie the frame that is the highest in the stack for the given flow. + * 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. */ - FlowStackFrame getTopFrame() { - exists(FlowStackFrame flowStackFrame | - flowStackFrame = TFlowStackFrame(this, _) and - not exists(flowStackFrame.getParentStackFrame()) and - result = flowStackFrame + 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) + ) ) } /** - * Get the terminal frame in the DataFlowStack, ie the frame that is the end of the flow. + * 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. */ - FlowStackFrame getTerminalFrame() { - exists(FlowStackFrame flowStackFrame, CallFrame frame | - flowStackFrame = TFlowStackFrame(this, frame) and - not exists(frame.getSuccessor()) and - result = flowStackFrame - ) + predicate flowStackIsSubsetOf(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB) { + BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, + flowStackB) } - } - FlowStack createFlowStack(Flow::PathNode source, Flow::PathNode sink) { - result = TFlowStack(source, sink) + /** + * 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) + } } - /** 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 - ) - } + private module BiStackAnalysisImpl< + AbstractDF::ConfigSig ConfigA, + DataFlowGroup::TaintTrackingStackSig DataFlowStackA, + AbstractDF::ConfigSig ConfigB, + DataFlowGroup::TaintTrackingStackSig DataFlowStackB> + { + module FlowStackA = FlowStack; - class FlowStackFrame extends FlowStackFrameType, TFlowStackFrame { - string toString() { result = "FlowStackFrame" } + module FlowStackB = FlowStack; /** - * Get the next frame in the DataFlow Stack + * 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. */ - FlowStackFrame getASuccessor() { - exists(FlowStack flowStack, CallFrame frame, CallFrame nextFrame | - this = TFlowStackFrame(flowStack, frame) and - nextFrame = frame.getSuccessor() and - result = TFlowStackFrame(flowStack, nextFrame) + 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*()) + ) ) } /** - * Gets the next FlowStackFrame from the direct descendents that is a frame in the end-state (terminal) stack. + * If the top of stackA is in stackB at any location, and the bottoms of the stack are the same call. */ - FlowStackFrame getASucceedingTerminalStateFrame() { - result = this.getChildStackFrame() and - // There are no other direct children that are further in the flow - not result.getASuccessor+() = this.getChildStackFrame() + 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) + ) } /** - * Gets a predecessor FlowStackFrame of this FlowStackFrame. + * Holds if the given FlowStackFrames share the same call. + * i.e. they are both arguments of the same function call. */ - FlowStackFrame getAPredecessor() { result.getASuccessor() = this } + predicate sharesCallWith(FlowStackA::FlowStackFrame frameA, FlowStackB::FlowStackFrame frameB) { + frameA.getCall() = frameB.getCall() + } + } - /** - * Gets a predecessor FlowStackFrame that is a parent in the stack. - */ - FlowStackFrame getParentStackFrame() { result.getChildStackFrame() = this } + module FlowStack< + AbstractDF::ConfigSig Config, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> + { + private module Flow = TT::TaintFlowMake::Global; /** - * Gets the set of succeeding FlowStackFrame which are a direct descendant of this frame in the Stack. + * Determines whether or not the given PathNode is a source + * TODO: Refactor to Flow::PathNode signature */ - FlowStackFrame getChildStackFrame() { - exists(FlowStackFrame transitiveSuccessor | - transitiveSuccessor = this.getASuccessor+() and - TaintTrackingStack::getARuntimeTarget(this.getCall()) = - transitiveSuccessor.getCall().getEnclosingCallable() and - result = transitiveSuccessor - ) - } + predicate isSource(Flow::PathNode node) { TaintTrackingStack::isSource(node) } /** - * Unpacks the PathNode associated with this FlowStackFrame + * Determines whether or not the given PathNode is a sink + * TODO: Refactor to Flow::PathNode signature */ - Flow::PathNode getPathNode() { - exists(CallFrame callFrame | - this = TFlowStackFrame(_, callFrame) and - result = callFrame.getPathNode() - ) + 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 + ) + } } - /** - * Unpacks the DataFlowCall associated with this FlowStackFrame - */ - Lang::DataFlowCall getCall() { result = this.getCallFrame().getCall() } + FlowStack createFlowStack(Flow::PathNode source, Flow::PathNode sink) { + result = TFlowStack(source, sink) + } - /** - * Unpacks the CallFrame associated with this FlowStackFrame - */ - CallFrame getCallFrame() { this = TFlowStackFrame(_, result) } - } + /** 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() + ) + } - /** - * 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) - ) - } + /** + * Unpacks the DataFlowCall associated with this FlowStackFrame + */ + Lang::DataFlowCall getCall() { result = this.getCallFrame().getCall() } - /** - * 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() - ) + /** + * Unpacks the CallFrame associated with this FlowStackFrame + */ + CallFrame getCallFrame() { this = TFlowStackFrame(_, result) } } /** - * Find the set of CallFrames that are immediate successors of this CallFrame. + * A CallFrame is a PathNode that represents a (DataFlowCall/Accessor). */ - CallFrame getSuccessor() { result = TCallFrame(getSuccessorCall(this.getPathNode())) } + private newtype TCallFrameType = + TCallFrame(Flow::PathNode node) { + exists(Lang::DataFlowCall c | + TaintTrackingStack::getAnArgumentNode(c) = TaintTrackingStack::getNode(node) + ) + } /** - * Find the set of CallFrames that are an immediate predecessor of this CallFrame. + * The CallFrame is a PathNode that represents an argument to a Call. */ - CallFrame getPredecessor() { - exists(CallFrame prior | - prior.getSuccessor() = this and - result = prior - ) + 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 + ) + } } /** - * Unpack the CallFrame and retrieve the associated DataFlowCall. + * From the given PathNode argument, find the set of successors that are an argument in a DataFlowCall, + * and return them as the result. */ - Lang::DataFlowCall getCall() { - exists(Lang::DataFlowCall call, Flow::PathNode node | - this = TCallFrame(node) and - TaintTrackingStack::getAnArgumentNode(call) = TaintTrackingStack::getNode(node) and - result = call + 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) ) } /** - * Unpack the CallFrame and retrieve the associated PathNode. + * A user-supplied predicate which given a Stack Frame, returns some Node associated with it. */ - 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) - ) - } + signature Lang::Node extractNodeFromFrame(Flow::PathNode pathNode); - /** - * 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 . + * Provides some higher-order predicates for analyzing Stacks */ - 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())) + 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())) + } + + /** + * 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 From 641d3793313e7f193e11015c018000dd10f1c459 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Wed, 29 Oct 2025 00:06:19 -0700 Subject: [PATCH 2/6] indendation --- .../dataflowstack/TaintTrackingStack.qll | 683 +++++++++--------- 1 file changed, 339 insertions(+), 344 deletions(-) diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll index 668bc8af9df1..880f92d5282b 100644 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll @@ -20,6 +20,7 @@ module LanguageTaintTracking Lang, */ module DataFlowGroup{ + module MyConfig = Config; module TaintFlowGlobal = AbstractTaintFlow::Global; module TaintFlowOverlayGlobal = AbstractTaintFlowOverlay::Global; @@ -62,419 +63,413 @@ module LanguageTaintTracking Lang, Lang::Node getAnArgumentNode(Lang::DataFlowCall call); } } -// } -// -// module TaintTrackingStackMake< -// LocationSig Location, DF::InputSig Lang, TT::InputSig TTLang> -// { - // module TaintTracking = TT::TaintFlowMake; + module BiStackAnalysis< + AbstractDF::ConfigSig ConfigA, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStackA, + AbstractDF::ConfigSig ConfigB, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStackB> + { + module FlowA = AbstractTaintFlow::Global; - module BiStackAnalysis< - AbstractDF::ConfigSig ConfigA, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStackA, - AbstractDF::ConfigSig ConfigB, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStackB> - { - module FlowA = AbstractTaintFlow::Global; + module FlowStackA = FlowStack; - module FlowStackA = FlowStack; + module FlowB = AbstractTaintFlow::Global; - module FlowB = AbstractTaintFlow::Global; + module FlowStackB = FlowStack; - 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 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< + AbstractDF::ConfigSig ConfigA, + DataFlowGroup::TaintTrackingStackSig DataFlowStackA, + 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< + AbstractDF::ConfigSig Config, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> + { + private module Flow = TT::TaintFlowMake::Global; + + /** + * 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" } + /** - * 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. + * Get the first frame in the DataFlowStack, irregardless of whether or not it has a parent. */ - 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) - ) + FlowStackFrame getFirstFrame() { + exists(FlowStackFrame flowStackFrame, CallFrame frame | + flowStackFrame = TFlowStackFrame(this, frame) and + not exists(frame.getPredecessor()) and + result = flowStackFrame ) } /** - * 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. + * Get the top frame in the DataFlowStack, ie the frame that is the highest in the stack for the given flow. */ - predicate flowStackIsSubsetOf(FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB) { - BiStackAnalysisImpl::flowStackIsSubsetOf(flowStackA, - flowStackB) + FlowStackFrame getTopFrame() { + exists(FlowStackFrame flowStackFrame | + flowStackFrame = TFlowStackFrame(this, _) and + not exists(flowStackFrame.getParentStackFrame()) and + result = flowStackFrame + ) } /** - * 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. + * Get the terminal frame in the DataFlowStack, ie the frame that is the end of the flow. */ - predicate flowStackIsConvergingTerminatingSubsetOf( - FlowStackA::FlowStack flowStackA, FlowStackB::FlowStack flowStackB - ) { - BiStackAnalysisImpl::flowStackIsConvergingTerminatingSubsetOf(flowStackA, - flowStackB) + FlowStackFrame getTerminalFrame() { + exists(FlowStackFrame flowStackFrame, CallFrame frame | + flowStackFrame = TFlowStackFrame(this, frame) and + not exists(frame.getSuccessor()) and + result = flowStackFrame + ) } } - private module BiStackAnalysisImpl< - AbstractDF::ConfigSig ConfigA, - DataFlowGroup::TaintTrackingStackSig DataFlowStackA, - AbstractDF::ConfigSig ConfigB, - DataFlowGroup::TaintTrackingStackSig DataFlowStackB> - { - module FlowStackA = FlowStack; - - module FlowStackB = FlowStack; + FlowStack createFlowStack(Flow::PathNode source, Flow::PathNode sink) { + result = TFlowStack(source, sink) + } - /** - * 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*()) - ) + /** 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" } + /** - * If the top of stackA is in stackB at any location, and the bottoms of the stack are the same call. + * Get the next frame in the DataFlow Stack */ - 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) + FlowStackFrame getASuccessor() { + exists(FlowStack flowStack, CallFrame frame, CallFrame nextFrame | + this = TFlowStackFrame(flowStack, frame) and + nextFrame = frame.getSuccessor() and + result = TFlowStackFrame(flowStack, nextFrame) ) } /** - * Holds if the given FlowStackFrames share the same call. - * i.e. they are both arguments of the same function call. + * Gets the next FlowStackFrame from the direct descendents that is a frame in the end-state (terminal) stack. */ - predicate sharesCallWith(FlowStackA::FlowStackFrame frameA, FlowStackB::FlowStackFrame frameB) { - frameA.getCall() = frameB.getCall() + FlowStackFrame getASucceedingTerminalStateFrame() { + result = this.getChildStackFrame() and + // There are no other direct children that are further in the flow + not result.getASuccessor+() = this.getChildStackFrame() } - } - module FlowStack< - AbstractDF::ConfigSig Config, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> - { - private module Flow = TT::TaintFlowMake::Global; + /** + * Gets a predecessor FlowStackFrame of this FlowStackFrame. + */ + FlowStackFrame getAPredecessor() { result.getASuccessor() = this } /** - * Determines whether or not the given PathNode is a source - * TODO: Refactor to Flow::PathNode signature + * Gets a predecessor FlowStackFrame that is a parent in the stack. */ - predicate isSource(Flow::PathNode node) { TaintTrackingStack::isSource(node) } + FlowStackFrame getParentStackFrame() { result.getChildStackFrame() = this } /** - * Determines whether or not the given PathNode is a sink - * TODO: Refactor to Flow::PathNode signature + * Gets the set of succeeding FlowStackFrame which are a direct descendant of this frame in the Stack. */ - 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 - ) - } + FlowStackFrame getChildStackFrame() { + exists(FlowStackFrame transitiveSuccessor | + transitiveSuccessor = this.getASuccessor+() and + TaintTrackingStack::getARuntimeTarget(this.getCall()) = + transitiveSuccessor.getCall().getEnclosingCallable() and + result = transitiveSuccessor + ) } - FlowStack createFlowStack(Flow::PathNode source, Flow::PathNode sink) { - result = TFlowStack(source, sink) + /** + * Unpacks the PathNode associated with this FlowStackFrame + */ + Flow::PathNode getPathNode() { + exists(CallFrame callFrame | + this = TFlowStackFrame(_, callFrame) and + result = callFrame.getPathNode() + ) } - /** 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 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) + ) + } - /** - * Unpacks the CallFrame associated with this FlowStackFrame - */ - CallFrame getCallFrame() { this = TFlowStackFrame(_, result) } + /** + * 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() + ) } /** - * A CallFrame is a PathNode that represents a (DataFlowCall/Accessor). + * Find the set of CallFrames that are immediate successors of this CallFrame. */ - private newtype TCallFrameType = - TCallFrame(Flow::PathNode node) { - exists(Lang::DataFlowCall c | - TaintTrackingStack::getAnArgumentNode(c) = TaintTrackingStack::getNode(node) - ) - } + CallFrame getSuccessor() { result = TCallFrame(getSuccessorCall(this.getPathNode())) } /** - * The CallFrame is a PathNode that represents an argument to a Call. + * Find the set of CallFrames that are an immediate predecessor of this CallFrame. */ - 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 - ) - } + CallFrame getPredecessor() { + exists(CallFrame prior | + prior.getSuccessor() = this and + result = prior + ) } /** - * From the given PathNode argument, find the set of successors that are an argument in a DataFlowCall, - * and return them as the result. + * Unpack the CallFrame and retrieve the associated DataFlowCall. */ - 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) + Lang::DataFlowCall getCall() { + exists(Lang::DataFlowCall call, Flow::PathNode node | + this = TCallFrame(node) and + TaintTrackingStack::getAnArgumentNode(call) = TaintTrackingStack::getNode(node) and + result = call ) } /** - * A user-supplied predicate which given a Stack Frame, returns some Node associated with it. + * Unpack the CallFrame and retrieve the associated PathNode. */ - signature Lang::Node extractNodeFromFrame(Flow::PathNode 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 { /** - * Provides some higher-order predicates for analyzing Stacks + * 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 . */ - 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())) - ) + 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())) - ) + ) + } + + /** + * 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 From a20e093839a0adcd6c03252d6be748ef654bf2f2 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Wed, 29 Oct 2025 22:25:28 -0700 Subject: [PATCH 3/6] All types matching up --- .../dataflowstack/TaintTrackingStack.qll | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll index 880f92d5282b..0f2a38c26f86 100644 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll @@ -25,16 +25,16 @@ module LanguageTaintTracking Lang, module TaintFlowOverlayGlobal = AbstractTaintFlowOverlay::Global; /** - * A Taint tracking implementation without Overlay + * A Taint tracking implementation, paramaterized over a DataFlow type */ - signature module TaintTrackingStackSig{ + signature module TaintTrackingStackSig{ - Lang::Node getNode(TaintFlowGlobal::PathNode n); + Lang::Node getNode(GlobalFlow::PathNode n); - predicate isSource(TaintFlowGlobal::PathNode n); + predicate isSource(GlobalFlow::PathNode n); - TaintFlowGlobal::PathNode getASuccessor( - TaintFlowGlobal::PathNode n + GlobalFlow::PathNode getASuccessor( + GlobalFlow::PathNode n ); Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); @@ -42,41 +42,42 @@ module LanguageTaintTracking Lang, Lang::Node getAnArgumentNode(Lang::DataFlowCall call); } - /** - * TODO: Declare a AbstractTaintFlow Signature, and allow consumer to specify either TaintFlowMake or TaintFlowMakeOverlay - * depending on the language - * - * A Taint tracking implementation with Overlay - */ - signature module TaintTrackingOverlayStackSig{ + // TODO: Declare a AbstractTaintFlow Signature, and allow consumer to specify either TaintFlowMake or TaintFlowMakeOverlay + // depending on the language + // + // A Taint tracking implementation with Overlay + // / + // signature module TaintTrackingOverlayStackSig{ - Lang::Node getNode(TaintFlowOverlayGlobal::PathNode n); + // Lang::Node getNode(TaintFlowOverlayGlobal::PathNode n); - predicate isSource(TaintFlowOverlayGlobal::PathNode n); + // predicate isSource(TaintFlowOverlayGlobal::PathNode n); - TaintFlowOverlayGlobal::PathNode getASuccessor( - TaintFlowOverlayGlobal::PathNode n - ); + // TaintFlowOverlayGlobal::PathNode getASuccessor( + // TaintFlowOverlayGlobal::PathNode n + // ); - Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); + // Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); - Lang::Node getAnArgumentNode(Lang::DataFlowCall call); - } + // Lang::Node getAnArgumentNode(Lang::DataFlowCall call); + // } } module BiStackAnalysis< AbstractDF::ConfigSig ConfigA, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStackA, + AbstractDataFlow::GlobalFlowSig GlobalFlowA, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStackA, AbstractDF::ConfigSig ConfigB, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStackB> + AbstractDataFlow::GlobalFlowSig GlobalFlowB, + DataFlowGroup::TaintTrackingStackSig TaintTrackingStackB> { - module FlowA = AbstractTaintFlow::Global; + module FlowA = GlobalFlowA; - module FlowStackA = FlowStack; + module FlowStackA = FlowStack; - module FlowB = AbstractTaintFlow::Global; + 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` @@ -94,10 +95,10 @@ module LanguageTaintTracking 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) ) ) @@ -122,10 +123,10 @@ module LanguageTaintTracking 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) ) ) @@ -138,7 +139,7 @@ module LanguageTaintTracking 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) } @@ -150,21 +151,23 @@ module LanguageTaintTracking 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::TaintTrackingStackSig DataFlowStackA, + DataFlowGroup::TaintTrackingStackSig DataFlowStackA, + AbstractDataFlow::GlobalFlowSig GlobalFlowB, AbstractDF::ConfigSig ConfigB, - DataFlowGroup::TaintTrackingStackSig DataFlowStackB> + DataFlowGroup::TaintTrackingStackSig DataFlowStackB> { - module FlowStackA = FlowStack; + module FlowStackA = FlowStack; - module FlowStackB = FlowStack; + module FlowStackB = FlowStack; /** * Holds if stackA is a subset of stackB, @@ -209,10 +212,11 @@ module LanguageTaintTracking Lang, } module FlowStack< + AbstractDataFlow::GlobalFlowSig GlobalFlow, AbstractDF::ConfigSig Config, - DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> + DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> { - private module Flow = TT::TaintFlowMake::Global; + private module Flow = GlobalFlow; //TT::TaintFlowMake::Global; /** * Determines whether or not the given PathNode is a source From d6adad82feb6c9c4df1e90a52d046171331f63ad Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Wed, 29 Oct 2025 22:26:00 -0700 Subject: [PATCH 4/6] Remove code commented out --- .../dataflowstack/TaintTrackingStack.qll | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll index 0f2a38c26f86..ddf4e4d53204 100644 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll @@ -41,26 +41,6 @@ module LanguageTaintTracking Lang, Lang::Node getAnArgumentNode(Lang::DataFlowCall call); } - - // TODO: Declare a AbstractTaintFlow Signature, and allow consumer to specify either TaintFlowMake or TaintFlowMakeOverlay - // depending on the language - // - // A Taint tracking implementation with Overlay - // / - // signature module TaintTrackingOverlayStackSig{ - - // Lang::Node getNode(TaintFlowOverlayGlobal::PathNode n); - - // predicate isSource(TaintFlowOverlayGlobal::PathNode n); - - // TaintFlowOverlayGlobal::PathNode getASuccessor( - // TaintFlowOverlayGlobal::PathNode n - // ); - - // Lang::DataFlowCallable getARuntimeTarget(Lang::DataFlowCall call); - - // Lang::Node getAnArgumentNode(Lang::DataFlowCall call); - // } } module BiStackAnalysis< From ced775a953a17d7b054481d2931287806e3dec1a Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Wed, 29 Oct 2025 22:26:30 -0700 Subject: [PATCH 5/6] Removed commented code --- .../dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll index ddf4e4d53204..95ed7e77c992 100644 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll @@ -196,7 +196,7 @@ module LanguageTaintTracking Lang, AbstractDF::ConfigSig Config, DataFlowGroup::TaintTrackingStackSig TaintTrackingStack> { - private module Flow = GlobalFlow; //TT::TaintFlowMake::Global; + private module Flow = GlobalFlow; /** * Determines whether or not the given PathNode is a source From 18ff8d26692ddc2118f0e1b7b107b24d5e63fef4 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Tue, 4 Nov 2025 10:52:38 -0800 Subject: [PATCH 6/6] Parameterize TaintTrackingStack over Global Dataflow implementation --- .../code/java/dataflow/TaintTrackingStack.qll | 17 ++++++++--------- .../codeql/dataflowstack/TaintTrackingStack.qll | 3 +-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll b/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll index f3a6db14e078..b83d4fce814f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TaintTrackingStack.qll @@ -8,11 +8,10 @@ private import semmle.code.java.dataflow.internal.DataFlowImplSpecific private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific private import codeql.dataflowstack.TaintTrackingStack as TTS -module TaintTrackingStack = TTS::LanguageTaintTracking; -// private import TTS::TaintTrackingStackMake<> as TaintTrackingStackFactory +module LanguageTaintTrackingStack = TTS::LanguageTaintTracking; private module TaintTrackingStackInput - implements TaintTrackingStack::TaintTrackingStackSig + implements LanguageTaintTrackingStack::DataFlowGroup::TaintTrackingStackSig> { private module Flow = TaintTracking::Global; @@ -31,13 +30,13 @@ private module TaintTrackingStackInput } } -module DataFlowStackMake { - import TaintTrackingStackFactory::FlowStack> +module DataFlowStackMake { + import LanguageTaintTrackingStack::FlowStack, Config, TaintTrackingStackInput> } module BiStackAnalysisMake< - TaintTrackingStackFactory::DataFlow::ConfigSig ConfigA, - TaintTrackingStackFactory::DataFlow::ConfigSig ConfigB> -{ - import TaintTrackingStackFactory::BiStackAnalysis, ConfigB, TaintTrackingStackInput> + DataFlow::ConfigSig ConfigA, + DataFlow::ConfigSig ConfigB +>{ + import LanguageTaintTrackingStack::BiStackAnalysis, TaintTrackingStackInput, ConfigB, TaintTracking::Global, TaintTrackingStackInput> } \ No newline at end of file diff --git a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll index 95ed7e77c992..763e4438ea79 100644 --- a/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll +++ b/shared/dataflowstack/codeql/dataflowstack/TaintTrackingStack.qll @@ -8,8 +8,7 @@ private import codeql.util.Location /** * A Language-initialized grouping of DataFlow types and primitives. */ -module LanguageTaintTracking Lang, TT::InputSig TTLang> -{ +module LanguageTaintTracking Lang, TT::InputSig TTLang>{ module AbstractDF = DF::Configs; module AbstractDataFlow = DF::DataFlowMake; module AbstractTaintFlow = TT::TaintFlowMake;