diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index b24a104d388..2da4ec7f71e 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -109,6 +109,16 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon } } +private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) { + exists(Expr e | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, e, cfn) | + e.(OperatorCall).getTarget() instanceof ImplicitConversionOperator // Should only be implicit operator calls. + ) +} + +private ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) { + result = getALastEvalNode(e) +} + private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo) } @@ -177,6 +187,16 @@ private module Cached { readStep(nodeFrom, any(DataFlow::ContentSet c | c.isElement()), nodeTo) or nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) + or + // Allow reverse update flow for implicit conversion operator calls. + // This is needed to support flow out of method call arguments, where an implicit conversion is applied + // to a call argument. + nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() = + getPostUpdateReverseStep(nodeFrom + .(PostUpdateNode) + .getPreUpdateNode() + .(DataFlow::ExprNode) + .getControlFlowNode()) ) and model = "" or