Rust: move model generator to new format

This commit is contained in:
Paolo Tranquilli
2025-06-19 12:57:40 +02:00
parent 261c129555
commit 79fd10d31f
2 changed files with 37 additions and 32 deletions

View File

@@ -1,6 +1,7 @@
strategy: dca strategy: dca
language: rust language: rust
destination: rust/ql/lib/ext/generated destination: rust/ql/lib/ext/generated
single-file: true # dump models into a single file per crate (we do not have proper namespaces)
# targets must have name specified and corresponding to the name in the DCA suite # targets must have name specified and corresponding to the name in the DCA suite
# they can optionally specify any of # they can optionally specify any of
# with-sinks: false # with-sinks: false

View File

@@ -11,26 +11,32 @@ private import codeql.rust.dataflow.internal.TaintTrackingImpl
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary
private predicate relevant(Function api) { private newtype TCallable =
// Only include functions that have a resolved path. TFunction(Function api, string path) {
api.hasCrateOrigin() and path = api.getCanonicalPath() and
api.hasExtendedCanonicalPath() and (
// A canonical path can contain `;` as the syntax for array types use `;`. For // This excludes closures (these are not exported API endpoints) and
// instance `<[Foo; 1] as Bar>::baz`. This does not work with the shared model // functions without a `pub` visibility. A function can be `pub` without
// generator and it is not clear if this will also be the case when we move to // ultimately being exported by a crate, so this is an overapproximation.
// QL created canoonical paths, so for now we just exclude functions with api.hasVisibility()
// `;`s. or
not exists(api.getExtendedCanonicalPath().indexOf(";")) and // If a method implements a public trait it is exposed through the trait.
( // We overapproximate this by including all trait method implementations.
// This excludes closures (these are not exported API endpoints) and exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api)
// functions without a `pub` visibility. A function can be `pub` without )
// ultimately being exported by a crate, so this is an overapproximation. }
api.hasVisibility()
or private class QualifiedCallable extends TCallable {
// If a method implements a public trait it is exposed through the trait. Function api;
// We overapproximate this by including all trait method implementations. string path;
exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api)
) QualifiedCallable() { this = TFunction(api, path) }
string toString() { result = path }
Function asFunction() { result = api }
string getCanonicalPath() { result = path }
} }
module ModelGeneratorCommonInput implements module ModelGeneratorCommonInput implements
@@ -41,14 +47,14 @@ module ModelGeneratorCommonInput implements
class Parameter = R::ParamBase; class Parameter = R::ParamBase;
class Callable = R::Callable; class Callable = QualifiedCallable;
class NodeExtended extends DataFlow::Node { class NodeExtended extends DataFlow::Node {
Type getType() { any() } Type getType() { any() }
} }
Callable getEnclosingCallable(NodeExtended node) { QualifiedCallable getEnclosingCallable(NodeExtended node) {
result = node.(Node::Node).getEnclosingCallable().asCfgScope() result.asFunction() = node.(Node::Node).getEnclosingCallable().asCfgScope()
} }
predicate isRelevantType(Type t) { any() } predicate isRelevantType(Type t) { any() }
@@ -73,19 +79,19 @@ module ModelGeneratorCommonInput implements
} }
bindingset[c] bindingset[c]
string paramReturnNodeAsApproximateOutput(Callable c, DataFlowImpl::ParameterPosition pos) { string paramReturnNodeAsApproximateOutput(QualifiedCallable c, DataFlowImpl::ParameterPosition pos) {
result = paramReturnNodeAsExactOutput(c, pos) result = paramReturnNodeAsExactOutput(c, pos)
} }
bindingset[c] bindingset[c]
string paramReturnNodeAsExactOutput(Callable c, DataFlowImpl::ParameterPosition pos) { string paramReturnNodeAsExactOutput(QualifiedCallable c, DataFlowImpl::ParameterPosition pos) {
result = parameterExactAccess(c.getParam(pos.getPosition())) result = parameterExactAccess(c.asFunction().getParam(pos.getPosition()))
or or
pos.isSelf() and result = qualifierString() pos.isSelf() and result = qualifierString()
} }
Callable returnNodeEnclosingCallable(DataFlow::Node ret) { QualifiedCallable returnNodeEnclosingCallable(DataFlow::Node ret) {
result = ret.(Node::Node).getEnclosingCallable().asCfgScope() result.asFunction() = ret.(Node::Node).getEnclosingCallable().asCfgScope()
} }
predicate isOwnInstanceAccessNode(DataFlowImpl::RustDataFlow::ReturnNode node) { predicate isOwnInstanceAccessNode(DataFlowImpl::RustDataFlow::ReturnNode node) {
@@ -99,10 +105,8 @@ module ModelGeneratorCommonInput implements
c.(SingletonContentSet).getContent() instanceof ElementContent c.(SingletonContentSet).getContent() instanceof ElementContent
} }
string partialModelRow(Callable api, int i) { string partialModelRow(QualifiedCallable api, int i) {
i = 0 and result = api.(Function).getCrateOrigin() // crate i = 0 and result = min(string path | path = api.(Function).getCanonicalPath() | path)
or
i = 1 and result = api.(Function).getExtendedCanonicalPath() // name
} }
string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) } string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) }