Skip to content

Conversation

paldepind
Copy link
Contributor

@paldepind paldepind commented Sep 17, 2025

This PR adds support for MaD sources with an Argument[_].Parameter[_] access path. This corresponds to sources that pass tainted data to a callback/function.

The implementation is my interpretation of a comment on Slack by @hvitved. My understanding is that this is not necessarily the long-term ideal way to implement this, but it is a quick way to give us something that works and that lets us write the models that we want to write for Rust.

The DCA report looks good. Taint reach triples on rust-vulnerable-apps which makes sense as it uses Warp for which we now have working models.

@github-actions github-actions bot added Rust Pull requests that update Rust code DataFlow Library labels Sep 17, 2025
Copy link
Contributor

@geoffw0 geoffw0 left a comment

Choose a reason for hiding this comment

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

Results look great!

I'd like to see a DCA run when this comes out of draft.

exists(ArgumentPosition pos, Expr arg |
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
arg = getSourceNodeArgument(source, s.tail().head()) and
result.asParameter() = getCallable(arg).getParam(pos.getPosition())
Copy link
Contributor

Choose a reason for hiding this comment

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

So if I'm understanding correctly, this is pretty specific to the pattern .Argument[x].Parameter[y]. Could we plausibly want to support other flow path variants like (without having thought too hard about whether these examples in particular make sense) .Argument[x].Reference.Parameter[y], .Argument[x].Parameter[y].Parameter[z] or .ReturnValue.Parameter[x] or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, Parameter is only supported right after Argument. It seems plausible that other combinations could make sense, though it's not immediately clear to me what they would be.

I think it would make sense to be on the lookout for other sensible things, but I don't think we should generalize the current implementation right now.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, something to keep an eye on then.

@paldepind paldepind force-pushed the rust/mad-source-parameter branch from e6bd0ed to c83a9f9 Compare September 18, 2025 13:46
@paldepind paldepind force-pushed the rust/mad-source-parameter branch from bb712f0 to 99e88c5 Compare September 19, 2025 06:29
@paldepind paldepind marked this pull request as ready for review September 19, 2025 07:12
@paldepind paldepind requested review from a team as code owners September 19, 2025 07:12
@Copilot Copilot AI review requested due to automatic review settings September 19, 2025 07:12
@paldepind paldepind requested a review from a team as a code owner September 19, 2025 07:12
@paldepind paldepind requested review from a team as code owners September 19, 2025 07:12
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for MaD (Model-as-Data) sources with Argument[_].Parameter[_] access paths in Rust. This enables modeling of sources that pass tainted data to callbacks or function parameters.

Key changes:

  • Updated the shared dataflow framework to support Parameter components in source access paths
  • Modified flow summary implementations across multiple languages to use SummaryComponentStack instead of SummaryComponent
  • Added jump steps for sources that cross callable boundaries

Reviewed Changes

Copilot reviewed 20 out of 22 changed files in this pull request and generated no comments.

Show a summary per file
File Description
shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll Core implementation supporting Parameter in source models with jump steps
rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll Rust-specific implementation for handling callback parameter sources
rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll Integration of source jump steps in Rust dataflow
rust/ql/test/library-tests/dataflow/models/models.ext.yml Added test model for pass_source function
Multiple language-specific files Updated signatures to use SummaryComponentStack

DataFlowCall getACall(SummarizedCallable sc);

/** Gets the enclosing callable of `source`. */
DataFlowCallable getSourceNodeEnclosingCallable(SourceBase source);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to know wether the node returned by getSourceNode is in the same callable as SourceBase, and I don't think we can get that information without adding a new predicate.

Copy link
Contributor

@hvitved hvitved left a comment

Choose a reason for hiding this comment

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

Nice!

---
* The models-as-data format for sources now supports access paths of the form
`Argument[i].Parameter[j]`. This denotes that the source passes tainted data to
the `j`th parameter of it's `i`th argument (which must be a function or a
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: its


/** Get the callable that `expr` refers to. */
private Callable getCallable(Expr expr) {
result = resolvePath(expr.(PathExpr).getPath()).(Function)
Copy link
Contributor

Choose a reason for hiding this comment

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

I wasn't aware this was possible in Rust; we don't currently handle it in normal data flow.

arg = pos.getArgument(call)
exists(ArgumentPosition pos, Expr arg |
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
arg = getSourceNodeArgument(source, s.tail().head()) and
Copy link
Contributor

Choose a reason for hiding this comment

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

We should check that s.tail() is a singleton.

)
or
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() =
getSourceNodeArgument(source, s.head())
Copy link
Contributor

Choose a reason for hiding this comment

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

We should check that s is a singleton.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants