mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #18298 from hvitved/rust/mad-source-sink
Rust: Add support for MaD sources and sinks with access paths
This commit is contained in:
@@ -12,8 +12,14 @@ private import semmle.code.cpp.dataflow.ExternalFlow
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = Function;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { result.(NormalReturnKind).getIndirectionIndex() = 0 }
|
||||
@@ -93,6 +99,10 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) {
|
||||
result.getStaticCallTarget().getUnderlyingCallable() = sc
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
module SourceSinkInterpretationInput implements
|
||||
|
||||
@@ -14,8 +14,14 @@ private import semmle.code.csharp.Unification
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = UnboundCallable;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
predicate neutralElement(SummarizedCallableBase c, string kind, string provenance, boolean isExact) {
|
||||
interpretNeutral(c, kind, provenance) and
|
||||
// isExact is not needed for C#.
|
||||
@@ -176,12 +182,22 @@ private module TypesInput implements Impl::Private::TypesInputSig {
|
||||
result.asGvnType() = Gvn::getGlobalValueNumber(dt.getDelegateType().getReturnType())
|
||||
)
|
||||
}
|
||||
|
||||
DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponent sc) {
|
||||
none()
|
||||
}
|
||||
|
||||
DataFlowType getSinkType(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) {
|
||||
sc = viableCallable(result).asSummarizedCallable()
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
module SourceSinkInterpretationInput implements
|
||||
|
||||
@@ -90,7 +90,7 @@ import internal.ExternalFlowExtensions as FlowExtensions
|
||||
private import FlowSummary as FlowSummary
|
||||
private import internal.DataFlowPrivate
|
||||
private import internal.FlowSummaryImpl
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Public as Public
|
||||
private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
@@ -583,13 +583,13 @@ predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind,
|
||||
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
|
||||
|
||||
// adapter class for converting Mad summaries to `SummarizedCallable`s
|
||||
private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
private class SummarizedCallableAdapter extends Public::SummarizedCallable {
|
||||
SummarizedCallableAdapter() { summaryElement(this, _, _, _, _, _) }
|
||||
|
||||
private predicate relevantSummaryElementManual(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
exists(Public::Provenance provenance |
|
||||
summaryElement(this, input, output, kind, provenance, model) and
|
||||
provenance.isManual()
|
||||
)
|
||||
@@ -598,11 +598,11 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
private predicate relevantSummaryElementGenerated(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
exists(Public::Provenance provenance |
|
||||
summaryElement(this, input, output, kind, provenance, model) and
|
||||
provenance.isGenerated()
|
||||
) and
|
||||
not exists(Provenance provenance |
|
||||
not exists(Public::Provenance provenance |
|
||||
neutralElement(this, "summary", provenance) and
|
||||
provenance.isManual()
|
||||
)
|
||||
@@ -621,7 +621,7 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) {
|
||||
override predicate hasProvenance(Public::Provenance provenance) {
|
||||
summaryElement(this, _, _, _, provenance, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,14 @@ private string positionToString(int pos) {
|
||||
}
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::GoDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = Callable;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
predicate neutralElement(
|
||||
Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact
|
||||
) {
|
||||
@@ -108,6 +114,10 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
call.getACalleeIncludingExternals() = sc
|
||||
)
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
module SourceSinkInterpretationInput implements
|
||||
|
||||
@@ -27,8 +27,14 @@ private string positionToString(int pos) {
|
||||
}
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::JavaDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = FlowSummary::SummarizedCallableBase;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
predicate neutralElement(
|
||||
Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact
|
||||
) {
|
||||
@@ -123,12 +129,22 @@ private module TypesInput implements Impl::Private::TypesInputSig {
|
||||
result = getErasedRepr(t.(FunctionalInterface).getRunMethod().getReturnType()) and
|
||||
exists(rk)
|
||||
}
|
||||
|
||||
DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponent sc) {
|
||||
none()
|
||||
}
|
||||
|
||||
DataFlowType getSinkType(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) {
|
||||
sc = viableCallable(result).asSummarizedCallable()
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
private predicate relatedArgSpec(Callable c, string spec) {
|
||||
|
||||
@@ -10,8 +10,14 @@ private import DataFlowImplSpecific::Private
|
||||
private import DataFlowImplSpecific::Public
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = string;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result.isLambdaSelf() }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { any() }
|
||||
@@ -98,6 +104,10 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
sc.(LibraryCallable).getACallSimple().asCfgNode()
|
||||
])
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
module Private {
|
||||
|
||||
@@ -10,8 +10,14 @@ private import DataFlowImplSpecific::Private
|
||||
private import DataFlowImplSpecific::Public
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::RubyDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = string;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result.isLambdaSelf() }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { result instanceof NormalReturnKind }
|
||||
@@ -154,6 +160,10 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
or
|
||||
result.asCall().getAstNode() = sc.(LibraryCallable).getACallSimple()
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
module Private {
|
||||
|
||||
36
rust/ql/lib/codeql/rust/dataflow/FlowSink.qll
Normal file
36
rust/ql/lib/codeql/rust/dataflow/FlowSink.qll
Normal file
@@ -0,0 +1,36 @@
|
||||
/** Provides classes and predicates for defining flow sinks. */
|
||||
|
||||
private import rust
|
||||
private import internal.FlowSummaryImpl as Impl
|
||||
private import internal.DataFlowImpl as DataFlowImpl
|
||||
|
||||
// import all instances below
|
||||
private module Sinks {
|
||||
private import codeql.rust.Frameworks
|
||||
private import codeql.rust.dataflow.internal.ModelsAsData
|
||||
}
|
||||
|
||||
/** Provides the `Range` class used to define the extent of `FlowSink`. */
|
||||
module FlowSink {
|
||||
/** A flow source. */
|
||||
abstract class Range extends Impl::Public::SinkElement {
|
||||
bindingset[this]
|
||||
Range() { any() }
|
||||
|
||||
override predicate isSink(
|
||||
string input, string kind, Impl::Public::Provenance provenance, string model
|
||||
) {
|
||||
this.isSink(input, kind) and provenance = "manual" and model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds is this element is a flow sink of kind `kind`, where data
|
||||
* flows in as described by `input`.
|
||||
*/
|
||||
predicate isSink(string output, string kind) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
final class FlowSink = FlowSink::Range;
|
||||
|
||||
predicate sinkNode = DataFlowImpl::sinkNode/2;
|
||||
36
rust/ql/lib/codeql/rust/dataflow/FlowSource.qll
Normal file
36
rust/ql/lib/codeql/rust/dataflow/FlowSource.qll
Normal file
@@ -0,0 +1,36 @@
|
||||
/** Provides classes and predicates for defining flow sources. */
|
||||
|
||||
private import rust
|
||||
private import internal.FlowSummaryImpl as Impl
|
||||
private import internal.DataFlowImpl as DataFlowImpl
|
||||
|
||||
// import all instances below
|
||||
private module Sources {
|
||||
private import codeql.rust.Frameworks
|
||||
private import codeql.rust.dataflow.internal.ModelsAsData
|
||||
}
|
||||
|
||||
/** Provides the `Range` class used to define the extent of `FlowSource`. */
|
||||
module FlowSource {
|
||||
/** A flow source. */
|
||||
abstract class Range extends Impl::Public::SourceElement {
|
||||
bindingset[this]
|
||||
Range() { any() }
|
||||
|
||||
override predicate isSource(
|
||||
string output, string kind, Impl::Public::Provenance provenance, string model
|
||||
) {
|
||||
this.isSource(output, kind) and provenance = "manual" and model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds is this element is a flow source of kind `kind`, where data
|
||||
* flows out as described by `output`.
|
||||
*/
|
||||
predicate isSource(string output, string kind) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
final class FlowSource = FlowSource::Range;
|
||||
|
||||
predicate sourceNode = DataFlowImpl::sourceNode/2;
|
||||
@@ -57,3 +57,5 @@ module SummarizedCallable {
|
||||
}
|
||||
|
||||
final class SummarizedCallable = SummarizedCallable::Range;
|
||||
|
||||
final class Provenance = Impl::Public::Provenance;
|
||||
|
||||
@@ -186,18 +186,51 @@ module Node {
|
||||
class FlowSummaryNode extends Node, TFlowSummaryNode {
|
||||
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
|
||||
|
||||
/** Gets the summarized callable that this node belongs to. */
|
||||
/** Gets the summarized callable that this node belongs to, if any. */
|
||||
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
|
||||
result = this.getSummaryNode().getSummarizedCallable()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { none() }
|
||||
/** Gets the AST source node that this node belongs to, if any */
|
||||
FlowSummaryImpl::Public::SourceElement getSourceElement() {
|
||||
result = this.getSummaryNode().getSourceElement()
|
||||
}
|
||||
|
||||
/** Gets the AST sink node that this node belongs to, if any */
|
||||
FlowSummaryImpl::Public::SinkElement getSinkElement() {
|
||||
result = this.getSummaryNode().getSinkElement()
|
||||
}
|
||||
|
||||
/** Holds is this node is a source node of kind `kind`. */
|
||||
predicate isSource(string kind, string model) {
|
||||
this.getSummaryNode().(FlowSummaryImpl::Private::SourceOutputNode).isEntry(kind, model)
|
||||
}
|
||||
|
||||
/** Holds is this node is a sink node of kind `kind`. */
|
||||
predicate isSink(string kind, string model) {
|
||||
this.getSummaryNode().(FlowSummaryImpl::Private::SinkInputNode).isExit(kind, model)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() {
|
||||
result = this.getSummaryNode().getSourceElement().getEnclosingCfgScope()
|
||||
or
|
||||
result = this.getSummaryNode().getSinkElement().getEnclosingCfgScope()
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asLibraryCallable() = this.getSummarizedCallable()
|
||||
or
|
||||
result.asCfgScope() = this.getCfgScope()
|
||||
}
|
||||
|
||||
override EmptyLocation getLocation() { any() }
|
||||
override Location getLocation() {
|
||||
exists(this.getSummarizedCallable()) and
|
||||
result instanceof EmptyLocation
|
||||
or
|
||||
result = this.getSourceElement().getLocation()
|
||||
or
|
||||
result = this.getSinkElement().getLocation()
|
||||
}
|
||||
|
||||
override string toString() { result = this.getSummaryNode().toString() }
|
||||
}
|
||||
@@ -527,13 +560,20 @@ private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
|
||||
}
|
||||
|
||||
module LocalFlow {
|
||||
predicate flowSummaryLocalStep(
|
||||
Node::FlowSummaryNode nodeFrom, Node::FlowSummaryNode nodeTo,
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, string model
|
||||
) {
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.getSummaryNode(),
|
||||
nodeTo.getSummaryNode(), true, model) and
|
||||
c = nodeFrom.getSummarizedCallable()
|
||||
predicate flowSummaryLocalStep(Node nodeFrom, Node nodeTo, string model) {
|
||||
exists(FlowSummaryImpl::Public::SummarizedCallable c |
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom
|
||||
.(Node::FlowSummaryNode)
|
||||
.getSummaryNode(), nodeTo.(Node::FlowSummaryNode).getSummaryNode(), true, model) and
|
||||
c = nodeFrom.(Node::FlowSummaryNode).getSummarizedCallable()
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::sourceLocalStep(nodeFrom
|
||||
.(Node::FlowSummaryNode)
|
||||
.getSummaryNode(), nodeTo, model)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::sinkLocalStep(nodeFrom,
|
||||
nodeTo.(Node::FlowSummaryNode).getSummaryNode(), model)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -854,7 +894,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
predicate nodeIsHidden(Node node) {
|
||||
node instanceof Node::SsaNode
|
||||
or
|
||||
node instanceof Node::FlowSummaryNode
|
||||
node.(Node::FlowSummaryNode).getSummaryNode().isHidden()
|
||||
or
|
||||
node instanceof Node::CaptureNode
|
||||
or
|
||||
@@ -870,6 +910,10 @@ module RustDataFlow implements InputSig<Location> {
|
||||
node.asExpr() = match.getScrutinee() or
|
||||
node.asExpr() = match.getArmPat(_)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::sourceLocalStep(_, node, _)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::sinkLocalStep(node, _, _)
|
||||
}
|
||||
|
||||
class DataFlowExpr = ExprCfgNode;
|
||||
@@ -950,7 +994,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
LocalFlow::flowSummaryLocalStep(nodeFrom, nodeTo, _, model)
|
||||
LocalFlow::flowSummaryLocalStep(nodeFrom, nodeTo, model)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1262,9 +1306,13 @@ module RustDataFlow implements InputSig<Location> {
|
||||
/** Extra data flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
predicate knownSourceModel(Node source, string model) { none() }
|
||||
predicate knownSourceModel(Node source, string model) {
|
||||
source.(Node::FlowSummaryNode).isSource(_, model)
|
||||
}
|
||||
|
||||
predicate knownSinkModel(Node sink, string model) { none() }
|
||||
predicate knownSinkModel(Node sink, string model) {
|
||||
sink.(Node::FlowSummaryNode).isSink(_, model)
|
||||
}
|
||||
|
||||
class DataFlowSecondLevelScope = Void;
|
||||
}
|
||||
@@ -1529,6 +1577,14 @@ private module Cached {
|
||||
|
||||
cached
|
||||
newtype TContentSet = TSingletonContentSet(Content c)
|
||||
|
||||
/** Holds if `n` is a flow source of kind `kind`. */
|
||||
cached
|
||||
predicate sourceNode(Node n, string kind) { n.(Node::FlowSummaryNode).isSource(kind, _) }
|
||||
|
||||
/** Holds if `n` is a flow sink of kind `kind`. */
|
||||
cached
|
||||
predicate sinkNode(Node n, string kind) { n.(Node::FlowSummaryNode).isSink(kind, _) }
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
@@ -9,8 +9,48 @@ private import codeql.rust.dataflow.internal.DataFlowImpl
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
|
||||
module Input implements InputSig<Location, RustDataFlow> {
|
||||
private import codeql.rust.elements.internal.CallExprBaseImpl::Impl as CallExprBaseImpl
|
||||
|
||||
class SummarizedCallableBase = string;
|
||||
|
||||
abstract private class SourceSinkBase extends AstNode {
|
||||
/** Gets the associated call. */
|
||||
abstract CallExprBase getCall();
|
||||
|
||||
/** Holds if the associated call resolves to `crate, path`. */
|
||||
final predicate callResolvesTo(string crate, string path) {
|
||||
exists(Resolvable r |
|
||||
r = CallExprBaseImpl::getCallResolvable(this.getCall()) and
|
||||
path = r.getResolvedPath()
|
||||
|
|
||||
crate = r.getResolvedCrateOrigin()
|
||||
or
|
||||
not r.hasResolvedCrateOrigin() and
|
||||
crate = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SourceBase extends SourceSinkBase { }
|
||||
|
||||
abstract class SinkBase extends SourceSinkBase { }
|
||||
|
||||
private class CallExprFunction extends SourceBase, SinkBase {
|
||||
private CallExpr call;
|
||||
|
||||
CallExprFunction() { this = call.getFunction() }
|
||||
|
||||
override CallExpr getCall() { result = call }
|
||||
}
|
||||
|
||||
private class MethodCallExprNameRef extends SourceBase, SinkBase {
|
||||
private MethodCallExpr call;
|
||||
|
||||
MethodCallExprNameRef() { this = call.getNameRef() }
|
||||
|
||||
override MethodCallExpr getCall() { result = call }
|
||||
}
|
||||
|
||||
RustDataFlow::ArgumentPosition callbackSelfParameterPosition() { none() }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { result = TNormalReturnKind() }
|
||||
@@ -86,12 +126,32 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) {
|
||||
result.asCallBaseExprCfgNode().getCallExprBase() = sc.(LibraryCallable).getACall()
|
||||
}
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) {
|
||||
sc = Impl::Private::SummaryComponent::return(_) and
|
||||
result.asExpr().getExpr() = source.getCall()
|
||||
}
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) {
|
||||
exists(CallExprBase call, Expr arg, ParameterPosition pos |
|
||||
result.asExpr().getExpr() = arg and
|
||||
sc = Impl::Private::SummaryComponent::argument(pos) and
|
||||
call = sink.getCall()
|
||||
|
|
||||
arg = call.getArgList().getArg(pos.getPosition())
|
||||
or
|
||||
arg = call.(MethodCallExpr).getReceiver() and pos.isSelf()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Private {
|
||||
import Impl::Private
|
||||
|
||||
module Steps = Impl::Private::Steps<StepsInput>;
|
||||
|
||||
private import codeql.rust.dataflow.FlowSource
|
||||
private import codeql.rust.dataflow.FlowSink
|
||||
}
|
||||
|
||||
module Public = Impl::Public;
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
private import codeql.rust.dataflow.FlowSource
|
||||
private import codeql.rust.dataflow.FlowSink
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, defined in the
|
||||
@@ -138,3 +140,37 @@ private class SummarizedCallableFromModel extends SummarizedCallable::Range {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FlowSourceFromModel extends FlowSource::Range {
|
||||
private string crate;
|
||||
private string path;
|
||||
|
||||
FlowSourceFromModel() {
|
||||
sourceModel(crate, path, _, _, _, _) and
|
||||
this.callResolvesTo(crate, path)
|
||||
}
|
||||
|
||||
override predicate isSource(string output, string kind, Provenance provenance, string model) {
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
sourceModel(crate, path, output, kind, provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FlowSinkFromModel extends FlowSink::Range {
|
||||
private string crate;
|
||||
private string path;
|
||||
|
||||
FlowSinkFromModel() {
|
||||
sinkModel(crate, path, _, _, _, _) and
|
||||
this.callResolvesTo(crate, path)
|
||||
}
|
||||
|
||||
override predicate isSink(string input, string kind, Provenance provenance, string model) {
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
sinkModel(crate, path, input, kind, provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@ private module FlowTestImpl implements InputSig<Location, RustDataFlow> {
|
||||
private string getSourceArgString(DataFlow::Node src) {
|
||||
defaultSource(src) and
|
||||
result = src.asExpr().(CallExprCfgNode).getArgument(0).toString()
|
||||
or
|
||||
sourceNode(src, _) and
|
||||
exists(CallExprBase call |
|
||||
call = src.(Node::FlowSummaryNode).getSourceElement().getCall() and
|
||||
result = call.getArgList().getArg(0).toString()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[src, sink]
|
||||
|
||||
@@ -175,6 +175,71 @@ fn test_set_tuple_element() {
|
||||
sink(t.1); // $ hasValueFlow=11
|
||||
}
|
||||
|
||||
impl MyFieldEnum {
|
||||
// has a source model
|
||||
fn source(&self, i: i64) -> MyFieldEnum {
|
||||
MyFieldEnum::C { field_c: 0 }
|
||||
}
|
||||
|
||||
// has a sink model
|
||||
fn sink(self) {}
|
||||
}
|
||||
|
||||
// has a source model
|
||||
fn enum_source(i: i64) -> MyFieldEnum {
|
||||
MyFieldEnum::C { field_c: 0 }
|
||||
}
|
||||
|
||||
fn test_enum_source() {
|
||||
let s = enum_source(12);
|
||||
match s {
|
||||
MyFieldEnum::C { field_c: i } => sink(i),
|
||||
MyFieldEnum::D { field_d: i } => sink(i), // $ hasValueFlow=12
|
||||
}
|
||||
}
|
||||
|
||||
fn test_enum_method_source() {
|
||||
let e = MyFieldEnum::D { field_d: 0 };
|
||||
let s = e.source(13);
|
||||
match s {
|
||||
MyFieldEnum::C { field_c: i } => sink(i), // $ hasValueFlow=13
|
||||
MyFieldEnum::D { field_d: i } => sink(i),
|
||||
}
|
||||
}
|
||||
|
||||
// has a sink model
|
||||
fn enum_sink(e: MyFieldEnum) {}
|
||||
|
||||
fn test_enum_sink() {
|
||||
let s = source(14);
|
||||
enum_sink(MyFieldEnum::C { field_c: s }); // $ hasValueFlow=14
|
||||
enum_sink(MyFieldEnum::D { field_d: s });
|
||||
}
|
||||
|
||||
fn test_enum_method_sink() {
|
||||
let s = source(15);
|
||||
let e = MyFieldEnum::D { field_d: s };
|
||||
e.sink(); // $ hasValueFlow=15
|
||||
}
|
||||
|
||||
// has a source model
|
||||
fn simple_source(i: i64) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
fn test_simple_source() {
|
||||
let s = simple_source(16);
|
||||
sink(s) // $ hasValueFlow=16
|
||||
}
|
||||
|
||||
// has a sink model
|
||||
fn simple_sink(i: i64) {}
|
||||
|
||||
fn test_simple_sink() {
|
||||
let s = source(17);
|
||||
simple_sink(s); // $ hasValueFlow=17
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_identify();
|
||||
test_get_var_pos();
|
||||
@@ -187,5 +252,11 @@ fn main() {
|
||||
test_set_array_element();
|
||||
test_get_tuple_element();
|
||||
test_set_tuple_element();
|
||||
test_enum_source();
|
||||
test_enum_method_source();
|
||||
test_enum_sink();
|
||||
test_enum_method_sink();
|
||||
test_simple_source();
|
||||
test_simple_sink();
|
||||
let dummy = Some(0); // ensure that the the `lang:core` crate is extracted
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
models
|
||||
| 1 | Summary: repo::test; crate::coerce; Argument[0]; ReturnValue; taint |
|
||||
| 2 | Summary: repo::test; crate::get_array_element; Argument[0].ArrayElement; ReturnValue; value |
|
||||
| 3 | Summary: repo::test; crate::get_struct_field; Argument[0].Struct[crate::MyStruct::field1]; ReturnValue; value |
|
||||
| 4 | Summary: repo::test; crate::get_tuple_element; Argument[0].Tuple[0]; ReturnValue; value |
|
||||
| 5 | Summary: repo::test; crate::get_var_field; Argument[0].Variant[crate::MyFieldEnum::C::field_c]; ReturnValue; value |
|
||||
| 6 | Summary: repo::test; crate::get_var_pos; Argument[0].Variant[crate::MyPosEnum::A(0)]; ReturnValue; value |
|
||||
| 7 | Summary: repo::test; crate::set_array_element; Argument[0]; ReturnValue.ArrayElement; value |
|
||||
| 8 | Summary: repo::test; crate::set_tuple_element; Argument[0]; ReturnValue.Tuple[1]; value |
|
||||
| 9 | Summary: repo::test; crate::set_var_field; Argument[0]; ReturnValue.Variant[crate::MyFieldEnum::D::field_d]; value |
|
||||
| 10 | Summary: repo::test; crate::set_var_pos; Argument[0]; ReturnValue.Variant[crate::MyPosEnum::B(0)]; value |
|
||||
| 1 | Sink: repo::test; <crate::MyFieldEnum>::sink; test-sink; Argument[self].Variant[crate::MyFieldEnum::D::field_d] |
|
||||
| 2 | Sink: repo::test; crate::enum_sink; test-sink; Argument[0].Variant[crate::MyFieldEnum::C::field_c] |
|
||||
| 3 | Sink: repo::test; crate::simple_sink; test-sink; Argument[0] |
|
||||
| 4 | Source: repo::test; <crate::MyFieldEnum>::source; test-source; ReturnValue.Variant[crate::MyFieldEnum::C::field_c] |
|
||||
| 5 | Source: repo::test; crate::enum_source; test-source; ReturnValue.Variant[crate::MyFieldEnum::D::field_d] |
|
||||
| 6 | Source: repo::test; crate::simple_source; test-source; ReturnValue |
|
||||
| 7 | Summary: repo::test; crate::coerce; Argument[0]; ReturnValue; taint |
|
||||
| 8 | Summary: repo::test; crate::get_array_element; Argument[0].ArrayElement; ReturnValue; value |
|
||||
| 9 | Summary: repo::test; crate::get_struct_field; Argument[0].Struct[crate::MyStruct::field1]; ReturnValue; value |
|
||||
| 10 | Summary: repo::test; crate::get_tuple_element; Argument[0].Tuple[0]; ReturnValue; value |
|
||||
| 11 | Summary: repo::test; crate::get_var_field; Argument[0].Variant[crate::MyFieldEnum::C::field_c]; ReturnValue; value |
|
||||
| 12 | Summary: repo::test; crate::get_var_pos; Argument[0].Variant[crate::MyPosEnum::A(0)]; ReturnValue; value |
|
||||
| 13 | Summary: repo::test; crate::set_array_element; Argument[0]; ReturnValue.ArrayElement; value |
|
||||
| 14 | Summary: repo::test; crate::set_tuple_element; Argument[0]; ReturnValue.Tuple[1]; value |
|
||||
| 15 | Summary: repo::test; crate::set_var_field; Argument[0]; ReturnValue.Variant[crate::MyFieldEnum::D::field_d]; value |
|
||||
| 16 | Summary: repo::test; crate::set_var_pos; Argument[0]; ReturnValue.Variant[crate::MyPosEnum::B(0)]; value |
|
||||
edges
|
||||
| main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | |
|
||||
| main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | |
|
||||
@@ -18,7 +24,7 @@ edges
|
||||
| main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | QL |
|
||||
| main.rs:25:9:25:9 | s | main.rs:26:17:26:17 | s | provenance | |
|
||||
| main.rs:25:13:25:22 | source(...) | main.rs:25:9:25:9 | s | provenance | |
|
||||
| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:1 |
|
||||
| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:7 |
|
||||
| main.rs:40:9:40:9 | s | main.rs:41:27:41:27 | s | provenance | |
|
||||
| main.rs:40:9:40:9 | s | main.rs:41:27:41:27 | s | provenance | |
|
||||
| main.rs:40:13:40:21 | source(...) | main.rs:40:9:40:9 | s | provenance | |
|
||||
@@ -29,8 +35,8 @@ edges
|
||||
| main.rs:41:14:41:28 | ...::A(...) [A] | main.rs:41:9:41:10 | e1 [A] | provenance | |
|
||||
| main.rs:41:27:41:27 | s | main.rs:41:14:41:28 | ...::A(...) [A] | provenance | |
|
||||
| main.rs:41:27:41:27 | s | main.rs:41:14:41:28 | ...::A(...) [A] | provenance | |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:6 |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:6 |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:12 |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:12 |
|
||||
| main.rs:53:9:53:9 | s | main.rs:54:26:54:26 | s | provenance | |
|
||||
| main.rs:53:9:53:9 | s | main.rs:54:26:54:26 | s | provenance | |
|
||||
| main.rs:53:13:53:21 | source(...) | main.rs:53:9:53:9 | s | provenance | |
|
||||
@@ -39,8 +45,8 @@ edges
|
||||
| main.rs:54:9:54:10 | e1 [B] | main.rs:55:11:55:12 | e1 [B] | provenance | |
|
||||
| main.rs:54:14:54:27 | set_var_pos(...) [B] | main.rs:54:9:54:10 | e1 [B] | provenance | |
|
||||
| main.rs:54:14:54:27 | set_var_pos(...) [B] | main.rs:54:9:54:10 | e1 [B] | provenance | |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:10 |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:10 |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:16 |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:16 |
|
||||
| main.rs:55:11:55:12 | e1 [B] | main.rs:57:9:57:23 | ...::B(...) [B] | provenance | |
|
||||
| main.rs:55:11:55:12 | e1 [B] | main.rs:57:9:57:23 | ...::B(...) [B] | provenance | |
|
||||
| main.rs:57:9:57:23 | ...::B(...) [B] | main.rs:57:22:57:22 | i | provenance | |
|
||||
@@ -57,8 +63,8 @@ edges
|
||||
| main.rs:73:14:73:42 | ...::C {...} [C] | main.rs:73:9:73:10 | e1 [C] | provenance | |
|
||||
| main.rs:73:40:73:40 | s | main.rs:73:14:73:42 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:73:40:73:40 | s | main.rs:73:14:73:42 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:5 |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:5 |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:11 |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:11 |
|
||||
| main.rs:85:9:85:9 | s | main.rs:86:28:86:28 | s | provenance | |
|
||||
| main.rs:85:9:85:9 | s | main.rs:86:28:86:28 | s | provenance | |
|
||||
| main.rs:85:13:85:21 | source(...) | main.rs:85:9:85:9 | s | provenance | |
|
||||
@@ -67,8 +73,8 @@ edges
|
||||
| main.rs:86:9:86:10 | e1 [D] | main.rs:87:11:87:12 | e1 [D] | provenance | |
|
||||
| main.rs:86:14:86:29 | set_var_field(...) [D] | main.rs:86:9:86:10 | e1 [D] | provenance | |
|
||||
| main.rs:86:14:86:29 | set_var_field(...) [D] | main.rs:86:9:86:10 | e1 [D] | provenance | |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:9 |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:9 |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:15 |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:15 |
|
||||
| main.rs:87:11:87:12 | e1 [D] | main.rs:89:9:89:37 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:87:11:87:12 | e1 [D] | main.rs:89:9:89:37 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:89:9:89:37 | ...::D {...} [D] | main.rs:89:35:89:35 | i | provenance | |
|
||||
@@ -85,14 +91,14 @@ edges
|
||||
| main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | main.rs:105:9:105:17 | my_struct [MyStruct.field1] | provenance | |
|
||||
| main.rs:106:17:106:17 | s | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | provenance | |
|
||||
| main.rs:106:17:106:17 | s | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | provenance | |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:3 |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:3 |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:9 |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:9 |
|
||||
| main.rs:138:9:138:9 | s | main.rs:139:29:139:29 | s | provenance | |
|
||||
| main.rs:138:9:138:9 | s | main.rs:139:29:139:29 | s | provenance | |
|
||||
| main.rs:138:13:138:21 | source(...) | main.rs:138:9:138:9 | s | provenance | |
|
||||
| main.rs:138:13:138:21 | source(...) | main.rs:138:9:138:9 | s | provenance | |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:2 |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:2 |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:8 |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:8 |
|
||||
| main.rs:139:29:139:29 | s | main.rs:139:28:139:30 | [...] [array[]] | provenance | |
|
||||
| main.rs:139:29:139:29 | s | main.rs:139:28:139:30 | [...] [array[]] | provenance | |
|
||||
| main.rs:148:9:148:9 | s | main.rs:149:33:149:33 | s | provenance | |
|
||||
@@ -103,8 +109,8 @@ edges
|
||||
| main.rs:149:9:149:11 | arr [array[]] | main.rs:150:10:150:12 | arr [array[]] | provenance | |
|
||||
| main.rs:149:15:149:34 | set_array_element(...) [array[]] | main.rs:149:9:149:11 | arr [array[]] | provenance | |
|
||||
| main.rs:149:15:149:34 | set_array_element(...) [array[]] | main.rs:149:9:149:11 | arr [array[]] | provenance | |
|
||||
| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [array[]] | provenance | MaD:7 |
|
||||
| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [array[]] | provenance | MaD:7 |
|
||||
| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [array[]] | provenance | MaD:13 |
|
||||
| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [array[]] | provenance | MaD:13 |
|
||||
| main.rs:150:10:150:12 | arr [array[]] | main.rs:150:10:150:15 | arr[0] | provenance | |
|
||||
| main.rs:150:10:150:12 | arr [array[]] | main.rs:150:10:150:15 | arr[0] | provenance | |
|
||||
| main.rs:159:9:159:9 | s | main.rs:160:14:160:14 | s | provenance | |
|
||||
@@ -117,8 +123,8 @@ edges
|
||||
| main.rs:160:13:160:18 | TupleExpr [tuple.0] | main.rs:160:9:160:9 | t [tuple.0] | provenance | |
|
||||
| main.rs:160:14:160:14 | s | main.rs:160:13:160:18 | TupleExpr [tuple.0] | provenance | |
|
||||
| main.rs:160:14:160:14 | s | main.rs:160:13:160:18 | TupleExpr [tuple.0] | provenance | |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:4 |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:4 |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:10 |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:10 |
|
||||
| main.rs:172:9:172:9 | s | main.rs:173:31:173:31 | s | provenance | |
|
||||
| main.rs:172:9:172:9 | s | main.rs:173:31:173:31 | s | provenance | |
|
||||
| main.rs:172:13:172:22 | source(...) | main.rs:172:9:172:9 | s | provenance | |
|
||||
@@ -127,10 +133,66 @@ edges
|
||||
| main.rs:173:9:173:9 | t [tuple.1] | main.rs:175:10:175:10 | t [tuple.1] | provenance | |
|
||||
| main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | main.rs:173:9:173:9 | t [tuple.1] | provenance | |
|
||||
| main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | main.rs:173:9:173:9 | t [tuple.1] | provenance | |
|
||||
| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:8 |
|
||||
| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:8 |
|
||||
| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:14 |
|
||||
| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:14 |
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | main.rs:175:10:175:12 | t.1 | provenance | |
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | main.rs:175:10:175:12 | t.1 | provenance | |
|
||||
| main.rs:194:9:194:9 | s [D] | main.rs:195:11:195:11 | s [D] | provenance | |
|
||||
| main.rs:194:9:194:9 | s [D] | main.rs:195:11:195:11 | s [D] | provenance | |
|
||||
| main.rs:194:13:194:23 | enum_source | main.rs:194:13:194:27 | enum_source(...) [D] | provenance | Src:MaD:5 |
|
||||
| main.rs:194:13:194:23 | enum_source | main.rs:194:13:194:27 | enum_source(...) [D] | provenance | Src:MaD:5 |
|
||||
| main.rs:194:13:194:27 | enum_source(...) [D] | main.rs:194:9:194:9 | s [D] | provenance | |
|
||||
| main.rs:194:13:194:27 | enum_source(...) [D] | main.rs:194:9:194:9 | s [D] | provenance | |
|
||||
| main.rs:195:11:195:11 | s [D] | main.rs:197:9:197:37 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:195:11:195:11 | s [D] | main.rs:197:9:197:37 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:197:9:197:37 | ...::D {...} [D] | main.rs:197:35:197:35 | i | provenance | |
|
||||
| main.rs:197:9:197:37 | ...::D {...} [D] | main.rs:197:35:197:35 | i | provenance | |
|
||||
| main.rs:197:35:197:35 | i | main.rs:197:47:197:47 | i | provenance | |
|
||||
| main.rs:197:35:197:35 | i | main.rs:197:47:197:47 | i | provenance | |
|
||||
| main.rs:203:9:203:9 | s [C] | main.rs:204:11:204:11 | s [C] | provenance | |
|
||||
| main.rs:203:9:203:9 | s [C] | main.rs:204:11:204:11 | s [C] | provenance | |
|
||||
| main.rs:203:13:203:24 | e.source(...) [C] | main.rs:203:9:203:9 | s [C] | provenance | |
|
||||
| main.rs:203:13:203:24 | e.source(...) [C] | main.rs:203:9:203:9 | s [C] | provenance | |
|
||||
| main.rs:203:15:203:20 | source | main.rs:203:13:203:24 | e.source(...) [C] | provenance | Src:MaD:4 |
|
||||
| main.rs:203:15:203:20 | source | main.rs:203:13:203:24 | e.source(...) [C] | provenance | Src:MaD:4 |
|
||||
| main.rs:204:11:204:11 | s [C] | main.rs:205:9:205:37 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:204:11:204:11 | s [C] | main.rs:205:9:205:37 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:205:9:205:37 | ...::C {...} [C] | main.rs:205:35:205:35 | i | provenance | |
|
||||
| main.rs:205:9:205:37 | ...::C {...} [C] | main.rs:205:35:205:35 | i | provenance | |
|
||||
| main.rs:205:35:205:35 | i | main.rs:205:47:205:47 | i | provenance | |
|
||||
| main.rs:205:35:205:35 | i | main.rs:205:47:205:47 | i | provenance | |
|
||||
| main.rs:214:9:214:9 | s | main.rs:215:41:215:41 | s | provenance | |
|
||||
| main.rs:214:9:214:9 | s | main.rs:215:41:215:41 | s | provenance | |
|
||||
| main.rs:214:13:214:22 | source(...) | main.rs:214:9:214:9 | s | provenance | |
|
||||
| main.rs:214:13:214:22 | source(...) | main.rs:214:9:214:9 | s | provenance | |
|
||||
| main.rs:215:15:215:43 | ...::C {...} [C] | main.rs:215:5:215:13 | enum_sink | provenance | MaD:2 Sink:MaD:2 |
|
||||
| main.rs:215:15:215:43 | ...::C {...} [C] | main.rs:215:5:215:13 | enum_sink | provenance | MaD:2 Sink:MaD:2 |
|
||||
| main.rs:215:41:215:41 | s | main.rs:215:15:215:43 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:215:41:215:41 | s | main.rs:215:15:215:43 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:220:9:220:9 | s | main.rs:221:39:221:39 | s | provenance | |
|
||||
| main.rs:220:9:220:9 | s | main.rs:221:39:221:39 | s | provenance | |
|
||||
| main.rs:220:13:220:22 | source(...) | main.rs:220:9:220:9 | s | provenance | |
|
||||
| main.rs:220:13:220:22 | source(...) | main.rs:220:9:220:9 | s | provenance | |
|
||||
| main.rs:221:9:221:9 | e [D] | main.rs:222:5:222:5 | e [D] | provenance | |
|
||||
| main.rs:221:9:221:9 | e [D] | main.rs:222:5:222:5 | e [D] | provenance | |
|
||||
| main.rs:221:13:221:41 | ...::D {...} [D] | main.rs:221:9:221:9 | e [D] | provenance | |
|
||||
| main.rs:221:13:221:41 | ...::D {...} [D] | main.rs:221:9:221:9 | e [D] | provenance | |
|
||||
| main.rs:221:39:221:39 | s | main.rs:221:13:221:41 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:221:39:221:39 | s | main.rs:221:13:221:41 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:222:5:222:5 | e [D] | main.rs:222:7:222:10 | sink | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:222:5:222:5 | e [D] | main.rs:222:7:222:10 | sink | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:231:9:231:9 | s | main.rs:232:10:232:10 | s | provenance | |
|
||||
| main.rs:231:9:231:9 | s | main.rs:232:10:232:10 | s | provenance | |
|
||||
| main.rs:231:13:231:25 | simple_source | main.rs:231:13:231:29 | simple_source(...) | provenance | Src:MaD:6 MaD:6 |
|
||||
| main.rs:231:13:231:25 | simple_source | main.rs:231:13:231:29 | simple_source(...) | provenance | Src:MaD:6 MaD:6 |
|
||||
| main.rs:231:13:231:29 | simple_source(...) | main.rs:231:9:231:9 | s | provenance | |
|
||||
| main.rs:231:13:231:29 | simple_source(...) | main.rs:231:9:231:9 | s | provenance | |
|
||||
| main.rs:239:9:239:9 | s | main.rs:240:17:240:17 | s | provenance | |
|
||||
| main.rs:239:9:239:9 | s | main.rs:240:17:240:17 | s | provenance | |
|
||||
| main.rs:239:13:239:22 | source(...) | main.rs:239:9:239:9 | s | provenance | |
|
||||
| main.rs:239:13:239:22 | source(...) | main.rs:239:9:239:9 | s | provenance | |
|
||||
| main.rs:240:17:240:17 | s | main.rs:240:5:240:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 |
|
||||
| main.rs:240:17:240:17 | s | main.rs:240:5:240:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 |
|
||||
nodes
|
||||
| main.rs:15:9:15:9 | s | semmle.label | s |
|
||||
| main.rs:15:9:15:9 | s | semmle.label | s |
|
||||
@@ -274,6 +336,74 @@ nodes
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | semmle.label | t [tuple.1] |
|
||||
| main.rs:175:10:175:12 | t.1 | semmle.label | t.1 |
|
||||
| main.rs:175:10:175:12 | t.1 | semmle.label | t.1 |
|
||||
| main.rs:194:9:194:9 | s [D] | semmle.label | s [D] |
|
||||
| main.rs:194:9:194:9 | s [D] | semmle.label | s [D] |
|
||||
| main.rs:194:13:194:23 | enum_source | semmle.label | enum_source |
|
||||
| main.rs:194:13:194:23 | enum_source | semmle.label | enum_source |
|
||||
| main.rs:194:13:194:27 | enum_source(...) [D] | semmle.label | enum_source(...) [D] |
|
||||
| main.rs:194:13:194:27 | enum_source(...) [D] | semmle.label | enum_source(...) [D] |
|
||||
| main.rs:195:11:195:11 | s [D] | semmle.label | s [D] |
|
||||
| main.rs:195:11:195:11 | s [D] | semmle.label | s [D] |
|
||||
| main.rs:197:9:197:37 | ...::D {...} [D] | semmle.label | ...::D {...} [D] |
|
||||
| main.rs:197:9:197:37 | ...::D {...} [D] | semmle.label | ...::D {...} [D] |
|
||||
| main.rs:197:35:197:35 | i | semmle.label | i |
|
||||
| main.rs:197:35:197:35 | i | semmle.label | i |
|
||||
| main.rs:197:47:197:47 | i | semmle.label | i |
|
||||
| main.rs:197:47:197:47 | i | semmle.label | i |
|
||||
| main.rs:203:9:203:9 | s [C] | semmle.label | s [C] |
|
||||
| main.rs:203:9:203:9 | s [C] | semmle.label | s [C] |
|
||||
| main.rs:203:13:203:24 | e.source(...) [C] | semmle.label | e.source(...) [C] |
|
||||
| main.rs:203:13:203:24 | e.source(...) [C] | semmle.label | e.source(...) [C] |
|
||||
| main.rs:203:15:203:20 | source | semmle.label | source |
|
||||
| main.rs:203:15:203:20 | source | semmle.label | source |
|
||||
| main.rs:204:11:204:11 | s [C] | semmle.label | s [C] |
|
||||
| main.rs:204:11:204:11 | s [C] | semmle.label | s [C] |
|
||||
| main.rs:205:9:205:37 | ...::C {...} [C] | semmle.label | ...::C {...} [C] |
|
||||
| main.rs:205:9:205:37 | ...::C {...} [C] | semmle.label | ...::C {...} [C] |
|
||||
| main.rs:205:35:205:35 | i | semmle.label | i |
|
||||
| main.rs:205:35:205:35 | i | semmle.label | i |
|
||||
| main.rs:205:47:205:47 | i | semmle.label | i |
|
||||
| main.rs:205:47:205:47 | i | semmle.label | i |
|
||||
| main.rs:214:9:214:9 | s | semmle.label | s |
|
||||
| main.rs:214:9:214:9 | s | semmle.label | s |
|
||||
| main.rs:214:13:214:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:214:13:214:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:215:5:215:13 | enum_sink | semmle.label | enum_sink |
|
||||
| main.rs:215:5:215:13 | enum_sink | semmle.label | enum_sink |
|
||||
| main.rs:215:15:215:43 | ...::C {...} [C] | semmle.label | ...::C {...} [C] |
|
||||
| main.rs:215:15:215:43 | ...::C {...} [C] | semmle.label | ...::C {...} [C] |
|
||||
| main.rs:215:41:215:41 | s | semmle.label | s |
|
||||
| main.rs:215:41:215:41 | s | semmle.label | s |
|
||||
| main.rs:220:9:220:9 | s | semmle.label | s |
|
||||
| main.rs:220:9:220:9 | s | semmle.label | s |
|
||||
| main.rs:220:13:220:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:220:13:220:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:221:9:221:9 | e [D] | semmle.label | e [D] |
|
||||
| main.rs:221:9:221:9 | e [D] | semmle.label | e [D] |
|
||||
| main.rs:221:13:221:41 | ...::D {...} [D] | semmle.label | ...::D {...} [D] |
|
||||
| main.rs:221:13:221:41 | ...::D {...} [D] | semmle.label | ...::D {...} [D] |
|
||||
| main.rs:221:39:221:39 | s | semmle.label | s |
|
||||
| main.rs:221:39:221:39 | s | semmle.label | s |
|
||||
| main.rs:222:5:222:5 | e [D] | semmle.label | e [D] |
|
||||
| main.rs:222:5:222:5 | e [D] | semmle.label | e [D] |
|
||||
| main.rs:222:7:222:10 | sink | semmle.label | sink |
|
||||
| main.rs:222:7:222:10 | sink | semmle.label | sink |
|
||||
| main.rs:231:9:231:9 | s | semmle.label | s |
|
||||
| main.rs:231:9:231:9 | s | semmle.label | s |
|
||||
| main.rs:231:13:231:25 | simple_source | semmle.label | simple_source |
|
||||
| main.rs:231:13:231:25 | simple_source | semmle.label | simple_source |
|
||||
| main.rs:231:13:231:29 | simple_source(...) | semmle.label | simple_source(...) |
|
||||
| main.rs:231:13:231:29 | simple_source(...) | semmle.label | simple_source(...) |
|
||||
| main.rs:232:10:232:10 | s | semmle.label | s |
|
||||
| main.rs:232:10:232:10 | s | semmle.label | s |
|
||||
| main.rs:239:9:239:9 | s | semmle.label | s |
|
||||
| main.rs:239:9:239:9 | s | semmle.label | s |
|
||||
| main.rs:239:13:239:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:239:13:239:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:240:5:240:15 | simple_sink | semmle.label | simple_sink |
|
||||
| main.rs:240:5:240:15 | simple_sink | semmle.label | simple_sink |
|
||||
| main.rs:240:17:240:17 | s | semmle.label | s |
|
||||
| main.rs:240:17:240:17 | s | semmle.label | s |
|
||||
subpaths
|
||||
testFailures
|
||||
invalidSpecComponent
|
||||
@@ -299,3 +429,15 @@ invalidSpecComponent
|
||||
| main.rs:161:10:161:29 | get_tuple_element(...) | main.rs:159:13:159:22 | source(...) | main.rs:161:10:161:29 | get_tuple_element(...) | $@ | main.rs:159:13:159:22 | source(...) | source(...) |
|
||||
| main.rs:175:10:175:12 | t.1 | main.rs:172:13:172:22 | source(...) | main.rs:175:10:175:12 | t.1 | $@ | main.rs:172:13:172:22 | source(...) | source(...) |
|
||||
| main.rs:175:10:175:12 | t.1 | main.rs:172:13:172:22 | source(...) | main.rs:175:10:175:12 | t.1 | $@ | main.rs:172:13:172:22 | source(...) | source(...) |
|
||||
| main.rs:197:47:197:47 | i | main.rs:194:13:194:23 | enum_source | main.rs:197:47:197:47 | i | $@ | main.rs:194:13:194:23 | enum_source | enum_source |
|
||||
| main.rs:197:47:197:47 | i | main.rs:194:13:194:23 | enum_source | main.rs:197:47:197:47 | i | $@ | main.rs:194:13:194:23 | enum_source | enum_source |
|
||||
| main.rs:205:47:205:47 | i | main.rs:203:15:203:20 | source | main.rs:205:47:205:47 | i | $@ | main.rs:203:15:203:20 | source | source |
|
||||
| main.rs:205:47:205:47 | i | main.rs:203:15:203:20 | source | main.rs:205:47:205:47 | i | $@ | main.rs:203:15:203:20 | source | source |
|
||||
| main.rs:215:5:215:13 | enum_sink | main.rs:214:13:214:22 | source(...) | main.rs:215:5:215:13 | enum_sink | $@ | main.rs:214:13:214:22 | source(...) | source(...) |
|
||||
| main.rs:215:5:215:13 | enum_sink | main.rs:214:13:214:22 | source(...) | main.rs:215:5:215:13 | enum_sink | $@ | main.rs:214:13:214:22 | source(...) | source(...) |
|
||||
| main.rs:222:7:222:10 | sink | main.rs:220:13:220:22 | source(...) | main.rs:222:7:222:10 | sink | $@ | main.rs:220:13:220:22 | source(...) | source(...) |
|
||||
| main.rs:222:7:222:10 | sink | main.rs:220:13:220:22 | source(...) | main.rs:222:7:222:10 | sink | $@ | main.rs:220:13:220:22 | source(...) | source(...) |
|
||||
| main.rs:232:10:232:10 | s | main.rs:231:13:231:25 | simple_source | main.rs:232:10:232:10 | s | $@ | main.rs:231:13:231:25 | simple_source | simple_source |
|
||||
| main.rs:232:10:232:10 | s | main.rs:231:13:231:25 | simple_source | main.rs:232:10:232:10 | s | $@ | main.rs:231:13:231:25 | simple_source | simple_source |
|
||||
| main.rs:240:5:240:15 | simple_sink | main.rs:239:13:239:22 | source(...) | main.rs:240:5:240:15 | simple_sink | $@ | main.rs:239:13:239:22 | source(...) | source(...) |
|
||||
| main.rs:240:5:240:15 | simple_sink | main.rs:239:13:239:22 | source(...) | main.rs:240:5:240:15 | simple_sink | $@ | main.rs:239:13:239:22 | source(...) | source(...) |
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["repo::test", "crate::simple_source", "ReturnValue", "test-source", "manual"]
|
||||
- ["repo::test", "crate::enum_source", "ReturnValue.Variant[crate::MyFieldEnum::D::field_d]", "test-source", "manual"]
|
||||
- ["repo::test", "<crate::MyFieldEnum>::source", "ReturnValue.Variant[crate::MyFieldEnum::C::field_c]", "test-source", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["repo::test", "crate::simple_sink", "Argument[0]", "test-sink", "manual"]
|
||||
- ["repo::test", "crate::enum_sink", "Argument[0].Variant[crate::MyFieldEnum::C::field_c]", "test-sink", "manual"]
|
||||
- ["repo::test", "<crate::MyFieldEnum>::sink", "Argument[self].Variant[crate::MyFieldEnum::D::field_d]", "test-sink", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModel
|
||||
|
||||
@@ -8,6 +8,8 @@ import codeql.rust.dataflow.DataFlow
|
||||
import codeql.rust.dataflow.FlowSummary
|
||||
import codeql.rust.dataflow.TaintTracking
|
||||
import codeql.rust.dataflow.internal.FlowSummaryImpl
|
||||
import codeql.rust.dataflow.FlowSource
|
||||
import codeql.rust.dataflow.FlowSink
|
||||
import PathGraph
|
||||
|
||||
query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c) {
|
||||
@@ -31,9 +33,17 @@ private class SummarizedCallableIdentity extends SummarizedCallable::Range {
|
||||
}
|
||||
|
||||
module CustomConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { DefaultFlowConfig::isSource(source) }
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
DefaultFlowConfig::isSource(source)
|
||||
or
|
||||
sourceNode(source, "test-source")
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { DefaultFlowConfig::isSink(sink) }
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
DefaultFlowConfig::isSink(sink)
|
||||
or
|
||||
sinkNode(sink, "test-sink")
|
||||
}
|
||||
}
|
||||
|
||||
import FlowTest<CustomConfig, CustomConfig>
|
||||
|
||||
@@ -1040,19 +1040,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
private predicate sourceModel(NodeEx node, string model) {
|
||||
sourceNode(node, _) and
|
||||
exists(Node n | n = node.asNode() |
|
||||
knownSourceModel(n, model)
|
||||
(
|
||||
model = getSourceModel(node)
|
||||
or
|
||||
not knownSourceModel(n, _) and model = ""
|
||||
not exists(getSourceModel(node)) and model = ""
|
||||
)
|
||||
}
|
||||
|
||||
private predicate sinkModel(NodeEx node, string model) {
|
||||
sinkNode(node, _) and
|
||||
exists(Node n | n = node.asNodeOrImplicitRead() |
|
||||
knownSinkModel(n, model)
|
||||
(
|
||||
model = getSinkModel(node)
|
||||
or
|
||||
not knownSinkModel(n, _) and model = ""
|
||||
not exists(getSinkModel(node)) and model = ""
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1063,6 +1063,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
exists(n.asParamReturnNode())
|
||||
}
|
||||
|
||||
cached
|
||||
string getSourceModel(NodeEx node) { knownSourceModel(node.asNode(), result) }
|
||||
|
||||
cached
|
||||
string getSinkModel(NodeEx node) { knownSinkModel(node.asNodeOrImplicitRead(), result) }
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||
isParameterNode(p, c, pos)
|
||||
|
||||
@@ -19,6 +19,24 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
|
||||
string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class of elements that are candidates for flow source modeling.
|
||||
*/
|
||||
bindingset[this]
|
||||
class SourceBase {
|
||||
bindingset[this]
|
||||
string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class of elements that are candidates for flow sink modeling.
|
||||
*/
|
||||
bindingset[this]
|
||||
class SinkBase {
|
||||
bindingset[this]
|
||||
string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a neutral (MaD) model exists for `c` of kind `kind`
|
||||
* with provenance `provenance` and `isExact` is true if the model
|
||||
@@ -159,6 +177,10 @@ module Make<
|
||||
|
||||
final private class SummarizedCallableBaseFinal = SummarizedCallableBase;
|
||||
|
||||
final private class SourceBaseFinal = SourceBase;
|
||||
|
||||
final private class SinkBaseFinal = SinkBase;
|
||||
|
||||
/** Provides classes and predicates for defining flow summaries. */
|
||||
module Public {
|
||||
private import Private
|
||||
@@ -273,6 +295,32 @@ module Make<
|
||||
predicate hasExactModel() { none() }
|
||||
}
|
||||
|
||||
/** A source element. */
|
||||
abstract class SourceElement extends SourceBaseFinal {
|
||||
bindingset[this]
|
||||
SourceElement() { any() }
|
||||
|
||||
/**
|
||||
* Holds if this element is a flow source of kind `kind`, where data
|
||||
* flows out as described by `output`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate isSource(string output, string kind, Provenance provenance, string model);
|
||||
}
|
||||
|
||||
/** A sink element. */
|
||||
abstract class SinkElement extends SinkBaseFinal {
|
||||
bindingset[this]
|
||||
SinkElement() { any() }
|
||||
|
||||
/**
|
||||
* Holds if this element is a flow sink of kind `kind`, where data
|
||||
* flows in as described by `input`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate isSink(string input, string kind, Provenance provenance, string model);
|
||||
}
|
||||
|
||||
private signature predicate hasKindSig(string kind);
|
||||
|
||||
signature class NeutralCallableSig extends SummarizedCallableBaseFinal {
|
||||
@@ -488,6 +536,10 @@ module Make<
|
||||
or
|
||||
c.propagatesFlow(_, spec, _, _)
|
||||
)
|
||||
or
|
||||
any(SourceElement s).isSource(spec, _, _, _)
|
||||
or
|
||||
any(SinkElement s).isSink(spec, _, _, _)
|
||||
}
|
||||
|
||||
import AccessPathSyntax::AccessPath<summarySpec/1>
|
||||
@@ -837,9 +889,57 @@ module Make<
|
||||
outputState(c, s) and s = SummaryComponentStack::argument(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate sourceOutputStateEntry(
|
||||
SourceElement source, SummaryComponentStack s, string kind, string model
|
||||
) {
|
||||
exists(string outSpec |
|
||||
source.isSource(outSpec, kind, _, model) and
|
||||
External::interpretSpec(outSpec, s)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate sourceOutputState(
|
||||
SourceElement source, SummaryComponentStack s, string kind, string model
|
||||
) {
|
||||
sourceOutputStateEntry(source, s, kind, model)
|
||||
or
|
||||
exists(SummaryComponentStack out |
|
||||
sourceOutputState(source, out, kind, model) and
|
||||
out.head() = TContentSummaryComponent(_) and
|
||||
s = out.tail()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate sinkInputStateExit(
|
||||
SinkElement sink, SummaryComponentStack s, string kind, string model
|
||||
) {
|
||||
exists(string inSpec |
|
||||
sink.isSink(inSpec, kind, _, model) and
|
||||
External::interpretSpec(inSpec, s)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate sinkInputState(
|
||||
SinkElement sink, SummaryComponentStack s, string kind, string model
|
||||
) {
|
||||
sinkInputStateExit(sink, s, kind, model)
|
||||
or
|
||||
exists(SummaryComponentStack inp |
|
||||
sinkInputState(sink, inp, kind, model) and
|
||||
inp.head() = TContentSummaryComponent(_) and
|
||||
s = inp.tail()
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TSummaryNodeState =
|
||||
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) }
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or
|
||||
TSourceOutputState(SummaryComponentStack s) { sourceOutputState(_, s, _, _) } or
|
||||
TSinkInputState(SummaryComponentStack s) { sinkInputState(_, s, _, _) }
|
||||
|
||||
/**
|
||||
* A state used to break up (complex) flow summaries into atomic flow steps.
|
||||
@@ -875,6 +975,24 @@ module Make<
|
||||
outputState(c, s)
|
||||
}
|
||||
|
||||
/** Holds if this state is a valid output state for `source`. */
|
||||
pragma[nomagic]
|
||||
predicate isSourceOutputState(
|
||||
SourceElement source, SummaryComponentStack s, string kind, string model
|
||||
) {
|
||||
sourceOutputState(source, s, kind, model) and
|
||||
this = TSourceOutputState(s)
|
||||
}
|
||||
|
||||
/** Holds if this state is a valid input state for `sink`. */
|
||||
pragma[nomagic]
|
||||
predicate isSinkInputState(
|
||||
SinkElement sink, SummaryComponentStack s, string kind, string model
|
||||
) {
|
||||
sinkInputState(sink, s, kind, model) and
|
||||
this = TSinkInputState(s)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this state. */
|
||||
string toString() {
|
||||
exists(SummaryComponentStack s |
|
||||
@@ -886,6 +1004,16 @@ module Make<
|
||||
this = TSummaryNodeOutputState(s) and
|
||||
result = "to write: " + s
|
||||
)
|
||||
or
|
||||
exists(SummaryComponentStack s |
|
||||
this = TSourceOutputState(s) and
|
||||
result = "to write source: " + s
|
||||
)
|
||||
or
|
||||
exists(SummaryComponentStack s |
|
||||
this = TSinkInputState(s) and
|
||||
result = "read sink: " + s
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,12 +1023,24 @@ module Make<
|
||||
} or
|
||||
TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) {
|
||||
summaryParameterNodeRange(c, pos)
|
||||
} or
|
||||
TSourceOutputNode(SourceElement source, SummaryNodeState state, string kind, string model) {
|
||||
state.isSourceOutputState(source, _, kind, model)
|
||||
} or
|
||||
TSinkInputNode(SinkElement sink, SummaryNodeState state, string kind, string model) {
|
||||
state.isSinkInputState(sink, _, kind, model)
|
||||
}
|
||||
|
||||
abstract class SummaryNode extends TSummaryNode {
|
||||
abstract string toString();
|
||||
|
||||
abstract SummarizedCallable getSummarizedCallable();
|
||||
|
||||
abstract SourceElement getSourceElement();
|
||||
|
||||
abstract SinkElement getSinkElement();
|
||||
|
||||
predicate isHidden() { any() }
|
||||
}
|
||||
|
||||
private class SummaryInternalNode extends SummaryNode, TSummaryInternalNode {
|
||||
@@ -912,6 +1052,10 @@ module Make<
|
||||
override string toString() { result = "[summary] " + state + " in " + c }
|
||||
|
||||
override SummarizedCallable getSummarizedCallable() { result = c }
|
||||
|
||||
override SourceElement getSourceElement() { none() }
|
||||
|
||||
override SinkElement getSinkElement() { none() }
|
||||
}
|
||||
|
||||
private class SummaryParamNode extends SummaryNode, TSummaryParameterNode {
|
||||
@@ -923,6 +1067,107 @@ module Make<
|
||||
override string toString() { result = "[summary param] " + pos + " in " + c }
|
||||
|
||||
override SummarizedCallable getSummarizedCallable() { result = c }
|
||||
|
||||
override SourceElement getSourceElement() { none() }
|
||||
|
||||
override SinkElement getSinkElement() { none() }
|
||||
}
|
||||
|
||||
class SourceOutputNode extends SummaryNode, TSourceOutputNode {
|
||||
private SourceElement source_;
|
||||
private SummaryNodeState state_;
|
||||
private string kind_;
|
||||
private string model_;
|
||||
|
||||
SourceOutputNode() { this = TSourceOutputNode(source_, state_, kind_, model_) }
|
||||
|
||||
/**
|
||||
* Holds if this node is an entry node, i.e. before any stores have been performed.
|
||||
*
|
||||
* This node should be used as the actual source node in data flow configurations.
|
||||
*/
|
||||
predicate isEntry(string kind, string model) {
|
||||
model = model_ and
|
||||
exists(SummaryComponentStack out |
|
||||
sourceOutputStateEntry(source_, out, kind, model_) and
|
||||
state_.isSourceOutputState(source_, out, kind, model_)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is an exit node, i.e. after all stores have been performed.
|
||||
*
|
||||
* A local flow step should be added from this node to a data flow node representing
|
||||
* `sc` inside `source`.
|
||||
*/
|
||||
predicate isExit(SourceElement source, SummaryComponent sc, string model) {
|
||||
source = source_ and
|
||||
model = model_ and
|
||||
state_.isSourceOutputState(source, TSingletonSummaryComponentStack(sc), _, model)
|
||||
}
|
||||
|
||||
override predicate isHidden() { not this.isEntry(_, _) }
|
||||
|
||||
override string toString() {
|
||||
if this.isEntry(_, _)
|
||||
then result = source_.toString()
|
||||
else result = "[source] " + state_ + " at " + source_
|
||||
}
|
||||
|
||||
override SummarizedCallable getSummarizedCallable() { none() }
|
||||
|
||||
override SourceElement getSourceElement() { result = source_ }
|
||||
|
||||
override SinkElement getSinkElement() { none() }
|
||||
}
|
||||
|
||||
class SinkInputNode extends SummaryNode, TSinkInputNode {
|
||||
private SinkElement sink_;
|
||||
private SummaryNodeState state_;
|
||||
private string kind_;
|
||||
private string model_;
|
||||
|
||||
SinkInputNode() { this = TSinkInputNode(sink_, state_, kind_, model_) }
|
||||
|
||||
/**
|
||||
* Holds if this node is an entry node, i.e. before any reads have been performed.
|
||||
*
|
||||
* A local flow step should be added to this node from a data flow node representing
|
||||
* `sc` inside `sink`.
|
||||
*/
|
||||
predicate isEntry(SinkElement sink, SummaryComponent sc, string model) {
|
||||
sink = sink_ and
|
||||
model = model_ and
|
||||
state_.isSinkInputState(sink, TSingletonSummaryComponentStack(sc), _, model)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is an exit node, i.e. after all reads have been performed.
|
||||
*
|
||||
* This node should be used as the actual sink node in data flow configurations.
|
||||
*/
|
||||
predicate isExit(string kind, string model) {
|
||||
kind = kind_ and
|
||||
model = model_ and
|
||||
exists(SummaryComponentStack inp |
|
||||
sinkInputStateExit(sink_, inp, kind, model_) and
|
||||
state_.isSinkInputState(sink_, inp, kind, model_)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isHidden() { not this.isExit(_, _) }
|
||||
|
||||
override string toString() {
|
||||
if this.isExit(_, _)
|
||||
then result = sink_.toString()
|
||||
else result = "[sink] " + state_ + " at " + sink_
|
||||
}
|
||||
|
||||
override SummarizedCallable getSummarizedCallable() { none() }
|
||||
|
||||
override SourceElement getSourceElement() { none() }
|
||||
|
||||
override SinkElement getSinkElement() { result = sink_ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -967,6 +1212,22 @@ module Make<
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SummaryNode sourceElementOutputState(SourceElement source, SummaryComponentStack s) {
|
||||
exists(SummaryNodeState state, string kind, string model |
|
||||
state.isSourceOutputState(source, s, kind, model) and
|
||||
result = TSourceOutputNode(source, state, kind, model)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SummaryNode sinkElementInputState(SinkElement sink, SummaryComponentStack s) {
|
||||
exists(SummaryNodeState state, string kind, string model |
|
||||
state.isSinkInputState(sink, s, kind, model) and
|
||||
result = TSinkInputNode(sink, state, kind, model)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a write targets `post`, which is a post-update node for a
|
||||
* parameter at position `pos` in `c`.
|
||||
@@ -1090,6 +1351,10 @@ module Make<
|
||||
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk);
|
||||
|
||||
DataFlowType getSyntheticGlobalType(SyntheticGlobal sg);
|
||||
|
||||
DataFlowType getSourceType(SourceBase source, SummaryComponent sc);
|
||||
|
||||
DataFlowType getSinkType(SinkBase sink, SummaryComponent sc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1168,12 +1433,54 @@ module Make<
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(SourceElement source |
|
||||
exists(SummaryComponent sc |
|
||||
n.(SourceOutputNode).isExit(source, sc, _) and
|
||||
result = getSourceType(source, sc)
|
||||
)
|
||||
or
|
||||
exists(SummaryComponentStack s, ContentSet cont |
|
||||
n = sourceElementOutputState(source, s) and
|
||||
s.head() = TContentSummaryComponent(cont) and
|
||||
result = getContentType(cont)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(SinkElement sink |
|
||||
exists(SummaryComponent sc |
|
||||
n.(SinkInputNode).isEntry(sink, sc, _) and
|
||||
result = getSinkType(sink, sc)
|
||||
)
|
||||
or
|
||||
exists(SummaryComponentStack s, ContentSet cont |
|
||||
n = sinkElementInputState(sink, s) and
|
||||
s.head() = TContentSummaryComponent(cont) and
|
||||
result = getContentType(cont)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
signature module StepsInputSig {
|
||||
/** Gets a call that targets summarized callable `sc`. */
|
||||
DataFlowCall getACall(SummarizedCallable sc);
|
||||
|
||||
/**
|
||||
* Gets a data flow node corresponding to the `sc` part of `source`.
|
||||
*
|
||||
* `sc` is typically `ReturnValue` and the result is the node that
|
||||
* represents the return value of `source`.
|
||||
*/
|
||||
Node getSourceNode(SourceBase source, SummaryComponent sc);
|
||||
|
||||
/**
|
||||
* Gets a data flow node corresponding to the `sc` part of `sink`.
|
||||
*
|
||||
* `sc` is typically `Argument[i]` and the result is the node that
|
||||
* represents the `i`th argument of `sink`.
|
||||
*/
|
||||
Node getSinkNode(SinkBase sink, SummaryComponent sc);
|
||||
}
|
||||
|
||||
/** Provides a compilation of flow summaries to atomic data-flow steps. */
|
||||
@@ -1207,6 +1514,20 @@ module Make<
|
||||
)
|
||||
}
|
||||
|
||||
predicate sourceLocalStep(SourceOutputNode nodeFrom, Node nodeTo, string model) {
|
||||
exists(SummaryComponent sc, SourceElement source |
|
||||
nodeFrom.isExit(source, sc, model) and
|
||||
nodeTo = StepsInput::getSourceNode(source, sc)
|
||||
)
|
||||
}
|
||||
|
||||
predicate sinkLocalStep(Node nodeFrom, SinkInputNode nodeTo, string model) {
|
||||
exists(SummaryComponent sc, SinkElement sink |
|
||||
nodeFrom = StepsInput::getSinkNode(sink, sc) and
|
||||
nodeTo.isEntry(sink, sc, model)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the value of `succ` is uniquely determined by the value of `pred`. */
|
||||
predicate summaryLocalMustFlowStep(SummaryNode pred, SummaryNode succ) {
|
||||
pred = unique(SummaryNode n1 | summaryLocalStep(n1, succ, true, _))
|
||||
@@ -1222,6 +1543,12 @@ module Make<
|
||||
succ = summaryNodeInputState(sc, s) and
|
||||
SummaryComponent::content(c) = s.head()
|
||||
)
|
||||
or
|
||||
exists(SinkElement sink, SummaryComponentStack s |
|
||||
pred = sinkElementInputState(sink, s.tail()) and
|
||||
succ = sinkElementInputState(sink, s) and
|
||||
SummaryComponent::content(c) = s.head()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1234,6 +1561,12 @@ module Make<
|
||||
succ = summaryNodeOutputState(sc, s.tail()) and
|
||||
SummaryComponent::content(c) = s.head()
|
||||
)
|
||||
or
|
||||
exists(SourceElement source, SummaryComponentStack s |
|
||||
pred = sourceElementOutputState(source, s) and
|
||||
succ = sourceElementOutputState(source, s.tail()) and
|
||||
SummaryComponent::content(c) = s.head()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,14 @@ private import DataFlowImplCommon
|
||||
private import codeql.swift.dataflow.ExternalFlow
|
||||
|
||||
module Input implements InputSig<Location, DataFlowImplSpecific::SwiftDataFlow> {
|
||||
private import codeql.util.Void
|
||||
|
||||
class SummarizedCallableBase = Function;
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result instanceof ThisArgumentPosition }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { result instanceof NormalReturnKind }
|
||||
@@ -106,6 +112,10 @@ private import Make<Location, DataFlowImplSpecific::SwiftDataFlow, Input> as Imp
|
||||
|
||||
private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
module SourceSinkInterpretationInput implements
|
||||
|
||||
Reference in New Issue
Block a user