-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Initial model generation setup #18628
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
Changes from all commits
f76647f
0a9b864
fc15c0d
0741331
cf4f657
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,21 @@ | ||
| private import rust as R | ||
| private import codeql.mad.test.InlineMadTest | ||
|
|
||
| private module InlineMadTestLang implements InlineMadTestLangSig { | ||
| class Callable = R::Function; | ||
|
|
||
| string getComment(R::Function callable) { | ||
| exists(R::Comment comment | | ||
| result = comment.getCommentText() and | ||
| comment.getLocation().getFile() = callable.getLocation().getFile() and | ||
| // When a function is preceded by comments its start line is the line of | ||
| // the first comment. Hence all relevant comments are found by including | ||
| // comments from the start line and up to the line with the function | ||
| // name. | ||
| callable.getLocation().getStartLine() <= comment.getLocation().getStartLine() and | ||
| comment.getLocation().getStartLine() <= callable.getName().getLocation().getStartLine() | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| import InlineMadTestImpl<InlineMadTestLang> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
| * @name Capture content based summary models. | ||
| * @description Finds applicable content based summary models to be used by other queries. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/contentbased-summary-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSummaryTargetApi api, string flow | ||
| where flow = ContentSensitive::captureFlow(api, _) | ||
| select flow order by flow |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
| * @name Capture mixed neutral models. | ||
| * @description Finds neutral models to be used by other queries. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/mixed-neutral-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSummaryTargetApi api, string noflow | ||
| where noflow = captureMixedNeutral(api) | ||
| select noflow order by noflow |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
|
Contributor
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'm not sure we'll want this query, I hope that
Contributor
Author
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 don't have strong feelings but I'd be inclined to leave the files in places because: |
||
| * @name Capture mixed summary models. | ||
| * @description Finds applicable summary models to be used by other queries. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/mixed-summary-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSummaryTargetApi api, string flow | ||
| where flow = captureMixedFlow(api, _) | ||
| select flow order by flow | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
| * @name Capture neutral models. | ||
| * @description Finds neutral models to be used by other queries. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/neutral-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSummaryTargetApi api, string noflow | ||
| where noflow = captureNoFlow(api) | ||
| select noflow order by noflow |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
| * @name Capture sink models. | ||
| * @description Finds public methods that act as sinks as they flow into a known sink. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/sink-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSinkTargetApi api, string sink | ||
| where sink = captureSink(api) | ||
| select sink order by sink |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
| * @name Capture source models. | ||
| * @description Finds APIs that act as sources as they expose already known sources. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/source-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSourceTargetApi api, string source | ||
| where source = captureSource(api) | ||
| select source order by source |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
|
Contributor
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. Same comment. |
||
| * @name Capture summary models. | ||
| * @description Finds applicable summary models to be used by other queries. | ||
| * @kind diagnostic | ||
| * @id rust/utils/modelgenerator/summary-models | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| import internal.CaptureModels | ||
|
|
||
| from DataFlowSummaryTargetApi api, string flow | ||
| where flow = captureFlow(api) | ||
| select flow order by flow | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #!/usr/bin/python3 | ||
|
|
||
| import sys | ||
| import os.path | ||
| import subprocess | ||
|
|
||
| # Add Model as Data script directory to sys.path. | ||
| gitroot = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip() | ||
| madpath = os.path.join(gitroot, "misc/scripts/models-as-data/") | ||
| sys.path.append(madpath) | ||
|
|
||
| import generate_flow_model as model | ||
|
|
||
| language = "rust" | ||
| model.Generator.make(language).run() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /** | ||
| * @name Capture Summary Models Partial Path | ||
| * @description Capture Summary Models Partial Path | ||
| * @kind path-problem | ||
| * @precision low | ||
| * @id rust/utils/modelgenerator/summary-models-partial-path | ||
| * @severity info | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| private import codeql.rust.dataflow.DataFlow | ||
| import utils.modelgenerator.internal.CaptureModels | ||
| import PartialFlow::PartialPathGraph | ||
|
|
||
| int explorationLimit() { result = 3 } | ||
|
|
||
| module PartialFlow = PropagateFlow::FlowExplorationFwd<explorationLimit/0>; | ||
|
|
||
| from | ||
| PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink, | ||
| DataFlowSummaryTargetApi api, DataFlow::ParameterNode p | ||
| where | ||
| PartialFlow::partialFlow(source, sink, _) and | ||
| p = source.getNode() and | ||
| p.asParameter() = api.getParamList().getAParamBase() | ||
| select sink.getNode(), source, sink, "There is flow from a $@ to $@.", source.getNode(), | ||
| "parameter", sink.getNode(), "intermediate value" | ||
Check warningCode scanning / CodeQL Alert message style violation Warning
Don't repeat the alert location as a link.
Contributor
Author
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. These are debug queries copy pasted from C#, so I'm inclined to ignore this?
Contributor
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 wouldn't worry about this too much, assuming we're not expecting users to use these queries directly. We might want to make it clearer what these queries are for though (e.g. in the |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| /** | ||
| * @name Capture Summary Models Path | ||
| * @description Capture Summary Models Path | ||
| * @kind path-problem | ||
| * @precision low | ||
| * @id rust/utils/modelgenerator/summary-models-path | ||
| * @severity warning | ||
| * @tags modelgenerator | ||
| */ | ||
|
|
||
| private import codeql.rust.dataflow.DataFlow | ||
| import utils.modelgenerator.internal.CaptureModels | ||
| import PropagateFlow::PathGraph | ||
|
|
||
| from | ||
| PropagateFlow::PathNode source, PropagateFlow::PathNode sink, DataFlowSummaryTargetApi api, | ||
| DataFlow::Node p, DataFlow::Node returnNodeExt | ||
| where | ||
| PropagateFlow::flowPath(source, sink) and | ||
| p = source.getNode() and | ||
| returnNodeExt = sink.getNode() and | ||
| exists(captureThroughFlow0(api, p, returnNodeExt)) | ||
| select sink.getNode(), source, sink, "There is flow from $@ to the $@.", source.getNode(), | ||
| "parameter", sink.getNode(), "return value" | ||
Check warningCode scanning / CodeQL Alert message style violation Warning
Don't repeat the alert location as a link.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| The queries in this directory are purely used for model generator debugging purposes in VS Code. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| private import codeql.util.Unit | ||
| private import rust | ||
| private import rust as R | ||
| private import codeql.rust.dataflow.DataFlow | ||
| private import codeql.rust.dataflow.internal.DataFlowImpl | ||
| private import codeql.rust.dataflow.internal.TaintTrackingImpl | ||
| private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl | ||
| private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary | ||
|
|
||
| module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataFlow> { | ||
| // NOTE: We are not using type information for now. | ||
| class Type = Unit; | ||
|
|
||
| class Parameter = R::ParamBase; | ||
|
|
||
| class Callable = R::Callable; | ||
|
|
||
| class NodeExtended extends DataFlow::Node { | ||
| Callable getAsExprEnclosingCallable() { result = this.asExpr().getScope() } | ||
|
|
||
| Type getType() { any() } | ||
|
|
||
| Callable getEnclosingCallable() { | ||
| result = this.(Node::Node).getEnclosingCallable().asCfgScope() | ||
| } | ||
| } | ||
|
|
||
| private predicate relevant(Function api) { | ||
| // This excludes closures (these are not exported API endpoints) and | ||
| // functions without a `pub` visiblity. A function can be `pub` without | ||
| // ultimately being exported by a crate, so this is an overapproximation. | ||
| api.hasVisibility() | ||
| or | ||
| // If a method implements a public trait it is exposed through the trait. | ||
| // We overapproximate this by including all trait method implementations. | ||
| exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api) | ||
| } | ||
|
|
||
| predicate isUninterestingForDataFlowModels(Callable api) { none() } | ||
|
|
||
| predicate isUninterestingForHeuristicDataFlowModels(Callable api) { none() } | ||
|
|
||
| class SourceOrSinkTargetApi extends Callable { | ||
| SourceOrSinkTargetApi() { relevant(this) } | ||
| } | ||
|
|
||
| class SinkTargetApi extends SourceOrSinkTargetApi { } | ||
|
|
||
| class SourceTargetApi extends SourceOrSinkTargetApi { } | ||
|
|
||
| class SummaryTargetApi extends Callable { | ||
| private Callable lift; | ||
|
|
||
| SummaryTargetApi() { | ||
| lift = this and | ||
| relevant(this) | ||
| } | ||
|
|
||
| Callable lift() { result = lift } | ||
|
|
||
| predicate isRelevant() { relevant(this) } | ||
| } | ||
|
|
||
| predicate isRelevantType(Type t) { any() } | ||
|
|
||
| /** | ||
| * Gets the underlying type of the content `c`. | ||
| */ | ||
| Type getUnderlyingContentType(DataFlow::ContentSet c) { result = any(Type t) and exists(c) } | ||
Check warningCode scanning / CodeQL Redundant cast Warning
Redundant cast to
Unit Error loading related location Loading |
||
|
|
||
| string qualifierString() { result = "Argument[self]" } | ||
|
|
||
| string parameterAccess(R::ParamBase p) { | ||
| result = "Argument[" + any(ParameterPosition pos | p = pos.getParameterIn(_)).toString() + "]" | ||
| } | ||
|
|
||
| string parameterContentAccess(R::ParamBase p) { result = parameterAccess(p) } | ||
|
|
||
| class InstanceParameterNode extends DataFlow::ParameterNode { | ||
| InstanceParameterNode() { this.asParameter() instanceof SelfParam } | ||
| } | ||
|
|
||
| bindingset[c] | ||
| string paramReturnNodeAsOutput(R::Callable c, ParameterPosition pos) { | ||
| // TODO: Implement this to support returning through parameters. | ||
| result = "paramReturnNodeAsOutput(" + c + ", " + pos + ")" | ||
| } | ||
|
|
||
| bindingset[c] | ||
| string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) { | ||
| // TODO: Implement this to support returning through parameters. | ||
| result = "paramReturnNodeAsContentOutput(" + c + ", " + pos + ")" | ||
| } | ||
|
|
||
| Callable returnNodeEnclosingCallable(DataFlow::Node ret) { | ||
| result = ret.(Node::Node).getEnclosingCallable().asCfgScope() | ||
| } | ||
|
|
||
| predicate isOwnInstanceAccessNode(RustDataFlow::ReturnNode node) { | ||
| // This is probably not relevant to implement for Rust, as we only use | ||
| // `captureMixedFlow` which doesn't explicitly distinguish between | ||
| // functions that return `self` and those that don't. | ||
| none() | ||
| } | ||
|
|
||
| predicate sinkModelSanitizer(DataFlow::Node node) { none() } | ||
|
|
||
| predicate apiSource(DataFlow::Node source) { none() } | ||
|
|
||
| bindingset[sourceEnclosing, api] | ||
| predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) { none() } | ||
|
|
||
| string getInputArgument(DataFlow::Node source) { | ||
| // TODO: Implement when we want to generate sources and sinks | ||
| result = "getInputArgument(" + source + ")" | ||
| } | ||
|
|
||
| bindingset[kind] | ||
| predicate isRelevantSinkKind(string kind) { any() } | ||
|
|
||
| bindingset[kind] | ||
| predicate isRelevantSourceKind(string kind) { any() } | ||
|
|
||
| predicate containerContent(DataFlow::ContentSet c) { | ||
| c.(SingletonContentSet).getContent() instanceof ElementContent | ||
| } | ||
|
|
||
| predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() } | ||
|
|
||
| predicate isField(DataFlow::ContentSet c) { | ||
| c.(SingletonContentSet).getContent() instanceof StructFieldContent | ||
| } | ||
|
|
||
| predicate isCallback(DataFlow::ContentSet c) { none() } | ||
|
|
||
| string getSyntheticName(DataFlow::ContentSet c) { none() } | ||
|
|
||
| string printContent(DataFlow::ContentSet cs) { | ||
| exists(string arg | result = FlowSummary::Input::encodeContent(cs, arg) + "[" + arg + "]") | ||
| } | ||
|
|
||
| string partialModelRow(Callable api, int i) { | ||
| i = 0 and | ||
| ( | ||
| result = api.(Function).getCrateOrigin() | ||
| or | ||
| not api.(Function).hasCrateOrigin() and result = "" | ||
| ) // crate | ||
| or | ||
| i = 1 and result = api.(Function).getExtendedCanonicalPath() // name | ||
| } | ||
|
|
||
| string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) } | ||
|
|
||
| // TODO: Implement this when we want to generate sources. | ||
| predicate sourceNode(DataFlow::Node node, string kind) { none() } | ||
|
|
||
| // TODO: Implement this when we want to generate sinks. | ||
| predicate sinkNode(DataFlow::Node node, string kind) { none() } | ||
| } | ||
|
|
||
| import MakeModelGenerator<Location, RustDataFlow, RustTaintTracking, ModelGeneratorInput> | ||
Uh oh!
There was an error while loading. Please reload this page.