Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added reverse taint flow from implicit conversion operator calls to their arguments.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
}
}

private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) {
exists(OperatorCall oc | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, oc, cfn) |
oc.getTarget() instanceof ImplicitConversionOperator
)
}

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)
}
Expand Down Expand Up @@ -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.
Comment on lines +191 to +193
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new comment says "reverse update flow" but this predicate is adding a default taint step. Consider rewording to "reverse taint flow" (and/or explicitly mentioning post-update nodes) to avoid confusion with the data-flow reverse-step logic in DataFlowPrivate.

Suggested change
// 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.
// Allow reverse taint flow between post-update and pre-update nodes for implicit conversion operator calls.
// This is needed to support taint flow out of method call arguments where an implicit conversion is applied
// to the argument expression.

Copilot uses AI. Check for mistakes.
nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() =
getPostUpdateReverseStep(nodeFrom
.(PostUpdateNode)
.getPreUpdateNode()
.(DataFlow::ExprNode)
.getControlFlowNode())
) and
model = ""
or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

public class TestImplicitConversionOperator
{
static void Sink(object o) { }
static void TaintArgument(ArraySegment<byte> segment) { }

public void M1()
{
byte[] bytes = new byte[1];
TaintArgument(bytes);
Sink(bytes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
edges
| ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | provenance | |
nodes
| ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | semmle.label | [post] call to operator implicit conversion : ArraySegment<Byte> |
| ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | semmle.label | access to local variable bytes |
subpaths
#select
| ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | ImplicitConversionOperator.cs:12:14:12:18 | access to local variable bytes | $@ | ImplicitConversionOperator.cs:11:23:11:27 | [post] call to operator implicit conversion : ArraySegment<Byte> | [post] call to operator implicit conversion : ArraySegment<Byte> |
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @kind path-problem
*/

import csharp
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
import Taint::PathGraph

module TaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
exists(MethodCall mc |
mc.getTarget().hasName("TaintArgument") and
mc.getAnArgument() = src.(DataFlowPrivate::PostUpdateNode).getPreUpdateNode().asExpr()
)
}

predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getTarget().hasName("Sink") and
mc.getAnArgument() = sink.asExpr()
)
}
}

module Taint = TaintTracking::Global<TaintConfig>;

from Taint::PathNode source, Taint::PathNode sink
where Taint::flowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()