-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust, shared: Support Parameter
in source MaD models
#20452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
def1bcf
de9d102
44472c3
6b5d6bd
92c0739
99e88c5
25c14ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
category: feature | ||
--- | ||
* 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 | ||
closure). |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,10 @@ private import rust | |
private import codeql.dataflow.internal.FlowSummaryImpl | ||
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath | ||
private import codeql.rust.dataflow.internal.DataFlowImpl | ||
private import codeql.rust.internal.PathResolution | ||
private import codeql.rust.dataflow.FlowSummary | ||
private import codeql.rust.dataflow.Ssa | ||
private import codeql.rust.controlflow.CfgNodes | ||
private import Content | ||
|
||
module Input implements InputSig<Location, RustDataFlow> { | ||
|
@@ -133,16 +136,44 @@ private module StepsInput implements Impl::Private::StepsInputSig { | |
result.asCallCfgNode().getCall().getStaticTarget() = sc | ||
} | ||
|
||
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { | ||
sc = Impl::Private::SummaryComponent::return(_) and | ||
/** Gets the argument of `source` described by `sc`, if any. */ | ||
private Expr getSourceNodeArgument(Input::SourceBase source, Impl::Private::SummaryComponent sc) { | ||
exists(ArgumentPosition pos | | ||
sc = Impl::Private::SummaryComponent::argument(pos) and | ||
result = pos.getArgument(source.getCall()) | ||
) | ||
} | ||
|
||
/** Get the callable that `expr` refers to. */ | ||
private Callable getCallable(Expr expr) { | ||
result = resolvePath(expr.(PathExpr).getPath()).(Function) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
or | ||
result = expr.(ClosureExpr) | ||
or | ||
// The expression is an SSA read of an assignment of a closure | ||
exists(Ssa::Definition def, ExprCfgNode value | | ||
def.getARead().getAstNode() = expr and | ||
def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(value) and | ||
result = value.getExpr().(ClosureExpr) | ||
) | ||
} | ||
|
||
RustDataFlow::DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { | ||
result.asCfgScope() = source.getEnclosingCfgScope() | ||
} | ||
|
||
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { | ||
s.head() = Impl::Private::SummaryComponent::return(_) and | ||
result.asExpr().getExpr() = source.getCall() | ||
or | ||
exists(CallExprBase call, Expr arg, ArgumentPosition pos | | ||
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() = arg and | ||
sc = Impl::Private::SummaryComponent::argument(pos) and | ||
call = source.getCall() and | ||
arg = pos.getArgument(call) | ||
exists(ArgumentPosition pos, Expr arg | | ||
s.head() = Impl::Private::SummaryComponent::parameter(pos) and | ||
arg = getSourceNodeArgument(source, s.tail().head()) and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should check that |
||
result.asParameter() = getCallable(arg).getParam(pos.getPosition()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, something to keep an eye on then. |
||
) | ||
or | ||
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() = | ||
getSourceNodeArgument(source, s.head()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should check that |
||
} | ||
|
||
RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
multipleCallTargets | ||
| main.rs:362:14:362:30 | ... .lt(...) | | ||
| main.rs:389:14:389:30 | ... .lt(...) | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
its