diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 919a32d8a4b..1c338d5a52d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -2417,6 +2417,19 @@ class ContentSet instanceof Content { } } +private signature class ParamSig; + +private module WithParam { + /** + * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`. + * + * The expression `e` is expected to be a syntactic part of the guard `g`. + * For example, the guard `g` might be a call `isSafe(x)` and the expression `e` + * the argument `x`. + */ + signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch, P param); +} + /** * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`. * @@ -2438,7 +2451,7 @@ private predicate controls(IRGuardCondition g, Node n, boolean edge) { * This is expected to be used in `isBarrier`/`isSanitizer` definitions * in data flow and taint tracking. */ -module BarrierGuard { +module ParameterizedBarrierGuard::guardChecksSig/4 guardChecks> { bindingset[value, n] pragma[inline_late] private predicate convertedExprHasValueNumber(ValueNumber value, Node n) { @@ -2448,12 +2461,13 @@ module BarrierGuard { ) } - private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) { - guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch) + private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) { + guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch, p) } /** - * Gets an expression node that is safely guarded by the given guard check. + * Gets an expression node that is safely guarded by the given guard check + * when the parameter is `p`. * * For example, given the following code: * ```cpp @@ -2484,19 +2498,27 @@ module BarrierGuard { * * NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead. */ - Node getABarrierNode() { + Node getABarrierNode(P p) { exists(IRGuardCondition g, ValueNumber value, boolean edge | convertedExprHasValueNumber(value, result) and guardChecks(g, - pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and + pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and controls(g, result, edge) ) or - result = SsaImpl::BarrierGuard::getABarrierNode() + result = SsaImpl::BarrierGuard::getABarrierNode(p) } /** - * Gets an indirect expression node that is safely guarded by the given guard check. + * Gets an expression node that is safely guarded by the given guard check. + * + * See `getABarrierNode/1` for examples. + */ + Node getABarrierNode() { result = getABarrierNode(_) } + + /** + * Gets an indirect expression node that is safely guarded by the given + * guard check with parameter `p`. * * For example, given the following code: * ```cpp @@ -2528,6 +2550,13 @@ module BarrierGuard { * * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. */ + Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) } + + /** + * Gets an indirect expression node that is safely guarded by the given guard check. + * + * See `getAnIndirectBarrierNode/1` for examples. + */ Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) } bindingset[value, n] @@ -2542,10 +2571,10 @@ module BarrierGuard { } private predicate guardChecksIndirectNode( - IRGuardCondition g, Node n, boolean branch, int indirectionIndex + IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p ) { guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(), - branch) + branch, p) } /** @@ -2582,19 +2611,44 @@ module BarrierGuard { * * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. */ - Node getAnIndirectBarrierNode(int indirectionIndex) { + Node getAnIndirectBarrierNode(int indirectionIndex, P p) { exists(IRGuardCondition g, ValueNumber value, boolean edge | indirectConvertedExprHasValueNumber(indirectionIndex, value, result) and guardChecks(g, - pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and + pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and controls(g, result, edge) ) or result = - SsaImpl::BarrierGuardWithIntParam::getABarrierNode(indirectionIndex) + SsaImpl::BarrierGuardWithIntParam::getABarrierNode(indirectionIndex, + p) } } +/** + * Provides a set of barrier nodes for a guard that validates an expression. + * + * This is expected to be used in `isBarrier`/`isSanitizer` definitions + * in data flow and taint tracking. + */ +module BarrierGuard { + private predicate guardChecks(IRGuardCondition g, Expr e, boolean branch, Unit unit) { + guardChecks(g, e, branch) and + exists(unit) + } + + import ParameterizedBarrierGuard +} + +private module InstrWithParam { + /** + * Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`. + */ + signature predicate instructionGuardChecksSig( + IRGuardCondition g, Instruction instr, boolean branch, P p + ); +} + /** * Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`. */ @@ -2606,7 +2660,9 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in * This is expected to be used in `isBarrier`/`isSanitizer` definitions * in data flow and taint tracking. */ -module InstructionBarrierGuard { +module ParameterizedInstructionBarrierGuard< + ParamSig P, InstrWithParam

::instructionGuardChecksSig/4 instructionGuardChecks> +{ bindingset[value, n] pragma[inline_late] private predicate operandHasValueNumber(ValueNumber value, Node n) { @@ -2616,21 +2672,27 @@ module InstructionBarrierGuard::getABarrierNode() + result = SsaImpl::BarrierGuard::getABarrierNode(p) } + /** Gets a node that is safely guarded by the given guard check. */ + Node getABarrierNode() { result = getABarrierNode(_) } + bindingset[value, n] pragma[inline_late] private predicate indirectOperandHasValueNumber(ValueNumber value, int indirectionIndex, Node n) { @@ -2641,25 +2703,52 @@ module InstructionBarrierGuard::getABarrierNode(indirectionIndex) + SsaImpl::BarrierGuardWithIntParam::getABarrierNode(indirectionIndex, + p) } + + /** + * Gets an indirect node that is safely guarded by the given guard check + * with parameter `p`. + */ + Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) } + + /** Gets an indirect node that is safely guarded by the given guard check. */ + Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) } +} + +/** + * Provides a set of barrier nodes for a guard that validates an instruction. + * + * This is expected to be used in `isBarrier`/`isSanitizer` definitions + * in data flow and taint tracking. + */ +module InstructionBarrierGuard { + private predicate instructionGuardChecks( + IRGuardCondition g, Instruction i, boolean branch, Unit unit + ) { + instructionGuardChecks(g, i, branch) and + exists(unit) + } + + import ParameterizedInstructionBarrierGuard } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll index 99f13a81725..d4a80ff25c8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll @@ -1035,13 +1035,23 @@ class SynthNode extends DataFlowIntegrationImpl::SsaNode { SynthNode() { not this.asDefinition() instanceof SsaImpl::WriteDefinition } } -signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean branch); +private signature class ParamSig; -signature predicate guardChecksNodeSig( - IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex -); +private module ParamIntPair { + newtype TPair = MkPair(P p, int indirectionIndex) { nodeHasInstruction(_, _, indirectionIndex) } +} -module BarrierGuardWithIntParam { +private module WithParam { + signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean gv, P param); +} + +private module IntWithParam { + signature predicate guardChecksNodeSig( + IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P param + ); +} + +module BarrierGuardWithIntParam::guardChecksNodeSig/5 guardChecksNode> { private predicate ssaDefReachesCertainUse(Definition def, UseImpl use) { exists(SourceVariable v, IRBlock bb, int i | use.hasIndexInBlock(bb, i, v) and @@ -1052,21 +1062,23 @@ module BarrierGuardWithIntParam { private predicate guardChecksInstr( IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv, - int indirectionIndex + ParamIntPair

::TPair pair ) { - exists(Node node | + exists(Node node, int indirectionIndex, P p | + pair = ParamIntPair

::MkPair(p, indirectionIndex) and nodeHasInstruction(node, instr, indirectionIndex) and - guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex) + guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex, p) ) } private predicate guardChecksWithWrappers( DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val, - int indirectionIndex + ParamIntPair

::MkPair pair ) { - exists(Instruction e | - IRGuards::Guards_v1::ParameterizedValidationWrapper::guardChecks(g, - e, val, indirectionIndex) + exists(Instruction e, int indirectionIndex | + IRGuards::Guards_v1::ParameterizedValidationWrapper::TPair, guardChecksInstr/4>::guardChecks(g, + e, val, pair) and + pair = ParamIntPair

::MkPair(_, indirectionIndex) | indirectionIndex = 0 and def.(Definition).getAUse().getDef() = e @@ -1075,18 +1087,19 @@ module BarrierGuardWithIntParam { ) } - Node getABarrierNode(int indirectionIndex) { + Node getABarrierNode(int indirectionIndex, P p) { // Only get the SynthNodes from the shared implementation, as the ExprNodes cannot // be matched on SourceVariable. result.(SsaSynthNode).getSynthNode() = - DataFlowIntegrationImpl::BarrierGuardDefWithState::getABarrierNode(indirectionIndex) + DataFlowIntegrationImpl::BarrierGuardDefWithState::MkPair, guardChecksWithWrappers/4>::getABarrierNode(ParamIntPair

::MkPair(p, + indirectionIndex)) or // Calculate the guarded UseImpls corresponding to ExprNodes directly. exists( DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb | - guardChecksWithWrappers(g, def, branch, indirectionIndex) and exists(UseImpl use | + guardChecksWithWrappers(g, def, branch, ParamIntPair

::MkPair(p, indirectionIndex)) and ssaDefReachesCertainUse(def, use) and use.getBlock() = bb and DataFlowIntegrationInput::guardControlsBlock(g, bb, branch) and @@ -1096,15 +1109,16 @@ module BarrierGuardWithIntParam { } } -module BarrierGuard { +module BarrierGuard::guardChecksNodeSig/4 guardChecksNode> { private predicate guardChecksNode( - IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex + IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P p ) { - guardChecksNode(g, e, branch) and indirectionIndex = 0 + indirectionIndex = 0 and + guardChecksNode(g, e, gv, p) } - Node getABarrierNode() { - result = BarrierGuardWithIntParam::getABarrierNode(0) + Node getABarrierNode(P p) { + result = BarrierGuardWithIntParam::getABarrierNode(0, p) } }