Rust: Disable dynamic dispatch when generating models

This commit is contained in:
Simon Friis Vindum
2026-01-07 13:51:42 +01:00
parent 1fbf0387f5
commit 862adec081
3 changed files with 51 additions and 24 deletions

View File

@@ -306,7 +306,11 @@ predicate indexAssignment(
not index.getResolvedTarget().fromSource()
}
module RustDataFlow implements InputSig<Location> {
signature module RustDataFlowInputSig {
predicate includeDynamicTargets();
}
module RustDataFlowGen<RustDataFlowInputSig Input> implements InputSig<Location> {
private import Aliases
private import codeql.rust.dataflow.DataFlow
private import Node as Node
@@ -462,7 +466,11 @@ module RustDataFlow implements InputSig<Location> {
/** Gets a viable implementation of the target of the given `Call`. */
DataFlowCallable viableCallable(DataFlowCall call) {
exists(Call c | c = call.asCall() |
result.asCfgScope() = c.getARuntimeTarget()
(
if Input::includeDynamicTargets()
then result.asCfgScope() = c.getARuntimeTarget()
else result.asCfgScope() = c.getStaticTarget()
)
or
result.asSummarizedCallable() = getStaticTargetExt(c)
)
@@ -935,6 +943,12 @@ module RustDataFlow implements InputSig<Location> {
class DataFlowSecondLevelScope = Void;
}
module RustDataFlowInput implements RustDataFlowInputSig {
predicate includeDynamicTargets() { any() }
}
module RustDataFlow = RustDataFlowGen<RustDataFlowInput>;
/** Provides logic related to captured variables. */
module VariableCapture {
private import codeql.rust.internal.CachedStages
@@ -1110,7 +1124,7 @@ private module Cached {
}
cached
newtype TParameterPosition =
newtype TParameterPositionImpl =
TPositionalParameterPosition(int i) {
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
or
@@ -1121,6 +1135,8 @@ private module Cached {
TClosureSelfParameterPosition() or
TSelfParameterPosition()
final class TParameterPosition = TParameterPositionImpl;
cached
newtype TReturnKind = TNormalReturnKind()

View File

@@ -1,8 +1,9 @@
private import rust
private import codeql.dataflow.DataFlow as DF
private import codeql.dataflow.TaintTracking
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.DataFlow as RustDataFlow
private import codeql.rust.dataflow.FlowSummary
private import DataFlowImpl
private import DataFlowImpl as DataFlowImpl
private import Node as Node
private import Content
private import FlowSummaryImpl as FlowSummaryImpl
@@ -29,7 +30,11 @@ private predicate excludedTaintStepContent(Content c) {
)
}
module RustTaintTracking implements InputSig<Location, RustDataFlow> {
module RustTaintTrackingGen<DataFlowImpl::RustDataFlowInputSig I> implements
InputSig<Location, DataFlowImpl::RustDataFlowGen<I>>
{
private module DataFlow = DataFlowImpl::RustDataFlowGen<I>;
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
@@ -53,7 +58,7 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
// is tainted and an operation reads from `foo` (e.g., `foo.bar`) then
// taint is propagated.
exists(ContentSet cs |
RustDataFlow::readStep(pred, cs, succ) and
DataFlow::readStep(pred, cs, succ) and
not excludedTaintStepContent(cs.getAReadContent())
)
or
@@ -70,9 +75,11 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
)
or
succ.(Node::PostUpdateNode).getPreUpdateNode().asExpr() =
getPostUpdateReverseStep(pred.(Node::PostUpdateNode).getPreUpdateNode().asExpr(), false)
DataFlowImpl::getPostUpdateReverseStep(pred.(Node::PostUpdateNode)
.getPreUpdateNode()
.asExpr(), false)
or
indexAssignment(any(CompoundAssignmentExpr cae),
DataFlowImpl::indexAssignment(any(CompoundAssignmentExpr cae),
pred.(Node::PostUpdateNode).getPreUpdateNode().asExpr(), _, succ, _)
)
or
@@ -92,7 +99,7 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
c instanceof ReferenceContent
) and
// Optional steps are added through isAdditionalFlowStep but we don't want the implicit reads
not optionalStep(node, _, _)
not DataFlowImpl::optionalStep(node, _, _)
}
/**
@@ -101,3 +108,5 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
*/
predicate speculativeTaintStep(DataFlow::Node src, DataFlow::Node sink) { none() }
}
module RustTaintTracking = RustTaintTrackingGen<DataFlowImpl::RustDataFlowInput>;

View File

@@ -7,6 +7,7 @@ private import codeql.rust.dataflow.internal.Content
private import codeql.rust.dataflow.FlowSource as FlowSource
private import codeql.rust.dataflow.FlowSink as FlowSink
private import codeql.rust.dataflow.internal.TaintTrackingImpl
private import codeql.rust.dataflow.internal.TaintTrackingImpl as TaintTrackingImpl
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary
@@ -42,9 +43,15 @@ class QualifiedCallable extends TCallable {
string getCanonicalPath() { result = path }
}
module ModelGeneratorCommonInput implements
ModelGeneratorCommonInputSig<R::Location, DataFlowImpl::RustDataFlow>
{
private module RustDataFlowInput implements DataFlowImpl::RustDataFlowInputSig {
predicate includeDynamicTargets() { none() }
}
module RustDataFlow = DataFlowImpl::RustDataFlowGen<RustDataFlowInput>;
module RustTaintTracking = TaintTrackingImpl::RustTaintTrackingGen<RustDataFlowInput>;
module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<R::Location, RustDataFlow> {
// NOTE: We are not using type information for now.
class Type = Unit;
@@ -71,9 +78,8 @@ module ModelGeneratorCommonInput implements
string parameterExactAccess(R::ParamBase p) {
result =
"Argument[" +
any(DataFlowImpl::RustDataFlow::ParameterPosition pos | p = pos.getParameterIn(_))
.toString() + "]"
"Argument[" + any(RustDataFlow::ParameterPosition pos | p = pos.getParameterIn(_)).toString() +
"]"
}
string parameterApproximateAccess(R::ParamBase p) { result = parameterExactAccess(p) }
@@ -83,16 +89,12 @@ module ModelGeneratorCommonInput implements
}
bindingset[c]
string paramReturnNodeAsApproximateOutput(
QualifiedCallable c, DataFlowImpl::RustDataFlow::ParameterPosition pos
) {
string paramReturnNodeAsApproximateOutput(QualifiedCallable c, RustDataFlow::ParameterPosition pos) {
result = paramReturnNodeAsExactOutput(c, pos)
}
bindingset[c]
string paramReturnNodeAsExactOutput(
QualifiedCallable c, DataFlowImpl::RustDataFlow::ParameterPosition pos
) {
string paramReturnNodeAsExactOutput(QualifiedCallable c, RustDataFlow::ParameterPosition pos) {
result = parameterExactAccess(c.getFunction().getParam(pos.getPosition()))
or
pos.isSelf() and result = qualifierString()
@@ -102,7 +104,7 @@ module ModelGeneratorCommonInput implements
result.getFunction() = ret.(Node::Node).getEnclosingCallable().asCfgScope()
}
predicate isOwnInstanceAccessNode(DataFlowImpl::RustDataFlow::ReturnNode node) {
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.
@@ -121,7 +123,7 @@ module ModelGeneratorCommonInput implements
}
private import ModelGeneratorCommonInput
private import MakeModelGeneratorFactory<R::Location, DataFlowImpl::RustDataFlow, RustTaintTracking, ModelGeneratorCommonInput>
private import MakeModelGeneratorFactory<R::Location, RustDataFlow, RustTaintTracking, ModelGeneratorCommonInput>
private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
class SummaryTargetApi extends QualifiedCallable {