diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index 23caaee0cce10..42150ed975a6d 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -1335,7 +1335,7 @@ module MakeImpl { ) or // flow into a callable - fwdFlowIn(_, node, state, _, cc, _, _, _, t, ap, apa) and + fwdFlowIn(node, apa, state, cc, t, ap) and if PrevStage::parameterMayFlowThrough(node, apa) then ( summaryCtx = TParamNodeSome(node.asNode()) and @@ -1413,64 +1413,120 @@ module MakeImpl { ) } - bindingset[call, ctx] - pragma[inline_late] - private DataFlowCallable viableImplCallContextReducedInlineLate( - DataFlowCall call, CcCall ctx - ) { - result = viableImplCallContextReduced(call, ctx) - } + private signature module FwdFlowInInputSig { + default predicate callRestriction(DataFlowCall call) { any() } - bindingset[arg, ctx] - pragma[inline_late] - private DataFlowCallable viableImplCallContextReducedInlineLate( - DataFlowCall call, ArgNodeEx arg, CcCall ctx - ) { - call = arg.getCall() and - result = viableImplCallContextReducedInlineLate(call, ctx) + bindingset[p, apa] + default predicate parameterRestriction(ParamNodeEx p, ApApprox apa) { any() } } - bindingset[call] - pragma[inline_late] - private predicate flowIntoCallApaInlineLate( - DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p, - boolean allowsFieldFlow, ApApprox apa - ) { - flowIntoCallApa(call, c, arg, p, allowsFieldFlow, apa) + /** + * Exposes the inlined predicate `fwdFlowIn`, which is used to calculate both + * flow in and flow through. + * + * For flow in, only a subset of the columns are needed, specifically we don't + * need to record the argument that flows into the parameter. + * + * For flow through, we do need to record the argument, however, we can restrict + * this to arguments that may actually flow through, using `callRestriction` and + * `parameterRestriction`, which reduces the argument-to-parameter fan-in + * significantly. + */ + private module FwdFlowIn { + pragma[nomagic] + private predicate flowIntoCallApaRestricted( + DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p, + boolean allowsFieldFlow, ApApprox apa + ) { + flowIntoCallApa(call, c, arg, p, allowsFieldFlow, apa) and + I::callRestriction(call) and + I::parameterRestriction(p, apa) + } + + pragma[nomagic] + private DataFlowCallable viableImplCallContextReducedRestricted( + DataFlowCall call, CcCall ctx + ) { + result = viableImplCallContextReduced(call, ctx) and + flowIntoCallApaRestricted(call, result, _, _, _, _) + } + + bindingset[call, ctx] + pragma[inline_late] + private DataFlowCallable viableImplCallContextReducedInlineLate( + DataFlowCall call, CcCall ctx + ) { + result = viableImplCallContextReducedRestricted(call, ctx) + } + + bindingset[arg, ctx] + pragma[inline_late] + private DataFlowCallable viableImplCallContextReducedInlineLate( + DataFlowCall call, ArgNodeEx arg, CcCall ctx + ) { + flowIntoCallApaRestricted(call, _, arg, _, _, _) and + result = viableImplCallContextReducedInlineLate(call, ctx) + } + + bindingset[call] + pragma[inline_late] + private predicate flowIntoCallApaInlineLate( + DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p, + boolean allowsFieldFlow, ApApprox apa + ) { + flowIntoCallApaRestricted(call, c, arg, p, allowsFieldFlow, apa) + } + + bindingset[call, ctx] + pragma[inline_late] + private predicate viableImplNotCallContextReducedInlineLate(DataFlowCall call, Cc ctx) { + viableImplNotCallContextReduced(call, ctx) + } + + bindingset[arg, outercc] + pragma[inline_late] + private predicate viableImplArgNotCallContextReduced( + DataFlowCall call, ArgNodeEx arg, Cc outercc + ) { + flowIntoCallApaRestricted(call, _, arg, _, _, _) and + viableImplNotCallContextReducedInlineLate(call, outercc) + } + + pragma[inline] + predicate fwdFlowIn( + DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc, + ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa + ) { + exists(ArgNodeEx arg, boolean allowsFieldFlow, DataFlowCallable inner | + fwdFlow(arg, state, outercc, summaryCtx, argT, argAp, t, ap, apa) and + ( + inner = viableImplCallContextReducedInlineLate(call, arg, outercc) + or + viableImplArgNotCallContextReduced(call, arg, outercc) + ) and + flowIntoCallApaInlineLate(call, inner, arg, p, allowsFieldFlow, apa) + | + innercc = getCallContextCall(call, inner) and + if allowsFieldFlow = false then ap instanceof ApNil else any() + ) + } } - bindingset[call, ctx] - pragma[inline_late] - private predicate viableImplNotCallContextReducedInlineLate(DataFlowCall call, Cc ctx) { - viableImplNotCallContextReduced(call, ctx) - } + private module FwdFlowInNoRestriction implements FwdFlowInInputSig { } - bindingset[arg, outercc] - pragma[inline_late] - private predicate viableImplArgNotCallContextReduced( - DataFlowCall call, ArgNodeEx arg, Cc outercc + pragma[nomagic] + private predicate fwdFlowIn( + ParamNodeEx p, ApApprox apa, FlowState state, CcCall innercc, Typ t, Ap ap ) { - call = arg.getCall() and - viableImplNotCallContextReducedInlineLate(call, outercc) + FwdFlowIn::fwdFlowIn(_, p, state, _, innercc, _, _, _, t, ap, apa) } pragma[nomagic] - private predicate fwdFlowIn( - DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc, - ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa + private DataFlowCallable viableImplCallContextReducedReverseRestricted( + DataFlowCall call, CcNoCall ctx ) { - exists(ArgNodeEx arg, boolean allowsFieldFlow, DataFlowCallable inner | - fwdFlow(arg, state, outercc, summaryCtx, argT, argAp, t, ap, apa) and - ( - inner = viableImplCallContextReducedInlineLate(call, arg, outercc) - or - viableImplArgNotCallContextReduced(call, arg, outercc) - ) and - flowIntoCallApaInlineLate(call, inner, arg, p, allowsFieldFlow, apa) - | - innercc = getCallContextCall(call, inner) and - if allowsFieldFlow = false then ap instanceof ApNil else any() - ) + result = viableImplCallContextReducedReverse(call, ctx) and + flowOutOfCallApa(call, result, _, _, _, _, _) } bindingset[ctx, result] @@ -1478,7 +1534,7 @@ module MakeImpl { private DataFlowCallable viableImplCallContextReducedReverseInlineLate( DataFlowCall call, CcNoCall ctx ) { - result = viableImplCallContextReducedReverse(call, ctx) + result = viableImplCallContextReducedReverseRestricted(call, ctx) } bindingset[call] @@ -1564,6 +1620,12 @@ module MakeImpl { innerArgApa) } + private module FwdFlowThroughRestriction implements FwdFlowInInputSig { + predicate callRestriction = PrevStage::callMayFlowThroughRev/1; + + predicate parameterRestriction = PrevStage::parameterMayFlowThrough/2; + } + /** * Holds if an argument to `call` is reached in the flow covered by `fwdFlow` * and data might flow through the target callable and back out at `call`. @@ -1573,12 +1635,8 @@ module MakeImpl { DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, ParamNodeEx p, Typ t, Ap ap ) { - exists(ApApprox apa | - fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argT, argAp, t, - ap, pragma[only_bind_into](apa)) and - PrevStage::parameterMayFlowThrough(p, apa) and - PrevStage::callMayFlowThroughRev(call) - ) + FwdFlowIn::fwdFlowIn(call, p, _, cc, innerCc, summaryCtx, argT, + argAp, t, ap, _) } pragma[nomagic] @@ -3720,6 +3778,26 @@ module MakeImpl { ) } + pragma[nomagic] + private DataFlowCallable prunedViableImplInCallContextCand(DataFlowCall call, CallContext cc) { + result = prunedViableImplInCallContext(call, cc) and + parameterCand(result, _, _) + } + + pragma[nomagic] + private DataFlowCallable viableCallableExtCand(DataFlowCall call) { + result = viableCallableExt(call) and + parameterCand(result, _, _) + } + + bindingset[call, cc] + private DataFlowCallable resolveCallCand(DataFlowCall call, CallContext cc) { + result = prunedViableImplInCallContextCand(call, cc) + or + noPrunedViableImplInCallContext(call, cc) and + result = viableCallableExtCand(call) + } + pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, FlowState state, @@ -3728,7 +3806,7 @@ module MakeImpl { exists(AccessPathApprox apa | pathIntoArg(mid, pragma[only_bind_into](pos), state, outercc, call, t, ap, pragma[only_bind_into](apa)) and - callable = resolveCall(call, outercc) and + callable = resolveCallCand(call, outercc) and parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa)) ) } diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll index 6fb53e04331a2..de6e06eae52e7 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll @@ -299,7 +299,7 @@ module MakeImplCommon { } } - private DataFlowCallable viableCallableExt(DataFlowCall call) { + DataFlowCallable viableCallableExt(DataFlowCall call) { result = viableCallable(call) or result = viableCallableLambda(call, _)