mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Rust: Base DataFlow::Node on AST instead of CFG
This commit is contained in:
@@ -25,7 +25,7 @@ import codeql.rust.dataflow.TaintTracking
|
||||
module ConstantPasswordConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
// `node` is a string literal
|
||||
node.asExpr().getExpr() instanceof StringLiteralExpr
|
||||
node.asExpr() instanceof StringLiteralExpr
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
@@ -34,7 +34,7 @@ module ConstantPasswordConfig implements DataFlow::ConfigSig {
|
||||
call.getStaticTarget() = target and
|
||||
v.getParameter() = target.getParam(argIndex) and
|
||||
v.getText().matches("pass%") and
|
||||
call.getArg(argIndex) = node.asExpr().getExpr()
|
||||
call.getArg(argIndex) = node.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ module SqlInjectionConfig implements DataFlow::ConfigSig {
|
||||
// `node` is the first argument of a call to `sqlx_core::query::query`
|
||||
exists(CallExpr call |
|
||||
call.getStaticTarget().getCanonicalPath() = "sqlx_core::query::query" and
|
||||
call.getArg(0) = node.asExpr().getExpr()
|
||||
call.getArg(0) = node.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
* provide concrete subclasses.
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.internal.DataFlowImpl
|
||||
private import codeql.Locations
|
||||
private import codeql.threatmodels.ThreatModels
|
||||
private import codeql.rust.Frameworks
|
||||
private import codeql.rust.dataflow.FlowSource
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.rust.controlflow.CfgNodes as CfgNodes
|
||||
private import codeql.concepts.ConceptsShared
|
||||
|
||||
private module ConceptsShared = ConceptsMake<Location, RustDataFlow>;
|
||||
@@ -345,16 +344,16 @@ module Path {
|
||||
SafeAccessCheck() { this = DataFlow::BarrierGuard<safeAccessCheck/3>::getABarrierNode() }
|
||||
}
|
||||
|
||||
private predicate safeAccessCheck(CfgNodes::AstCfgNode g, Cfg::CfgNode node, boolean branch) {
|
||||
g.(SafeAccessCheck::Range).checks(node, branch)
|
||||
private predicate safeAccessCheck(AstNode g, Expr e, boolean branch) {
|
||||
g.(SafeAccessCheck::Range).checks(e, branch)
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new path safety checks. */
|
||||
module SafeAccessCheck {
|
||||
/** A data-flow node that checks that a path is safe to access in some way, for example by having a controlled prefix. */
|
||||
abstract class Range extends CfgNodes::AstCfgNode {
|
||||
/** Holds if this guard validates `node` upon evaluating to `branch`. */
|
||||
abstract predicate checks(Cfg::CfgNode node, boolean branch);
|
||||
abstract class Range extends AstNode {
|
||||
/** Holds if this guard validates `e` upon evaluating to `branch`. */
|
||||
abstract predicate checks(Expr e, boolean branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ private import codeql.dataflow.DataFlow
|
||||
private import internal.DataFlowImpl as DataFlowImpl
|
||||
private import internal.Node as Node
|
||||
private import internal.Content as Content
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.rust.controlflow.CfgNodes as CfgNodes
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and global
|
||||
@@ -68,7 +66,7 @@ module DataFlow {
|
||||
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
|
||||
* the argument `x`.
|
||||
*/
|
||||
signature predicate guardChecksSig(CfgNodes::AstCfgNode g, Cfg::CfgNode e, boolean branch);
|
||||
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch);
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an expression.
|
||||
|
||||
@@ -9,7 +9,6 @@ module Ssa {
|
||||
private import rust
|
||||
private import codeql.rust.controlflow.BasicBlocks
|
||||
private import codeql.rust.controlflow.ControlFlowGraph
|
||||
private import codeql.rust.controlflow.CfgNodes
|
||||
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import internal.SsaImpl as SsaImpl
|
||||
|
||||
@@ -51,7 +50,7 @@ module Ssa {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final CfgNode getARead() { result = SsaImpl::getARead(this) }
|
||||
final Expr getARead() { result = SsaImpl::getARead(this) }
|
||||
|
||||
/**
|
||||
* Gets a first control flow node that reads the value of this SSA definition.
|
||||
@@ -80,7 +79,7 @@ module Ssa {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final CfgNode getAFirstRead() { SsaImpl::firstRead(this, result) }
|
||||
final Expr getAFirstRead() { SsaImpl::firstRead(this, result) }
|
||||
|
||||
/**
|
||||
* Holds if `read1` and `read2` are adjacent reads of this SSA definition.
|
||||
@@ -108,7 +107,7 @@ module Ssa {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final predicate hasAdjacentReads(CfgNode read1, CfgNode read2) {
|
||||
final predicate hasAdjacentReads(Expr read1, Expr read2) {
|
||||
SsaImpl::adjacentReadPair(this, read1, read2)
|
||||
}
|
||||
|
||||
@@ -168,28 +167,28 @@ module Ssa {
|
||||
* ```
|
||||
*/
|
||||
class WriteDefinition extends Definition, SsaImpl::WriteDefinition {
|
||||
private CfgNode write;
|
||||
private AstNode write;
|
||||
|
||||
WriteDefinition() {
|
||||
exists(BasicBlock bb, int i, Variable v, CfgNode n |
|
||||
exists(BasicBlock bb, int i, Variable v, AstNode n |
|
||||
this.definesAt(v, bb, i) and
|
||||
SsaImpl::variableWriteActual(bb, i, v, n)
|
||||
SsaImpl::variableWriteActual(bb, i, v, n.getACfgNode())
|
||||
|
|
||||
write.(VariableAccessCfgNode).getAccess().getVariable() = v and
|
||||
write.(VariableAccess).getVariable() = v and
|
||||
(
|
||||
write = n.(AssignmentExprCfgNode).getAWriteAccess()
|
||||
write = n.(AssignmentExpr).getAWriteAccess()
|
||||
or
|
||||
write = n.(CompoundAssignmentExprCfgNode).getLhs()
|
||||
write = n.(CompoundAssignmentExpr).getLhs()
|
||||
)
|
||||
or
|
||||
not n instanceof AssignmentExprCfgNode and
|
||||
not n instanceof CompoundAssignmentExprCfgNode and
|
||||
not n instanceof AssignmentExpr and
|
||||
not n instanceof CompoundAssignmentExpr and
|
||||
write = n
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying write access. */
|
||||
final CfgNode getWriteAccess() { result = write }
|
||||
final AstNode getWriteAccess() { result = write }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition assigns `value` to the underlying
|
||||
@@ -199,19 +198,19 @@ module Ssa {
|
||||
* `let` statement, `let x = value`. Note that patterns on the lhs. are
|
||||
* currently not supported.
|
||||
*/
|
||||
predicate assigns(ExprCfgNode value) {
|
||||
exists(AssignmentExprCfgNode ae |
|
||||
predicate assigns(Expr value) {
|
||||
exists(AssignmentExpr ae |
|
||||
ae.getLhs() = write and
|
||||
ae.getRhs() = value
|
||||
)
|
||||
or
|
||||
exists(IdentPatCfgNode pat | pat.getName() = write |
|
||||
exists(LetStmtCfgNode ls |
|
||||
exists(IdentPat pat | pat.getName() = write |
|
||||
exists(LetStmt ls |
|
||||
pat = ls.getPat() and
|
||||
ls.getInitializer() = value
|
||||
)
|
||||
or
|
||||
exists(LetExprCfgNode le |
|
||||
exists(LetExpr le |
|
||||
pat = le.getPat() and
|
||||
le.getScrutinee() = value
|
||||
)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.controlflow.CfgNodes
|
||||
private import codeql.rust.frameworks.stdlib.Builtins
|
||||
private import DataFlowImpl
|
||||
|
||||
@@ -22,7 +21,7 @@ abstract class Content extends TContent {
|
||||
abstract class FieldContent extends Content {
|
||||
/** Gets an access to this field. */
|
||||
pragma[nomagic]
|
||||
abstract FieldExprCfgNode getAnAccess();
|
||||
abstract FieldExpr getAnAccess();
|
||||
}
|
||||
|
||||
/** A tuple field belonging to either a variant or a struct. */
|
||||
@@ -41,7 +40,7 @@ class TupleFieldContent extends FieldContent, TTupleFieldContent {
|
||||
/** Holds if this field belongs to a struct. */
|
||||
predicate isStructField(Struct s, int pos) { field.isStructField(s, pos) }
|
||||
|
||||
override FieldExprCfgNode getAnAccess() { field = result.getFieldExpr().getTupleField() }
|
||||
override FieldExpr getAnAccess() { field = result.getTupleField() }
|
||||
|
||||
final override string toString() {
|
||||
exists(Variant v, int pos, string vname |
|
||||
@@ -74,7 +73,7 @@ class StructFieldContent extends FieldContent, TStructFieldContent {
|
||||
/** Holds if this field belongs to a struct. */
|
||||
predicate isStructField(Struct s, string name) { field.isStructField(s, name) }
|
||||
|
||||
override FieldExprCfgNode getAnAccess() { field = result.getFieldExpr().getStructField() }
|
||||
override FieldExpr getAnAccess() { field = result.getStructField() }
|
||||
|
||||
final override string toString() {
|
||||
exists(Variant v, string name, string vname |
|
||||
@@ -153,7 +152,7 @@ final class TuplePositionContent extends FieldContent, TTuplePositionContent {
|
||||
/** Gets the index of this tuple position. */
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override FieldExprCfgNode getAnAccess() {
|
||||
override FieldExpr getAnAccess() {
|
||||
// TODO: limit to tuple types
|
||||
result.getIdentifier().getText().toInt() = pos
|
||||
}
|
||||
|
||||
@@ -29,17 +29,6 @@ private module Input implements InputSig<Location, RustDataFlow> {
|
||||
}
|
||||
|
||||
predicate missingLocationExclude(RustDataFlow::Node n) { not exists(n.asExpr().getLocation()) }
|
||||
|
||||
predicate multipleArgumentCallExclude(Node::ArgumentNode arg, DataFlowCall call) {
|
||||
// An argument such as `x` in `if !x { ... }` has two successors (and hence
|
||||
// two calls); one for each Boolean outcome of `x`.
|
||||
exists(CfgNodes::ExprCfgNode n |
|
||||
arg.isArgumentOf(call, _) and
|
||||
n = call.asCallCfgNode() and
|
||||
arg.asExpr().getASuccessor(any(ConditionalSuccessor c)).getASuccessor*() = n and
|
||||
n.getASplit() instanceof ConditionalCompletionSplitting::ConditionalCompletionSplit
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeConsistency<Location, RustDataFlow, RustTaintTracking, Input>
|
||||
|
||||
@@ -14,7 +14,6 @@ private import codeql.rust.controlflow.internal.Scope as Scope
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import codeql.rust.internal.TypeInference as TypeInference
|
||||
private import codeql.rust.controlflow.ControlFlowGraph
|
||||
private import codeql.rust.controlflow.CfgNodes
|
||||
private import codeql.rust.dataflow.Ssa
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
private import Node
|
||||
@@ -60,7 +59,7 @@ final class DataFlowCallable extends TDataFlowCallable {
|
||||
|
||||
final class DataFlowCall extends TDataFlowCall {
|
||||
/** Gets the underlying call in the CFG, if any. */
|
||||
CallCfgNode asCallCfgNode() { this = TCall(result) }
|
||||
Call asCall() { this = TCall(result) }
|
||||
|
||||
predicate isSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
@@ -69,13 +68,13 @@ final class DataFlowCall extends TDataFlowCall {
|
||||
}
|
||||
|
||||
DataFlowCallable getEnclosingCallable() {
|
||||
result.asCfgScope() = this.asCallCfgNode().getExpr().getEnclosingCfgScope()
|
||||
result.asCfgScope() = this.asCall().getEnclosingCfgScope()
|
||||
or
|
||||
this.isSummaryCall(result.asSummarizedCallable(), _)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = this.asCallCfgNode().toString()
|
||||
result = this.asCall().toString()
|
||||
or
|
||||
exists(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
@@ -85,7 +84,7 @@ final class DataFlowCall extends TDataFlowCall {
|
||||
)
|
||||
}
|
||||
|
||||
Location getLocation() { result = this.asCallCfgNode().getLocation() }
|
||||
Location getLocation() { result = this.asCall().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,13 +145,13 @@ final class ArgumentPosition extends ParameterPosition {
|
||||
* Note that this does not hold for the receiever expression of a method call
|
||||
* as the synthetic `ReceiverNode` is the argument for the `self` parameter.
|
||||
*/
|
||||
predicate isArgumentForCall(ExprCfgNode arg, CallCfgNode call, ParameterPosition pos) {
|
||||
predicate isArgumentForCall(Expr arg, Call call, ParameterPosition pos) {
|
||||
// TODO: Handle index expressions as calls in data flow.
|
||||
not call.getCall() instanceof IndexExpr and
|
||||
not call instanceof IndexExpr and
|
||||
(
|
||||
call.getPositionalArgument(pos.getPosition()) = arg
|
||||
or
|
||||
call.getReceiver() = arg and pos.isSelf() and not call.getCall().receiverImplicitlyBorrowed()
|
||||
call.getReceiver() = arg and pos.isSelf() and not call.receiverImplicitlyBorrowed()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -181,19 +180,24 @@ module SsaFlow {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a node that may execute last in `n`, and which, when it executes last,
|
||||
* will be the value of `n`.
|
||||
* Gets a node that may execute last in `e`, and which, when it executes last,
|
||||
* will be the value of `e`.
|
||||
*/
|
||||
private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
|
||||
e = any(IfExprCfgNode n | result = [n.getThen(), n.getElse()]) or
|
||||
result = e.(LoopExprCfgNode).getLoopBody() or
|
||||
result = e.(ReturnExprCfgNode).getExpr() or
|
||||
result = e.(BreakExprCfgNode).getExpr() or
|
||||
result = e.(BlockExprCfgNode).getTailExpr() or
|
||||
result = e.(MacroBlockExprCfgNode).getTailExpr() or
|
||||
result = e.(MatchExprCfgNode).getArmExpr(_) or
|
||||
result = e.(MacroExprCfgNode).getMacroCall().(MacroCallCfgNode).getExpandedNode() or
|
||||
result.(BreakExprCfgNode).getTarget() = e
|
||||
private Expr getALastEvalNode(Expr e) {
|
||||
e = any(IfExpr n | result = [n.getThen(), n.getElse()]) or
|
||||
result = e.(LoopExpr).getLoopBody() or
|
||||
result = e.(ReturnExpr).getExpr() or
|
||||
result = e.(BreakExpr).getExpr() or
|
||||
e =
|
||||
any(BlockExpr be |
|
||||
not be.isAsync() and
|
||||
result = be.getTailExpr()
|
||||
) or
|
||||
result = e.(MacroBlockExpr).getTailExpr() or
|
||||
result = e.(MatchExpr).getAnArm().getExpr() or
|
||||
result = e.(MacroExpr).getMacroCall().getMacroCallExpansion() or
|
||||
result.(BreakExpr).getTarget() = e or
|
||||
result = e.(ParenExpr).getExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,11 +215,11 @@ private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
|
||||
* we add a reverse flow step from `[post] { foo(); &mut a}` to `[post] &mut a`,
|
||||
* in order for the side-effect of `set_data` to reach `&mut a`.
|
||||
*/
|
||||
ExprCfgNode getPostUpdateReverseStep(ExprCfgNode e, boolean preservesValue) {
|
||||
Expr getPostUpdateReverseStep(Expr e, boolean preservesValue) {
|
||||
result = getALastEvalNode(e) and
|
||||
preservesValue = true
|
||||
or
|
||||
result = e.(CastExprCfgNode).getExpr() and
|
||||
result = e.(CastExpr).getExpr() and
|
||||
preservesValue = false
|
||||
}
|
||||
|
||||
@@ -236,48 +240,48 @@ module LocalFlow {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||
nodeFrom.getCfgNode() = getALastEvalNode(nodeTo.getCfgNode())
|
||||
nodeFrom.asExpr() = getALastEvalNode(nodeTo.asExpr())
|
||||
or
|
||||
// An edge from the right-hand side of a let statement to the left-hand side.
|
||||
exists(LetStmtCfgNode s |
|
||||
nodeFrom.getCfgNode() = s.getInitializer() and
|
||||
nodeTo.getCfgNode() = s.getPat()
|
||||
exists(LetStmt s |
|
||||
nodeFrom.asExpr() = s.getInitializer() and
|
||||
nodeTo.asPat() = s.getPat()
|
||||
)
|
||||
or
|
||||
// An edge from the right-hand side of a let expression to the left-hand side.
|
||||
exists(LetExprCfgNode e |
|
||||
nodeFrom.getCfgNode() = e.getScrutinee() and
|
||||
nodeTo.getCfgNode() = e.getPat()
|
||||
exists(LetExpr e |
|
||||
nodeFrom.asExpr() = e.getScrutinee() and
|
||||
nodeTo.asPat() = e.getPat()
|
||||
)
|
||||
or
|
||||
exists(IdentPatCfgNode p |
|
||||
exists(IdentPat p |
|
||||
not p.isRef() and
|
||||
nodeFrom.getCfgNode() = p and
|
||||
nodeTo.getCfgNode() = p.getName()
|
||||
nodeFrom.asPat() = p and
|
||||
nodeTo.(NameNode).getName() = p.getName()
|
||||
)
|
||||
or
|
||||
exists(SelfParamCfgNode self |
|
||||
nodeFrom.getCfgNode() = self and
|
||||
nodeTo.getCfgNode() = self.getName()
|
||||
exists(SelfParam self |
|
||||
nodeFrom.asParameter() = self and
|
||||
nodeTo.(NameNode).getName() = self.getName()
|
||||
)
|
||||
or
|
||||
// An edge from a pattern/expression to its corresponding SSA definition.
|
||||
nodeFrom.(AstCfgFlowNode).getCfgNode() =
|
||||
nodeFrom.(AstNodeNode).getAstNode() =
|
||||
nodeTo.(SsaNode).asDefinition().(Ssa::WriteDefinition).getWriteAccess()
|
||||
or
|
||||
nodeFrom.(SourceParameterNode).getParameter().(ParamCfgNode).getPat() = nodeTo.asPat()
|
||||
nodeFrom.(SourceParameterNode).getParameter().(Param).getPat() = nodeTo.asPat()
|
||||
or
|
||||
exists(AssignmentExprCfgNode a |
|
||||
a.getRhs() = nodeFrom.getCfgNode() and
|
||||
a.getLhs() = nodeTo.getCfgNode()
|
||||
exists(AssignmentExpr a |
|
||||
a.getRhs() = nodeFrom.asExpr() and
|
||||
a.getLhs() = nodeTo.asExpr()
|
||||
)
|
||||
or
|
||||
exists(MatchExprCfgNode match |
|
||||
exists(MatchExpr match |
|
||||
nodeFrom.asExpr() = match.getScrutinee() and
|
||||
nodeTo.asPat() = match.getArmPat(_)
|
||||
nodeTo.asPat() = match.getAnArm().getPat()
|
||||
)
|
||||
or
|
||||
nodeFrom.asPat().(OrPatCfgNode).getAPat() = nodeTo.asPat()
|
||||
nodeFrom.asPat().(OrPat).getAPat() = nodeTo.asPat()
|
||||
or
|
||||
// Simple value step from receiver expression to receiver node, in case
|
||||
// there is no implicit deref or borrow operation.
|
||||
@@ -305,12 +309,10 @@ predicate lambdaCreationExpr(Expr creation) {
|
||||
* Holds if `call` is a lambda call of kind `kind` where `receiver` is the
|
||||
* invoked expression.
|
||||
*/
|
||||
predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode receiver) {
|
||||
predicate lambdaCallExpr(CallExpr call, LambdaCallKind kind, Expr receiver) {
|
||||
receiver = call.getFunction() and
|
||||
// All calls to complex expressions and local variable accesses are lambda call.
|
||||
exists(Expr f | f = receiver.getExpr() |
|
||||
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
|
||||
) and
|
||||
(receiver instanceof PathExpr implies receiver = any(Variable v).getAnAccess()) and
|
||||
exists(kind)
|
||||
}
|
||||
|
||||
@@ -379,19 +381,27 @@ module RustDataFlow implements InputSig<Location> {
|
||||
node instanceof CaptureNode or
|
||||
node instanceof ClosureParameterNode or
|
||||
node instanceof ReceiverNode or
|
||||
node instanceof ReceiverPostUpdateNode
|
||||
node.asExpr() instanceof ParenExpr or
|
||||
nodeIsHidden(node.(PostUpdateNode).getPreUpdateNode())
|
||||
}
|
||||
|
||||
private Expr stripParens(Expr e) {
|
||||
not e instanceof ParenExpr and
|
||||
result = e
|
||||
or
|
||||
result = stripParens(e.(ParenExpr).getExpr())
|
||||
}
|
||||
|
||||
predicate neverSkipInPathGraph(Node node) {
|
||||
node.(Node::Node).getCfgNode() = any(LetStmtCfgNode s).getPat()
|
||||
node.(Node::Node).asPat() = any(LetStmt s).getPat()
|
||||
or
|
||||
node.(Node::Node).getCfgNode() = any(LetExprCfgNode e).getPat()
|
||||
node.(Node::Node).asPat() = any(LetExpr e).getPat()
|
||||
or
|
||||
node.(Node::Node).getCfgNode() = any(AssignmentExprCfgNode a).getLhs()
|
||||
node.(Node::Node).asExpr() = stripParens(any(AssignmentExpr a).getLhs())
|
||||
or
|
||||
exists(MatchExprCfgNode match |
|
||||
node.asExpr() = match.getScrutinee() or
|
||||
node.asExpr() = match.getArmPat(_)
|
||||
exists(MatchExpr match |
|
||||
node.asExpr() = stripParens(match.getScrutinee()) or
|
||||
node.asPat() = match.getAnArm().getPat()
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::sourceLocalStep(_, node, _)
|
||||
@@ -399,7 +409,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
FlowSummaryImpl::Private::Steps::sinkLocalStep(node, _, _)
|
||||
}
|
||||
|
||||
class DataFlowExpr = ExprCfgNode;
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
/** Gets the node corresponding to `e`. */
|
||||
Node exprNode(DataFlowExpr e) { result.asExpr() = e }
|
||||
@@ -412,7 +422,7 @@ 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.asCallCfgNode().getCall() |
|
||||
exists(Call c | c = call.asCall() |
|
||||
result.asCfgScope() = c.getARuntimeTarget()
|
||||
or
|
||||
exists(SummarizedCallable sc, Function staticTarget |
|
||||
@@ -511,79 +521,79 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate implicitDerefToReceiver(Node node1, ReceiverNode node2, ReferenceContent c) {
|
||||
TypeInference::receiverHasImplicitDeref(node1.asExpr().getExpr()) and
|
||||
TypeInference::receiverHasImplicitDeref(node1.asExpr()) and
|
||||
node1.asExpr() = node2.getReceiver() and
|
||||
exists(c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate implicitBorrowToReceiver(Node node1, ReceiverNode node2, ReferenceContent c) {
|
||||
TypeInference::receiverHasImplicitBorrow(node1.asExpr().getExpr()) and
|
||||
TypeInference::receiverHasImplicitBorrow(node1.asExpr()) and
|
||||
node1.asExpr() = node2.getReceiver() and
|
||||
exists(c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate referenceExprToExpr(Node node1, Node node2, ReferenceContent c) {
|
||||
node1.asExpr() = node2.asExpr().(RefExprCfgNode).getExpr() and
|
||||
node1.asExpr() = node2.asExpr().(RefExpr).getExpr() and
|
||||
exists(c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate readContentStep(Node node1, Content c, Node node2) {
|
||||
exists(TupleStructPatCfgNode pat, int pos |
|
||||
exists(TupleStructPat pat, int pos |
|
||||
pat = node1.asPat() and
|
||||
node2.asPat() = pat.getField(pos) and
|
||||
c = TTupleFieldContent(pat.getTupleStructPat().getTupleField(pos))
|
||||
c = TTupleFieldContent(pat.getTupleField(pos))
|
||||
)
|
||||
or
|
||||
exists(TuplePatCfgNode pat, int pos |
|
||||
exists(TuplePat pat, int pos |
|
||||
pos = c.(TuplePositionContent).getPosition() and
|
||||
node1.asPat() = pat and
|
||||
node2.asPat() = pat.getField(pos)
|
||||
)
|
||||
or
|
||||
exists(StructPatCfgNode pat, string field |
|
||||
exists(StructPat pat, string field |
|
||||
pat = node1.asPat() and
|
||||
c = TStructFieldContent(pat.getStructPat().getStructField(field)) and
|
||||
node2.asPat() = pat.getFieldPat(field)
|
||||
c = TStructFieldContent(pat.getStructField(field)) and
|
||||
node2.asPat() = pat.getPatField(field).getPat()
|
||||
)
|
||||
or
|
||||
c instanceof ReferenceContent and
|
||||
node1.asPat().(RefPatCfgNode).getPat() = node2.asPat()
|
||||
node1.asPat().(RefPat).getPat() = node2.asPat()
|
||||
or
|
||||
exists(FieldExprCfgNode access |
|
||||
exists(FieldExpr access |
|
||||
node1.asExpr() = access.getContainer() and
|
||||
node2.asExpr() = access and
|
||||
access = c.(FieldContent).getAnAccess()
|
||||
)
|
||||
or
|
||||
exists(IndexExprCfgNode arr |
|
||||
exists(IndexExpr arr |
|
||||
c instanceof ElementContent and
|
||||
node1.asExpr() = arr.getBase() and
|
||||
node2.asExpr() = arr
|
||||
)
|
||||
or
|
||||
exists(ForExprCfgNode for |
|
||||
exists(ForExpr for |
|
||||
c instanceof ElementContent and
|
||||
node1.asExpr() = for.getIterable() and
|
||||
node2.asPat() = for.getPat()
|
||||
)
|
||||
or
|
||||
exists(SlicePatCfgNode pat |
|
||||
exists(SlicePat pat |
|
||||
c instanceof ElementContent and
|
||||
node1.asPat() = pat and
|
||||
node2.asPat() = pat.getAPat()
|
||||
)
|
||||
or
|
||||
exists(TryExprCfgNode try |
|
||||
exists(TryExpr try |
|
||||
node1.asExpr() = try.getExpr() and
|
||||
node2.asExpr() = try and
|
||||
c.(TupleFieldContent)
|
||||
.isVariantField([any(OptionEnum o).getSome(), any(ResultEnum r).getOk()], 0)
|
||||
)
|
||||
or
|
||||
exists(PrefixExprCfgNode deref |
|
||||
exists(PrefixExpr deref |
|
||||
c instanceof ReferenceContent and
|
||||
deref.getOperatorName() = "*" and
|
||||
node1.asExpr() = deref.getExpr() and
|
||||
@@ -597,7 +607,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
c instanceof FunctionCallReturnContent
|
||||
)
|
||||
or
|
||||
exists(AwaitExprCfgNode await |
|
||||
exists(AwaitExpr await |
|
||||
c instanceof FutureContent and
|
||||
node1.asExpr() = await.getExpr() and
|
||||
node2.asExpr() = await
|
||||
@@ -644,7 +654,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fieldAssignment(Node node1, Node node2, FieldContent c) {
|
||||
exists(AssignmentExprCfgNode assignment, FieldExprCfgNode access |
|
||||
exists(AssignmentExpr assignment, FieldExpr access |
|
||||
assignment.getLhs() = access and
|
||||
node1.asExpr() = assignment.getRhs() and
|
||||
node2.asExpr() = access.getContainer() and
|
||||
@@ -654,7 +664,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate referenceAssignment(Node node1, Node node2, ReferenceContent c) {
|
||||
exists(AssignmentExprCfgNode assignment, PrefixExprCfgNode deref |
|
||||
exists(AssignmentExpr assignment, PrefixExpr deref |
|
||||
assignment.getLhs() = deref and
|
||||
deref.getOperatorName() = "*" and
|
||||
node1.asExpr() = assignment.getRhs() and
|
||||
@@ -665,19 +675,19 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate storeContentStep(Node node1, Content c, Node node2) {
|
||||
exists(CallExprCfgNode call, int pos |
|
||||
node1.asExpr() = call.getArgument(pragma[only_bind_into](pos)) and
|
||||
exists(CallExpr call, int pos |
|
||||
node1.asExpr() = call.getArg(pragma[only_bind_into](pos)) and
|
||||
node2.asExpr() = call and
|
||||
c = TTupleFieldContent(call.getCallExpr().getTupleField(pragma[only_bind_into](pos)))
|
||||
c = TTupleFieldContent(call.getTupleField(pragma[only_bind_into](pos)))
|
||||
)
|
||||
or
|
||||
exists(StructExprCfgNode re, string field |
|
||||
c = TStructFieldContent(re.getStructExpr().getStructField(field)) and
|
||||
node1.asExpr() = re.getFieldExpr(field) and
|
||||
exists(StructExpr re, string field |
|
||||
c = TStructFieldContent(re.getStructField(field)) and
|
||||
node1.asExpr() = re.getFieldExpr(field).getExpr() and
|
||||
node2.asExpr() = re
|
||||
)
|
||||
or
|
||||
exists(TupleExprCfgNode tuple |
|
||||
exists(TupleExpr tuple |
|
||||
node1.asExpr() = tuple.getField(c.(TuplePositionContent).getPosition()) and
|
||||
node2.asExpr() = tuple
|
||||
)
|
||||
@@ -685,23 +695,23 @@ module RustDataFlow implements InputSig<Location> {
|
||||
c instanceof ElementContent and
|
||||
node1.asExpr() =
|
||||
[
|
||||
node2.asExpr().(ArrayRepeatExprCfgNode).getRepeatOperand(),
|
||||
node2.asExpr().(ArrayListExprCfgNode).getAnExpr()
|
||||
node2.asExpr().(ArrayRepeatExpr).getRepeatOperand(),
|
||||
node2.asExpr().(ArrayListExpr).getAnExpr()
|
||||
]
|
||||
or
|
||||
// Store from a `ref` identifier pattern into the contained name.
|
||||
exists(IdentPatCfgNode p |
|
||||
exists(IdentPat p |
|
||||
c instanceof ReferenceContent and
|
||||
p.isRef() and
|
||||
node1.asPat() = p and
|
||||
node2.(NameNode).asName() = p.getName()
|
||||
node2.(NameNode).getName() = p.getName()
|
||||
)
|
||||
or
|
||||
fieldAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
|
||||
or
|
||||
referenceAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
|
||||
or
|
||||
exists(AssignmentExprCfgNode assignment, IndexExprCfgNode index |
|
||||
exists(AssignmentExpr assignment, IndexExpr index |
|
||||
c instanceof ElementContent and
|
||||
assignment.getLhs() = index and
|
||||
node1.asExpr() = assignment.getRhs() and
|
||||
@@ -808,7 +818,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(kind) and
|
||||
exists(Expr e | e = creation.asExpr().getExpr() |
|
||||
exists(Expr e | e = creation.asExpr() |
|
||||
lambdaCreationExpr(e) and e = c.asCfgScope()
|
||||
or
|
||||
// A path expression, that resolves to a function, evaluates to a function
|
||||
@@ -825,9 +835,9 @@ module RustDataFlow implements InputSig<Location> {
|
||||
*/
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
(
|
||||
receiver.asExpr() = call.asCallCfgNode().(CallExprCfgNode).getFunction() and
|
||||
receiver.asExpr() = call.asCall().(CallExpr).getFunction() and
|
||||
// All calls to complex expressions and local variable accesses are lambda call.
|
||||
exists(Expr f | f = receiver.asExpr().getExpr() |
|
||||
exists(Expr f | f = receiver.asExpr() |
|
||||
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
|
||||
)
|
||||
or
|
||||
@@ -854,7 +864,7 @@ module VariableCapture {
|
||||
private import codeql.dataflow.VariableCapture as SharedVariableCapture
|
||||
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
private predicate closureFlowStep(ExprCfgNode e1, ExprCfgNode e2) {
|
||||
private predicate closureFlowStep(Expr e1, Expr e2) {
|
||||
Stages::DataFlowStage::ref() and
|
||||
e1 = getALastEvalNode(e2)
|
||||
or
|
||||
@@ -883,48 +893,48 @@ module VariableCapture {
|
||||
|
||||
CapturedParameter() { p = this.getParameter() }
|
||||
|
||||
SourceParameterNode getParameterNode() { result.getParameter().getParamBase() = p }
|
||||
SourceParameterNode getParameterNode() { result.getParameter() = p }
|
||||
}
|
||||
|
||||
class Expr extends CfgNode {
|
||||
predicate hasCfgNode(BasicBlocks::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
class Expr extends AstNode {
|
||||
predicate hasCfgNode(BasicBlocks::BasicBlock bb, int i) { this = bb.getNode(i).getAstNode() }
|
||||
}
|
||||
|
||||
class VariableWrite extends Expr {
|
||||
ExprCfgNode source;
|
||||
Expr source;
|
||||
CapturedVariable v;
|
||||
|
||||
VariableWrite() {
|
||||
exists(AssignmentExprCfgNode assign, Variable::VariableWriteAccess write |
|
||||
exists(AssignmentExpr assign, Variable::VariableWriteAccess write |
|
||||
this = assign and
|
||||
v = write.getVariable() and
|
||||
assign.getLhs().getExpr() = write and
|
||||
assign.getLhs() = write and
|
||||
assign.getRhs() = source
|
||||
)
|
||||
or
|
||||
exists(LetStmtCfgNode ls |
|
||||
this = ls and
|
||||
v.getPat() = ls.getPat().getPat() and
|
||||
ls.getInitializer() = source
|
||||
)
|
||||
this =
|
||||
any(LetStmt ls |
|
||||
v.getPat() = ls.getPat() and
|
||||
ls.getInitializer() = source
|
||||
)
|
||||
or
|
||||
exists(LetExprCfgNode le |
|
||||
this = le and
|
||||
v.getPat() = le.getPat().getPat() and
|
||||
le.getScrutinee() = source
|
||||
)
|
||||
this =
|
||||
any(LetExpr le |
|
||||
v.getPat() = le.getPat() and
|
||||
le.getScrutinee() = source
|
||||
)
|
||||
}
|
||||
|
||||
CapturedVariable getVariable() { result = v }
|
||||
|
||||
ExprCfgNode getSource() { result = source }
|
||||
Expr getSource() { result = source }
|
||||
}
|
||||
|
||||
class VariableRead extends Expr instanceof ExprCfgNode {
|
||||
class VariableRead extends Expr {
|
||||
CapturedVariable v;
|
||||
|
||||
VariableRead() {
|
||||
exists(VariableAccess read | this.getExpr() = read and v = read.getVariable() |
|
||||
exists(VariableAccess read | this = read and v = read.getVariable() |
|
||||
read instanceof VariableReadAccess
|
||||
or
|
||||
read = any(RefExpr re).getExpr()
|
||||
@@ -934,10 +944,10 @@ module VariableCapture {
|
||||
CapturedVariable getVariable() { result = v }
|
||||
}
|
||||
|
||||
class ClosureExpr extends Expr instanceof ExprCfgNode {
|
||||
ClosureExpr() { lambdaCreationExpr(super.getExpr()) }
|
||||
class ClosureExpr extends Expr {
|
||||
ClosureExpr() { lambdaCreationExpr(this) }
|
||||
|
||||
predicate hasBody(Callable body) { body = super.getExpr() }
|
||||
predicate hasBody(Callable body) { body = this }
|
||||
|
||||
predicate hasAliasedAccess(Expr f) { closureFlowStep+(this, f) and not closureFlowStep(f, _) }
|
||||
}
|
||||
@@ -991,10 +1001,11 @@ private module Cached {
|
||||
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
TCall(CallCfgNode c) {
|
||||
TCall(Call call) {
|
||||
Stages::DataFlowStage::ref() and
|
||||
call.hasEnclosingCfgScope() and
|
||||
// TODO: Handle index expressions as calls in data flow.
|
||||
not c.getCall() instanceof IndexExpr
|
||||
not call instanceof IndexExpr
|
||||
} or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
|
||||
@@ -9,7 +9,6 @@ private import codeql.rust.dataflow.internal.DataFlowImpl
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
private import codeql.rust.dataflow.Ssa
|
||||
private import codeql.rust.controlflow.CfgNodes
|
||||
private import Content
|
||||
|
||||
module Input implements InputSig<Location, RustDataFlow> {
|
||||
@@ -132,9 +131,7 @@ module Input implements InputSig<Location, RustDataFlow> {
|
||||
private import Make<Location, RustDataFlow, Input> as Impl
|
||||
|
||||
private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) {
|
||||
result.asCallCfgNode().getCall().getStaticTarget() = sc
|
||||
}
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
|
||||
|
||||
/** Gets the argument of `source` described by `sc`, if any. */
|
||||
private Expr getSourceNodeArgument(Input::SourceBase source, Impl::Private::SummaryComponent sc) {
|
||||
@@ -151,10 +148,9 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
result = expr.(ClosureExpr)
|
||||
or
|
||||
// The expression is an SSA read of an assignment of a closure
|
||||
exists(Ssa::Definition def, ExprCfgNode value |
|
||||
def.getARead().getAstNode() = expr and
|
||||
def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(value) and
|
||||
result = value.getExpr().(ClosureExpr)
|
||||
exists(Ssa::Definition def |
|
||||
def.getARead() = expr and
|
||||
def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(result.(ClosureExpr))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -164,7 +160,7 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
|
||||
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
|
||||
s.head() = Impl::Private::SummaryComponent::return(_) and
|
||||
result.asExpr().getExpr() = source.getCall()
|
||||
result.asExpr() = source.getCall()
|
||||
or
|
||||
exists(ArgumentPosition pos, Expr arg |
|
||||
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
|
||||
@@ -172,13 +168,13 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
result.asParameter() = getCallable(arg).getParam(pos.getPosition())
|
||||
)
|
||||
or
|
||||
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() =
|
||||
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr() =
|
||||
getSourceNodeArgument(source, s.headOfSingleton())
|
||||
}
|
||||
|
||||
RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) {
|
||||
exists(CallExprBase call, Expr arg, ArgumentPosition pos |
|
||||
result.asExpr().getExpr() = arg and
|
||||
result.asExpr() = arg and
|
||||
sc = Impl::Private::SummaryComponent::argument(pos) and
|
||||
call = sink.getCall() and
|
||||
arg = pos.getArgument(call)
|
||||
|
||||
@@ -35,17 +35,17 @@ class NodePublic extends TNode {
|
||||
/**
|
||||
* Gets the expression that corresponds to this node, if any.
|
||||
*/
|
||||
final ExprCfgNode asExpr() { this = TExprNode(result) }
|
||||
final Expr asExpr() { this = TExprNode(result) }
|
||||
|
||||
/**
|
||||
* Gets the parameter that corresponds to this node, if any.
|
||||
*/
|
||||
ParamBase asParameter() { result = this.(SourceParameterNode).getParameter().getParamBase() }
|
||||
ParamBase asParameter() { result = this.(SourceParameterNode).getParameter() }
|
||||
|
||||
/**
|
||||
* Gets the pattern that corresponds to this node, if any.
|
||||
*/
|
||||
final PatCfgNode asPat() { this = TPatNode(result) }
|
||||
final Pat asPat() { this = TPatNode(result) }
|
||||
}
|
||||
|
||||
abstract class Node extends NodePublic {
|
||||
@@ -56,9 +56,9 @@ abstract class Node extends NodePublic {
|
||||
abstract CfgScope getCfgScope();
|
||||
|
||||
/**
|
||||
* Gets the control flow node that corresponds to this data flow node.
|
||||
* Gets the AST node that corresponds to this data flow node, if any.
|
||||
*/
|
||||
CfgNode getCfgNode() { none() }
|
||||
AstNode getAstNode() { none() }
|
||||
}
|
||||
|
||||
/** A data flow node used to model flow summaries. */
|
||||
@@ -119,16 +119,16 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
|
||||
}
|
||||
|
||||
/** A data flow node that corresponds directly to a CFG node for an AST node. */
|
||||
abstract class AstCfgFlowNode extends Node {
|
||||
AstCfgNode n;
|
||||
abstract class AstNodeNode extends Node {
|
||||
AstNode n;
|
||||
|
||||
final override CfgNode getCfgNode() { result = n }
|
||||
final override AstNode getAstNode() { result = n }
|
||||
|
||||
final override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() }
|
||||
final override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
|
||||
|
||||
final override Location getLocation() { result = n.getAstNode().getLocation() }
|
||||
final override Location getLocation() { result = n.getLocation() }
|
||||
|
||||
final override string toString() { result = n.getAstNode().toString() }
|
||||
final override string toString() { result = n.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,25 +139,25 @@ abstract class AstCfgFlowNode extends Node {
|
||||
* to multiple `ExprNode`s, just like it may correspond to multiple
|
||||
* `ControlFlow::Node`s.
|
||||
*/
|
||||
class ExprNode extends AstCfgFlowNode, TExprNode {
|
||||
override ExprCfgNode n;
|
||||
class ExprNode extends AstNodeNode, TExprNode {
|
||||
override Expr n;
|
||||
|
||||
ExprNode() { this = TExprNode(n) }
|
||||
}
|
||||
|
||||
final class PatNode extends AstCfgFlowNode, TPatNode {
|
||||
override PatCfgNode n;
|
||||
final class PatNode extends AstNodeNode, TPatNode {
|
||||
override Pat n;
|
||||
|
||||
PatNode() { this = TPatNode(n) }
|
||||
}
|
||||
|
||||
/** A data flow node that corresponds to a name node in the CFG. */
|
||||
final class NameNode extends AstCfgFlowNode, TNameNode {
|
||||
override NameCfgNode n;
|
||||
final class NameNode extends AstNodeNode, TNameNode {
|
||||
override Name n;
|
||||
|
||||
NameNode() { this = TNameNode(n) }
|
||||
|
||||
NameCfgNode asName() { result = n }
|
||||
Name getName() { result = n }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,20 +169,20 @@ abstract class ParameterNode extends Node {
|
||||
abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition pos);
|
||||
}
|
||||
|
||||
final class SourceParameterNode extends AstCfgFlowNode, ParameterNode, TSourceParameterNode {
|
||||
override ParamBaseCfgNode n;
|
||||
final class SourceParameterNode extends AstNodeNode, ParameterNode, TSourceParameterNode {
|
||||
override ParamBase n;
|
||||
|
||||
SourceParameterNode() { this = TSourceParameterNode(n) }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
n.getAstNode() = pos.getParameterIn(c.asCfgScope().(Callable).getParamList())
|
||||
n = pos.getParameterIn(c.asCfgScope().(Callable).getParamList())
|
||||
}
|
||||
|
||||
/** Get the parameter position of this parameter. */
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
/** Gets the parameter in the CFG that this node corresponds to. */
|
||||
ParamBaseCfgNode getParameter() { result = n }
|
||||
ParamBase getParameter() { result = n }
|
||||
}
|
||||
|
||||
/** A parameter for a library callable with a flow summary. */
|
||||
@@ -223,13 +223,13 @@ abstract class ArgumentNode extends Node {
|
||||
}
|
||||
|
||||
final class ExprArgumentNode extends ArgumentNode, ExprNode {
|
||||
private CallCfgNode call_;
|
||||
private Call call_;
|
||||
private RustDataFlow::ArgumentPosition pos_;
|
||||
|
||||
ExprArgumentNode() { isArgumentForCall(n, call_, pos_) }
|
||||
|
||||
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
|
||||
call.asCallCfgNode() = call_ and pos = pos_
|
||||
call.asCall() = call_ and pos = pos_
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,19 +238,19 @@ final class ExprArgumentNode extends ArgumentNode, ExprNode {
|
||||
* has taken place.
|
||||
*/
|
||||
final class ReceiverNode extends ArgumentNode, TReceiverNode {
|
||||
private CallCfgNode n;
|
||||
private Call n;
|
||||
|
||||
ReceiverNode() { this = TReceiverNode(n, false) }
|
||||
|
||||
ExprCfgNode getReceiver() { result = n.getReceiver() }
|
||||
Expr getReceiver() { result = n.getReceiver() }
|
||||
|
||||
MethodCallExprCfgNode getMethodCall() { result = n }
|
||||
MethodCallExpr getMethodCall() { result = n }
|
||||
|
||||
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
|
||||
call.asCallCfgNode() = n and pos = TSelfParameterPosition()
|
||||
call.asCall() = n and pos = TSelfParameterPosition()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() }
|
||||
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
|
||||
|
||||
override Location getLocation() { result = this.getReceiver().getLocation() }
|
||||
|
||||
@@ -275,12 +275,12 @@ final class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
|
||||
* passed into the closure body at an invocation.
|
||||
*/
|
||||
final class ClosureArgumentNode extends ArgumentNode, ExprNode {
|
||||
private CallExprCfgNode call_;
|
||||
private CallExpr call_;
|
||||
|
||||
ClosureArgumentNode() { lambdaCallExpr(call_, _, this.asExpr()) }
|
||||
|
||||
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
|
||||
call.asCallCfgNode() = call_ and
|
||||
call.asCall() = call_ and
|
||||
pos.isClosureSelf()
|
||||
}
|
||||
}
|
||||
@@ -309,7 +309,7 @@ abstract class ReturnNode extends Node {
|
||||
}
|
||||
|
||||
final class ExprReturnNode extends ExprNode, ReturnNode {
|
||||
ExprReturnNode() { this.getCfgNode().getASuccessor() instanceof AnnotatedExitCfgNode }
|
||||
ExprReturnNode() { n.getACfgNode().getASuccessor() instanceof AnnotatedExitCfgNode }
|
||||
|
||||
override ReturnKind getKind() { result = TNormalReturnKind() }
|
||||
}
|
||||
@@ -329,11 +329,11 @@ abstract class OutNode extends Node {
|
||||
}
|
||||
|
||||
final private class ExprOutNode extends ExprNode, OutNode {
|
||||
ExprOutNode() { this.asExpr() instanceof CallCfgNode }
|
||||
ExprOutNode() { this.asExpr() instanceof Call }
|
||||
|
||||
/** Gets the underlying call CFG node that includes this out node. */
|
||||
override DataFlowCall getCall(ReturnKind kind) {
|
||||
result.asCallCfgNode() = this.getCfgNode() and
|
||||
result.asCall() = n and
|
||||
kind = TNormalReturnKind()
|
||||
}
|
||||
}
|
||||
@@ -391,27 +391,27 @@ abstract class PostUpdateNode extends PostUpdateNodePublic, Node {
|
||||
}
|
||||
|
||||
final class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode {
|
||||
private ExprCfgNode n;
|
||||
private Expr e;
|
||||
|
||||
ExprPostUpdateNode() { this = TExprPostUpdateNode(n) }
|
||||
ExprPostUpdateNode() { this = TExprPostUpdateNode(e) }
|
||||
|
||||
override Node getPreUpdateNode() { result = TExprNode(n) }
|
||||
override Node getPreUpdateNode() { result = TExprNode(e) }
|
||||
|
||||
override CfgScope getCfgScope() { result = n.getScope() }
|
||||
override CfgScope getCfgScope() { result = e.getEnclosingCfgScope() }
|
||||
|
||||
override Location getLocation() { result = n.getLocation() }
|
||||
override Location getLocation() { result = e.getLocation() }
|
||||
}
|
||||
|
||||
final class ReceiverPostUpdateNode extends PostUpdateNode, TReceiverNode {
|
||||
private CallCfgNode n;
|
||||
private Call call;
|
||||
|
||||
ReceiverPostUpdateNode() { this = TReceiverNode(n, true) }
|
||||
ReceiverPostUpdateNode() { this = TReceiverNode(call, true) }
|
||||
|
||||
override Node getPreUpdateNode() { result = TReceiverNode(n, false) }
|
||||
override Node getPreUpdateNode() { result = TReceiverNode(call, false) }
|
||||
|
||||
override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() }
|
||||
override CfgScope getCfgScope() { result = call.getEnclosingCfgScope() }
|
||||
|
||||
override Location getLocation() { result = n.getReceiver().getLocation() }
|
||||
override Location getLocation() { result = call.getReceiver().getLocation() }
|
||||
}
|
||||
|
||||
final class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
|
||||
@@ -445,38 +445,46 @@ final class CastNode extends ExprNode {
|
||||
|
||||
cached
|
||||
newtype TNode =
|
||||
TExprNode(ExprCfgNode n) { Stages::DataFlowStage::ref() } or
|
||||
TSourceParameterNode(ParamBaseCfgNode p) or
|
||||
TPatNode(PatCfgNode p) or
|
||||
TNameNode(NameCfgNode n) { n.getName() = any(Variable v).getName() } or
|
||||
TExprPostUpdateNode(ExprCfgNode e) {
|
||||
isArgumentForCall(e, _, _)
|
||||
or
|
||||
lambdaCallExpr(_, _, e)
|
||||
or
|
||||
lambdaCreationExpr(e.getExpr())
|
||||
or
|
||||
// Whenever `&mut e` has a post-update node we also create one for `e`.
|
||||
// E.g., for `e` in `f(..., &mut e, ...)` or `*(&mut e) = ...`.
|
||||
e = any(RefExprCfgNode ref | ref.isMut() and exists(TExprPostUpdateNode(ref))).getExpr()
|
||||
or
|
||||
e =
|
||||
[
|
||||
any(IndexExprCfgNode i).getBase(), //
|
||||
any(FieldExprCfgNode access).getContainer(), //
|
||||
any(TryExprCfgNode try).getExpr(), //
|
||||
any(PrefixExprCfgNode pe | pe.getOperatorName() = "*").getExpr(), //
|
||||
any(AwaitExprCfgNode a).getExpr(), //
|
||||
any(MethodCallExprCfgNode mc).getReceiver(), //
|
||||
getPostUpdateReverseStep(any(PostUpdateNode n).getPreUpdateNode().asExpr(), _)
|
||||
]
|
||||
TExprNode(Expr e) { e.hasEnclosingCfgScope() and Stages::DataFlowStage::ref() } or
|
||||
TSourceParameterNode(ParamBase p) { p.hasEnclosingCfgScope() } or
|
||||
TPatNode(Pat p) { p.hasEnclosingCfgScope() } or
|
||||
TNameNode(Name n) { n = any(Variable v).getName() and n.hasEnclosingCfgScope() } or
|
||||
TExprPostUpdateNode(Expr e) {
|
||||
e.hasEnclosingCfgScope() and
|
||||
(
|
||||
isArgumentForCall(e, _, _)
|
||||
or
|
||||
lambdaCallExpr(_, _, e)
|
||||
or
|
||||
lambdaCreationExpr(e)
|
||||
or
|
||||
// Whenever `&mut e` has a post-update node we also create one for `e`.
|
||||
// E.g., for `e` in `f(..., &mut e, ...)` or `*(&mut e) = ...`.
|
||||
e = any(RefExpr ref | ref.isMut() and exists(TExprPostUpdateNode(ref))).getExpr()
|
||||
or
|
||||
e =
|
||||
[
|
||||
any(IndexExpr i).getBase(), //
|
||||
any(FieldExpr access).getContainer(), //
|
||||
any(TryExpr try).getExpr(), //
|
||||
any(PrefixExpr pe | pe.getOperatorName() = "*").getExpr(), //
|
||||
any(AwaitExpr a).getExpr(), //
|
||||
any(MethodCallExpr mc).getReceiver(), //
|
||||
getPostUpdateReverseStep(any(PostUpdateNode n).getPreUpdateNode().asExpr(), _)
|
||||
]
|
||||
)
|
||||
} or
|
||||
TReceiverNode(CallCfgNode mc, Boolean isPost) {
|
||||
mc.getCall().receiverImplicitlyBorrowed() and
|
||||
TReceiverNode(Call call, Boolean isPost) {
|
||||
call.hasEnclosingCfgScope() and
|
||||
call.receiverImplicitlyBorrowed() and
|
||||
// TODO: Handle index expressions as calls in data flow.
|
||||
not mc.getCall() instanceof IndexExpr
|
||||
not call instanceof IndexExpr
|
||||
} or
|
||||
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) {
|
||||
forall(AstNode n | n = sn.getSinkElement() or n = sn.getSourceElement() |
|
||||
n.hasEnclosingCfgScope()
|
||||
)
|
||||
} or
|
||||
TClosureSelfReferenceNode(CfgScope c) { lambdaCreationExpr(c) } or
|
||||
TCaptureNode(VariableCapture::Flow::SynthesizedCaptureNode cn)
|
||||
|
||||
@@ -2,7 +2,6 @@ private import rust
|
||||
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
|
||||
private import BasicBlocks
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.rust.controlflow.CfgNodes as CfgNodes
|
||||
private import Cfg
|
||||
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
@@ -229,11 +228,11 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
CfgNode getARead(Definition def) {
|
||||
Expr getARead(Definition def) {
|
||||
exists(Variable v, BasicBlock bb, int i |
|
||||
Impl::ssaDefReachesRead(v, def, bb, i) and
|
||||
variableReadCertain(bb, i, v.getAnAccess(), v) and
|
||||
result = bb.getNode(i)
|
||||
result = bb.getNode(i).getAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -247,8 +246,10 @@ private module Cached {
|
||||
* without passing through any other non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate firstRead(Definition def, CfgNode read) {
|
||||
exists(BasicBlock bb, int i | Impl::firstUse(def, bb, i, true) and read = bb.getNode(i))
|
||||
predicate firstRead(Definition def, Expr read) {
|
||||
exists(BasicBlock bb, int i |
|
||||
Impl::firstUse(def, bb, i, true) and read = bb.getNode(i).getAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,12 +258,12 @@ private module Cached {
|
||||
* passing through another non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate adjacentReadPair(Definition def, CfgNode read1, CfgNode read2) {
|
||||
predicate adjacentReadPair(Definition def, Expr read1, Expr read2) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2, Variable v |
|
||||
Impl::ssaDefReachesRead(v, def, bb1, i1) and
|
||||
Impl::adjacentUseUse(bb1, i1, bb2, i2, v, true) and
|
||||
read1 = bb1.getNode(i1) and
|
||||
read2 = bb2.getNode(i2)
|
||||
read1 = bb1.getNode(i1).getAstNode() and
|
||||
read2 = bb2.getNode(i2).getAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -287,7 +288,7 @@ private module Cached {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
signature predicate guardChecksSig(CfgNodes::AstCfgNode g, Cfg::CfgNode e, boolean branch);
|
||||
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch);
|
||||
|
||||
cached // nothing is actually cached
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
@@ -310,47 +311,49 @@ private module Cached {
|
||||
import Cached
|
||||
private import codeql.rust.dataflow.Ssa
|
||||
|
||||
private class ExprAlias = Expr;
|
||||
|
||||
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
|
||||
private import codeql.rust.dataflow.internal.DataFlowImpl as DataFlowImpl
|
||||
private import codeql.util.Boolean
|
||||
|
||||
class Expr extends CfgNodes::AstCfgNode {
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
class Expr extends ExprAlias {
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this.getACfgNode() = bb.getNode(i) }
|
||||
}
|
||||
|
||||
Expr getARead(Definition def) { result = Cached::getARead(def) }
|
||||
|
||||
predicate ssaDefHasSource(WriteDefinition def) { none() } // handled in `DataFlowImpl.qll` instead
|
||||
|
||||
private predicate isArg(CfgNodes::CallExprBaseCfgNode call, CfgNodes::ExprCfgNode e) {
|
||||
call.getArgument(_) = e
|
||||
private predicate isArg(CallExprBase call, Expr e) {
|
||||
call.getAnArg() = e
|
||||
or
|
||||
call.(CfgNodes::MethodCallExprCfgNode).getReceiver() = e
|
||||
call.(MethodCallExpr).getReceiver() = e
|
||||
or
|
||||
exists(CfgNodes::ExprCfgNode mid |
|
||||
exists(Expr mid |
|
||||
isArg(call, mid) and
|
||||
e = DataFlowImpl::getPostUpdateReverseStep(mid, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) {
|
||||
exists(CfgNodes::CallExprBaseCfgNode call, Variable v, BasicBlock bb, int i |
|
||||
exists(Variable v, BasicBlock bb, int i |
|
||||
def.definesAt(v, bb, i) and
|
||||
mutablyBorrows(bb.getNode(i).getAstNode(), v) and
|
||||
isArg(call, bb.getNode(i))
|
||||
isArg(_, bb.getNode(i).getAstNode())
|
||||
)
|
||||
}
|
||||
|
||||
class GuardValue = Boolean;
|
||||
|
||||
class Guard extends CfgNodes::AstCfgNode {
|
||||
class Guard extends AstNode {
|
||||
/**
|
||||
* Holds if the evaluation of this guard to `branch` corresponds to the edge
|
||||
* from `bb1` to `bb2`.
|
||||
*/
|
||||
predicate hasValueBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue branch) {
|
||||
exists(Cfg::ConditionalSuccessor s |
|
||||
this = bb1.getANode() and
|
||||
this = bb1.getANode().getAstNode() and
|
||||
bb2 = bb1.getASuccessor(s) and
|
||||
s.getValue() = branch
|
||||
)
|
||||
@@ -369,7 +372,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue branch) {
|
||||
exists(ConditionBasicBlock conditionBlock, ConditionalSuccessor s |
|
||||
guard = conditionBlock.getLastNode() and
|
||||
guard = conditionBlock.getLastNode().getAstNode() and
|
||||
s.getValue() = branch and
|
||||
conditionBlock.edgeDominates(bb, s)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
private import rust
|
||||
private import codeql.dataflow.TaintTracking
|
||||
private import codeql.rust.controlflow.CfgNodes
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
private import DataFlowImpl
|
||||
@@ -21,22 +20,22 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
|
||||
Stages::DataFlowStage::ref() and
|
||||
model = "" and
|
||||
(
|
||||
exists(BinaryExprCfgNode binary |
|
||||
exists(BinaryExpr binary |
|
||||
binary.getOperatorName() = ["+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>"] and
|
||||
pred.asExpr() = [binary.getLhs(), binary.getRhs()] and
|
||||
succ.asExpr() = binary
|
||||
)
|
||||
or
|
||||
exists(PrefixExprCfgNode prefix |
|
||||
exists(PrefixExpr prefix |
|
||||
prefix.getOperatorName() = ["-", "!"] and
|
||||
pred.asExpr() = prefix.getExpr() and
|
||||
succ.asExpr() = prefix
|
||||
)
|
||||
or
|
||||
pred.asExpr() = succ.asExpr().(CastExprCfgNode).getExpr()
|
||||
pred.asExpr() = succ.asExpr().(CastExpr).getExpr()
|
||||
or
|
||||
exists(IndexExprCfgNode index |
|
||||
index.getIndex() instanceof RangeExprCfgNode and
|
||||
exists(IndexExpr index |
|
||||
index.getIndex() instanceof RangeExpr and
|
||||
pred.asExpr() = index.getBase() and
|
||||
succ.asExpr() = index
|
||||
)
|
||||
@@ -52,8 +51,16 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
|
||||
cs.getContent() instanceof ReferenceContent
|
||||
)
|
||||
or
|
||||
exists(FormatArgsExprCfgNode format | succ.asExpr() = format |
|
||||
pred.asExpr() = [format.getArgumentExpr(_), format.getFormatTemplateVariableAccess(_)]
|
||||
exists(FormatArgsExpr format | succ.asExpr() = format |
|
||||
pred.asExpr() = format.getAnArg().getExpr()
|
||||
or
|
||||
pred.asExpr() =
|
||||
any(FormatTemplateVariableAccess v |
|
||||
exists(Format f |
|
||||
f = format.getAFormat() and
|
||||
v.getArgument() = [f.getArgumentRef(), f.getWidthArgument(), f.getPrecisionArgument()]
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
succ.(Node::PostUpdateNode).getPreUpdateNode().asExpr() =
|
||||
|
||||
@@ -25,6 +25,11 @@ final class AssignmentOperation = AssignmentOperationImpl;
|
||||
final class AssignmentExpr extends AssignmentOperationImpl {
|
||||
AssignmentExpr() { this.getOperatorName() = "=" }
|
||||
|
||||
/**
|
||||
* Gets a write access that occurs in the left-hand side of this assignment expression.
|
||||
*/
|
||||
VariableWriteAccess getAWriteAccess() { this = result.getAssignmentExpr() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AssignmentExpr" }
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ module Impl {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this node is inside a CFG scope. */
|
||||
predicate hasEnclosingCfgScope() { exists(this.getEnclosingCfgScope()) }
|
||||
|
||||
/** Gets the block that encloses this node, if any. */
|
||||
cached
|
||||
BlockExpr getEnclosingBlock() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `BlockExpr`.
|
||||
*
|
||||
@@ -26,5 +25,10 @@ module Impl {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class BlockExpr extends Generated::BlockExpr { }
|
||||
class BlockExpr extends Generated::BlockExpr {
|
||||
/**
|
||||
* Gets the tail expression of this block, if it exists.
|
||||
*/
|
||||
Expr getTailExpr() { result = this.getStmtList().getTailExpr() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ module Impl {
|
||||
* ```
|
||||
*/
|
||||
class ParenExpr extends Generated::ParenExpr {
|
||||
override string toStringImpl() { result = "(" + this.getExpr().toAbbreviatedString() + ")" }
|
||||
override string toStringImpl() {
|
||||
result = "(" + this.getExpr().toAbbreviatedString() + ")"
|
||||
or
|
||||
not exists(this.getExpr().toAbbreviatedString()) and
|
||||
result = "(...)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ private import codeql.rust.Concepts
|
||||
private class PoemHandlerParam extends RemoteSource::Range {
|
||||
PoemHandlerParam() {
|
||||
exists(TupleStructPat param |
|
||||
this.asPat().getPat() = param.getAField() and
|
||||
this.asPat() = param.getAField() and
|
||||
param.getStruct().getCanonicalPath() = ["poem::web::query::Query", "poem::web::path::Path"]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range {
|
||||
// a call to `cipher::KeyInit::new`, `cipher::KeyInit::new_from_slice`,
|
||||
// `cipher::KeyIvInit::new`, `cipher::KeyIvInit::new_from_slices`, `rc2::Rc2::new_with_eff_key_len` or similar.
|
||||
exists(CallExprBase ce, string rawAlgorithmName |
|
||||
ce = this.asExpr().getExpr() and
|
||||
ce = this.asExpr() and
|
||||
ce.getStaticTarget().(Function).getName().getText() =
|
||||
["new", "new_from_slice", "new_with_eff_key_len", "new_from_slices"] and
|
||||
// extract the algorithm name from the type of `ce` or its receiver.
|
||||
|
||||
@@ -4,20 +4,16 @@
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.Concepts
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.rust.controlflow.CfgNodes as CfgNodes
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.internal.PathResolution
|
||||
|
||||
/**
|
||||
* A call to the `starts_with` method on a `Path`.
|
||||
*/
|
||||
private class StartswithCall extends Path::SafeAccessCheck::Range, CfgNodes::MethodCallExprCfgNode {
|
||||
StartswithCall() {
|
||||
this.getMethodCallExpr().getStaticTarget().getCanonicalPath() = "<std::path::Path>::starts_with"
|
||||
}
|
||||
private class StartswithCall extends Path::SafeAccessCheck::Range, MethodCallExpr {
|
||||
StartswithCall() { this.getStaticTarget().getCanonicalPath() = "<std::path::Path>::starts_with" }
|
||||
|
||||
override predicate checks(Cfg::CfgNode e, boolean branch) {
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
e = this.getReceiver() and
|
||||
branch = true
|
||||
}
|
||||
|
||||
@@ -39,6 +39,14 @@ module AccessAfterLifetime {
|
||||
*/
|
||||
abstract class Barrier extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* Holds if the value `source` points to accesses a variable `target` with scope `scope`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate sourceValueScope(Source source, Variable target, BlockExpr scope) {
|
||||
valueScope(source.getTarget(), target, scope)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the pair `(source, sink)`, that represents a flow from a
|
||||
* pointer or reference to a dereference, has its dereference outside the
|
||||
@@ -47,8 +55,8 @@ module AccessAfterLifetime {
|
||||
bindingset[source, sink]
|
||||
predicate dereferenceAfterLifetime(Source source, Sink sink, Variable target) {
|
||||
exists(BlockExpr valueScope, BlockExpr accessScope |
|
||||
valueScope(source.getTarget(), target, valueScope) and
|
||||
accessScope = sink.asExpr().getExpr().getEnclosingBlock() and
|
||||
sourceValueScope(source, target, valueScope) and
|
||||
accessScope = sink.asExpr().getEnclosingBlock() and
|
||||
not mayEncloseOnStack(valueScope, accessScope)
|
||||
)
|
||||
}
|
||||
@@ -104,7 +112,7 @@ module AccessAfterLifetime {
|
||||
private class RefExprSource extends Source {
|
||||
Expr targetValue;
|
||||
|
||||
RefExprSource() { this.asExpr().getExpr().(RefExpr).getExpr() = targetValue }
|
||||
RefExprSource() { this.asExpr().(RefExpr).getExpr() = targetValue }
|
||||
|
||||
override Expr getTarget() { result = targetValue }
|
||||
}
|
||||
@@ -114,6 +122,6 @@ module AccessAfterLifetime {
|
||||
* variables through closures properly.
|
||||
*/
|
||||
private class ClosureBarrier extends Barrier {
|
||||
ClosureBarrier() { this.asExpr().getExpr().getEnclosingCallable() instanceof ClosureExpr }
|
||||
ClosureBarrier() { this.asExpr().getEnclosingCallable() instanceof ClosureExpr }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ module AccessInvalidPointer {
|
||||
* A pointer access using the unary `*` operator.
|
||||
*/
|
||||
private class DereferenceSink extends Sink {
|
||||
DereferenceSink() { any(DerefExpr p).getExpr() = this.asExpr().getExpr() }
|
||||
DereferenceSink() { any(DerefExpr p).getExpr() = this.asExpr() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@ private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
class NumericTypeBarrier extends DataFlow::Node {
|
||||
NumericTypeBarrier() {
|
||||
exists(StructType t, Struct s |
|
||||
t = TypeInference::inferType(this.asExpr().getExpr()) and
|
||||
t = TypeInference::inferType(this.asExpr()) and
|
||||
s = t.getStruct()
|
||||
|
|
||||
s instanceof Builtins::NumericType or
|
||||
@@ -32,7 +32,7 @@ class NumericTypeBarrier extends DataFlow::Node {
|
||||
class IntegralOrBooleanTypeBarrier extends DataFlow::Node {
|
||||
IntegralOrBooleanTypeBarrier() {
|
||||
exists(StructType t, Struct s |
|
||||
t = TypeInference::inferType(this.asExpr().getExpr()) and
|
||||
t = TypeInference::inferType(this.asExpr()) and
|
||||
s = t.getStruct()
|
||||
|
|
||||
s instanceof Builtins::IntegralType or
|
||||
|
||||
@@ -63,7 +63,7 @@ module HardcodedCryptographicValue {
|
||||
* A literal, considered as a flow source.
|
||||
*/
|
||||
private class LiteralSource extends Source {
|
||||
LiteralSource() { this.asExpr().getExpr() instanceof LiteralExpr }
|
||||
LiteralSource() { this.asExpr() instanceof LiteralExpr }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,8 +75,8 @@ module HardcodedCryptographicValue {
|
||||
*/
|
||||
private class ArrayListSource extends Source {
|
||||
ArrayListSource() {
|
||||
this.asExpr().getExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr or
|
||||
this.asExpr().getExpr().(ArrayRepeatExpr).getRepeatOperand() instanceof LiteralExpr
|
||||
this.asExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr or
|
||||
this.asExpr().(ArrayRepeatExpr).getRepeatOperand() instanceof LiteralExpr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ module HardcodedCryptographicValue {
|
||||
exists(CallExprBase ce |
|
||||
ce.getStaticTarget().(Addressable).getCanonicalPath() =
|
||||
["getrandom::fill", "getrandom::getrandom"] and
|
||||
this.asExpr().getExpr().getParentNode*() = ce.getArgList().getArg(0)
|
||||
this.asExpr().getParentNode*() = ce.getArgList().getArg(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +85,13 @@ module InsecureCookie {
|
||||
cookieOptionalBarrier(summaryNode, attrib, arg) and
|
||||
// find a call and arg referenced by this optional barrier
|
||||
ce.getStaticTarget() = summaryNode.getSummarizedCallable() and
|
||||
ce.getArg(arg) = argNode.asExpr().getExpr() and
|
||||
ce.getArg(arg) = argNode.asExpr() and
|
||||
// check if the argument is always `true`
|
||||
(
|
||||
if
|
||||
forex(DataFlow::Node argSourceNode, BooleanLiteralExpr argSourceValue |
|
||||
DataFlow::localFlow(argSourceNode, argNode) and
|
||||
argSourceValue = argSourceNode.asExpr().getExpr()
|
||||
argSourceValue = argSourceNode.asExpr()
|
||||
|
|
||||
argSourceValue.getTextValue() = "true"
|
||||
)
|
||||
@@ -101,7 +101,7 @@ module InsecureCookie {
|
||||
// and find the node where this happens (we can't just use the flow summary node, since its
|
||||
// shared across all calls to the modeled function, we need a node specific to this call)
|
||||
(
|
||||
node.asExpr().getExpr() = ce.(MethodCallExpr).getReceiver() // e.g. `a` in `a.set_secure(true)`
|
||||
node.asExpr() = ce.(MethodCallExpr).getReceiver() // e.g. `a` in `a.set_secure(true)`
|
||||
or
|
||||
exists(BasicBlock bb, int i |
|
||||
// associated SSA node
|
||||
|
||||
@@ -29,7 +29,7 @@ private class SensitiveDataCall extends SensitiveData {
|
||||
|
||||
SensitiveDataCall() {
|
||||
exists(CallExprBase call, string name |
|
||||
call = this.asExpr().getExpr() and
|
||||
call = this.asExpr() and
|
||||
name =
|
||||
[
|
||||
call.getStaticTarget().(Function).getName().getText(),
|
||||
@@ -50,7 +50,6 @@ private class SensitiveVariableAccess extends SensitiveData {
|
||||
|
||||
SensitiveVariableAccess() {
|
||||
HeuristicNames::nameIndicatesSensitiveData(this.asExpr()
|
||||
.getExpr()
|
||||
.(VariableAccess)
|
||||
.getVariable()
|
||||
.(Variable)
|
||||
@@ -69,7 +68,7 @@ private class SensitiveFieldAccess extends SensitiveData {
|
||||
SensitiveDataClassification classification;
|
||||
|
||||
SensitiveFieldAccess() {
|
||||
exists(FieldExpr fe | fieldExprParentField*(fe) = this.asExpr().getExpr() |
|
||||
exists(FieldExpr fe | fieldExprParentField*(fe) = this.asExpr() |
|
||||
HeuristicNames::nameIndicatesSensitiveData(fe.getIdentifier().getText(), classification)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ private import codeql.rust.dataflow.TaintTracking
|
||||
private import codeql.rust.Concepts
|
||||
private import codeql.rust.dataflow.internal.DataFlowImpl
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.rust.controlflow.CfgNodes as CfgNodes
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and barriers for detecting path injection
|
||||
@@ -50,16 +49,16 @@ module TaintedPath {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate sanitizerGuard(CfgNodes::AstCfgNode g, Cfg::CfgNode node, boolean branch) {
|
||||
g.(SanitizerGuard::Range).checks(node, branch)
|
||||
private predicate sanitizerGuard(AstNode g, Expr e, boolean branch) {
|
||||
g.(SanitizerGuard::Range).checks(e, branch)
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new path safety checks. */
|
||||
module SanitizerGuard {
|
||||
/** A data-flow node that checks that a path is safe to access. */
|
||||
abstract class Range extends CfgNodes::AstCfgNode {
|
||||
/** Holds if this guard validates `node` upon evaluating to `branch`. */
|
||||
abstract predicate checks(Cfg::CfgNode node, boolean branch);
|
||||
abstract class Range extends AstNode {
|
||||
/** Holds if this guard validates `e` upon evaluating to `branch`. */
|
||||
abstract predicate checks(Expr e, boolean branch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,15 +66,14 @@ module SanitizerGuard {
|
||||
* A check of the form `!strings.Contains(nd, "..")`, considered as a sanitizer guard for
|
||||
* path traversal.
|
||||
*/
|
||||
private class DotDotCheck extends SanitizerGuard::Range, CfgNodes::MethodCallExprCfgNode {
|
||||
private class DotDotCheck extends SanitizerGuard::Range, MethodCallExpr {
|
||||
DotDotCheck() {
|
||||
this.getAstNode().(CallExprBase).getStaticTarget().(Addressable).getCanonicalPath() =
|
||||
this.getStaticTarget().(Addressable).getCanonicalPath() =
|
||||
["<alloc::string::String>::contains", "<core::str>::contains"] and
|
||||
this.getArgument(0).getAstNode().(LiteralExpr).getTextValue() =
|
||||
["\"..\"", "\"../\"", "\"..\\\""]
|
||||
this.getArg(0).(LiteralExpr).getTextValue() = ["\"..\"", "\"../\"", "\"..\\\""]
|
||||
}
|
||||
|
||||
override predicate checks(Cfg::CfgNode e, boolean branch) {
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
e = this.getReceiver() and
|
||||
branch = false
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import rust
|
||||
private import codeql.rust.Concepts
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.FlowSink
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.rust.controlflow.CfgNodes as CfgNodes
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and barriers for detecting uncontrolled
|
||||
@@ -45,23 +43,24 @@ module UncontrolledAllocationSize {
|
||||
|
||||
/**
|
||||
* Holds if comparison `g` having result `branch` indicates an upper bound for the sub-expression
|
||||
* `node`. For example when the comparison `x < 10` is true, we have an upper bound for `x`.
|
||||
* `e`. For example when the comparison `x < 10` is true, we have an upper bound for `x`.
|
||||
*/
|
||||
private predicate isUpperBoundCheck(CfgNodes::AstCfgNode g, Cfg::CfgNode node, boolean branch) {
|
||||
exists(BinaryExpr cmp | g = cmp.getACfgNode() |
|
||||
node = cmp.(RelationalOperation).getLesserOperand().getACfgNode() and
|
||||
branch = true
|
||||
or
|
||||
node = cmp.(RelationalOperation).getGreaterOperand().getACfgNode() and
|
||||
branch = false
|
||||
or
|
||||
cmp instanceof EqualsOperation and
|
||||
[cmp.getLhs(), cmp.getRhs()].getACfgNode() = node and
|
||||
branch = true
|
||||
or
|
||||
cmp instanceof NotEqualsOperation and
|
||||
[cmp.getLhs(), cmp.getRhs()].getACfgNode() = node and
|
||||
branch = false
|
||||
)
|
||||
private predicate isUpperBoundCheck(AstNode g, Expr e, boolean branch) {
|
||||
g =
|
||||
any(BinaryExpr cmp |
|
||||
e = cmp.(RelationalOperation).getLesserOperand() and
|
||||
branch = true
|
||||
or
|
||||
e = cmp.(RelationalOperation).getGreaterOperand() and
|
||||
branch = false
|
||||
or
|
||||
cmp instanceof EqualsOperation and
|
||||
[cmp.getLhs(), cmp.getRhs()] = e and
|
||||
branch = true
|
||||
or
|
||||
cmp instanceof NotEqualsOperation and
|
||||
[cmp.getLhs(), cmp.getRhs()] = e and
|
||||
branch = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ module UseOfHttp {
|
||||
* An HTTP string literal as a source.
|
||||
*/
|
||||
private class HttpStringLiteralAsSource extends Source {
|
||||
HttpStringLiteralAsSource() { this.asExpr().getExpr() instanceof HttpStringLiteral }
|
||||
HttpStringLiteralAsSource() { this.asExpr() instanceof HttpStringLiteral }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -189,7 +189,7 @@ class ModeledHashOperation extends Cryptography::CryptographicOperation::Range {
|
||||
exists(CallExpr call |
|
||||
sinkNode(input, "hasher-input") and
|
||||
call = input.(Node::FlowSummaryNode).getSinkElement().getCall() and
|
||||
call = this.asExpr().getExpr() and
|
||||
call = this.asExpr() and
|
||||
algorithmName = call.getFunction().(PathExpr).getPath().getQualifier().getText()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
private import codeql.util.Unit
|
||||
private import rust
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.controlflow.CfgNodes
|
||||
private import codeql.rust.dataflow.FlowSink
|
||||
private import codeql.rust.Concepts
|
||||
private import codeql.rust.security.Barriers as Barriers
|
||||
@@ -57,8 +56,8 @@ module RegexInjection {
|
||||
exists(CallExprBase call, Addressable a |
|
||||
call.getStaticTarget() = a and
|
||||
a.getCanonicalPath() = "<regex::regex::string::Regex>::new" and
|
||||
this.asExpr().getExpr() = call.getArg(0) and
|
||||
not this.asExpr() instanceof LiteralExprCfgNode
|
||||
this.asExpr() = call.getArg(0) and
|
||||
not this.asExpr() instanceof LiteralExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -78,7 +77,6 @@ module RegexInjection {
|
||||
// A barrier is any call to a function named `escape`, in particular this
|
||||
// makes calls to `regex::escape` a barrier.
|
||||
this.asExpr()
|
||||
.getExpr()
|
||||
.(CallExpr)
|
||||
.getFunction()
|
||||
.(PathExpr)
|
||||
|
||||
@@ -18,20 +18,20 @@ private import internal.InlineExpectationsTestImpl as InlineExpectationsTestImpl
|
||||
* representation of the path has `name` as a prefix.
|
||||
*/
|
||||
bindingset[name]
|
||||
private predicate callTargetName(CallExprCfgNode call, string name) {
|
||||
call.getFunction().(PathExprCfgNode).toString().matches(name + "%")
|
||||
private predicate callTargetName(CallExpr call, string name) {
|
||||
call.getFunction().(PathExpr).toString().matches(name + "%")
|
||||
}
|
||||
|
||||
private module FlowTestImpl implements InputSig<Location, RustDataFlow> {
|
||||
predicate defaultSource(DataFlow::Node source) { callTargetName(source.asExpr(), "source") }
|
||||
|
||||
predicate defaultSink(DataFlow::Node sink) {
|
||||
any(CallExprCfgNode call | callTargetName(call, "sink")).getArgument(_) = sink.asExpr()
|
||||
any(CallExpr call | callTargetName(call, "sink")).getAnArg() = sink.asExpr()
|
||||
}
|
||||
|
||||
private string getSourceArgString(DataFlow::Node src) {
|
||||
defaultSource(src) and
|
||||
result = src.asExpr().(CallExprCfgNode).getArgument(0).toString()
|
||||
result = src.asExpr().(CallExpr).getArg(0).toString()
|
||||
or
|
||||
sourceNode(src, _) and
|
||||
result = src.(Node::FlowSummaryNode).getSourceElement().getCall().getArg(0).toString() and
|
||||
|
||||
@@ -37,7 +37,7 @@ module CleartextLoggingConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// flow from `a` to `&a`
|
||||
node2.asExpr().getExpr().(RefExpr).getExpr() = node1.asExpr().getExpr()
|
||||
node2.asExpr().(RefExpr).getExpr() = node1.asExpr()
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
|
||||
@@ -36,7 +36,7 @@ module CleartextStorageDatabaseConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// flow from `a` to `&a`
|
||||
node2.asExpr().getExpr().(RefExpr).getExpr() = node1.asExpr().getExpr()
|
||||
node2.asExpr().(RefExpr).getExpr() = node1.asExpr()
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
@@ -26,17 +26,17 @@ module AccessAfterLifetimeConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
node instanceof AccessAfterLifetime::Source and
|
||||
// exclude cases with sources in macros, since these results are difficult to interpret
|
||||
not node.asExpr().getExpr().isFromMacroExpansion()
|
||||
not node.asExpr().isFromMacroExpansion()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
node instanceof AccessAfterLifetime::Sink and
|
||||
// exclude cases with sinks in macros, since these results are difficult to interpret
|
||||
not node.asExpr().getExpr().isFromMacroExpansion() and
|
||||
not node.asExpr().isFromMacroExpansion() and
|
||||
// include only results inside `unsafe` blocks, as other results tend to be false positives
|
||||
(
|
||||
node.asExpr().getExpr().getEnclosingBlock*().isUnsafe() or
|
||||
node.asExpr().getExpr().getEnclosingCallable().(Function).isUnsafe()
|
||||
node.asExpr().getEnclosingBlock*().isUnsafe() or
|
||||
node.asExpr().getEnclosingCallable().(Function).isUnsafe()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -45,11 +45,9 @@ module AccessAfterLifetimeConfig implements DataFlow::ConfigSig {
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
exists(Variable target, DataFlow::Node sink |
|
||||
exists(Variable target |
|
||||
AccessAfterLifetime::sourceValueScope(source, target, _) and
|
||||
result = [target.getLocation(), source.getLocation()]
|
||||
|
|
||||
isSink(sink) and
|
||||
AccessAfterLifetime::dereferenceAfterLifetime(source, sink, target)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ where
|
||||
not write.isFromMacroExpansion() and
|
||||
not isAllowableUnused(v) and
|
||||
// SSA definitions are only created for live writes
|
||||
not write = any(Ssa::WriteDefinition def).getWriteAccess().getAstNode() and
|
||||
not write = any(Ssa::WriteDefinition def).getWriteAccess() and
|
||||
// avoid overlap with the unused variable query
|
||||
not isUnused(v)
|
||||
select write, "Variable $@ is assigned a value that is never used.", v, v.getText()
|
||||
|
||||
@@ -120,7 +120,7 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
|
||||
}
|
||||
|
||||
QualifiedCallable getAsExprEnclosingCallable(NodeExtended node) {
|
||||
result.getFunction() = node.asExpr().getScope()
|
||||
result.getFunction() = node.asExpr().getEnclosingCfgScope()
|
||||
}
|
||||
|
||||
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
models
|
||||
edges
|
||||
| main.rs:9:13:9:19 | ...: ... | main.rs:10:11:10:11 | s | provenance | |
|
||||
| main.rs:10:11:10:11 | s | main.rs:9:30:14:1 | { ... } | provenance | |
|
||||
| main.rs:10:11:10:11 | s | main.rs:12:9:12:9 | s | provenance | |
|
||||
| main.rs:12:9:12:9 | s | main.rs:9:30:14:1 | { ... } | provenance | |
|
||||
| main.rs:21:9:21:9 | s | main.rs:22:10:22:10 | s | provenance | |
|
||||
| main.rs:21:13:21:21 | source(...) | main.rs:21:9:21:9 | s | provenance | |
|
||||
| main.rs:26:9:26:9 | s | main.rs:27:22:27:22 | s | provenance | |
|
||||
@@ -16,6 +17,7 @@ nodes
|
||||
| main.rs:9:13:9:19 | ...: ... | semmle.label | ...: ... |
|
||||
| main.rs:9:30:14:1 | { ... } | semmle.label | { ... } |
|
||||
| main.rs:10:11:10:11 | s | semmle.label | s |
|
||||
| main.rs:12:9:12:9 | s | semmle.label | s |
|
||||
| main.rs:17:10:17:18 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:21:9:21:9 | s | semmle.label | s |
|
||||
| main.rs:21:13:21:21 | source(...) | semmle.label | source(...) |
|
||||
|
||||
@@ -82,12 +82,14 @@ localStep
|
||||
| main.rs:57:9:57:9 | a | main.rs:57:9:57:9 | [SSA] a |
|
||||
| main.rs:57:9:57:9 | a | main.rs:57:9:57:9 | a |
|
||||
| main.rs:57:13:59:5 | loop { ... } | main.rs:57:9:57:9 | a |
|
||||
| main.rs:57:18:59:5 | { ... } | main.rs:57:13:59:5 | loop { ... } |
|
||||
| main.rs:58:9:58:15 | break 1 | main.rs:57:13:59:5 | loop { ... } |
|
||||
| main.rs:58:15:58:15 | 1 | main.rs:58:9:58:15 | break 1 |
|
||||
| main.rs:61:9:61:9 | [SSA] b | main.rs:64:10:64:10 | b |
|
||||
| main.rs:61:9:61:9 | b | main.rs:61:9:61:9 | [SSA] b |
|
||||
| main.rs:61:9:61:9 | b | main.rs:61:9:61:9 | b |
|
||||
| main.rs:61:13:63:5 | loop { ... } | main.rs:61:9:61:9 | b |
|
||||
| main.rs:61:18:63:5 | { ... } | main.rs:61:13:63:5 | loop { ... } |
|
||||
| main.rs:62:9:62:23 | break ... | main.rs:61:13:63:5 | loop { ... } |
|
||||
| main.rs:62:15:62:23 | source(...) | main.rs:62:9:62:23 | break ... |
|
||||
| main.rs:68:9:68:13 | mut i | main.rs:68:13:68:13 | i |
|
||||
@@ -131,6 +133,7 @@ localStep
|
||||
| main.rs:92:9:92:9 | a | main.rs:92:9:92:9 | [SSA] a |
|
||||
| main.rs:92:9:92:9 | a | main.rs:92:9:92:9 | a |
|
||||
| main.rs:92:13:97:5 | 'block: { ... } | main.rs:92:9:92:9 | a |
|
||||
| main.rs:93:14:95:9 | { ... } | main.rs:93:9:95:9 | if b {...} |
|
||||
| main.rs:94:13:94:26 | break 'block 1 | main.rs:92:13:97:5 | 'block: { ... } |
|
||||
| main.rs:94:26:94:26 | 1 | main.rs:94:13:94:26 | break 'block 1 |
|
||||
| main.rs:96:9:96:9 | 2 | main.rs:92:13:97:5 | 'block: { ... } |
|
||||
@@ -143,6 +146,7 @@ localStep
|
||||
| main.rs:102:9:102:9 | a | main.rs:102:9:102:9 | [SSA] a |
|
||||
| main.rs:102:9:102:9 | a | main.rs:102:9:102:9 | a |
|
||||
| main.rs:102:13:107:5 | 'block: { ... } | main.rs:102:9:102:9 | a |
|
||||
| main.rs:103:14:105:9 | { ... } | main.rs:103:9:105:9 | if b {...} |
|
||||
| main.rs:104:13:104:26 | break 'block 1 | main.rs:102:13:107:5 | 'block: { ... } |
|
||||
| main.rs:104:26:104:26 | 1 | main.rs:104:13:104:26 | break 'block 1 |
|
||||
| main.rs:106:9:106:22 | break 'block 2 | main.rs:102:13:107:5 | 'block: { ... } |
|
||||
@@ -713,6 +717,7 @@ localStep
|
||||
| main.rs:480:16:480:19 | name | main.rs:480:16:480:19 | [SSA] name |
|
||||
| main.rs:480:16:480:19 | name | main.rs:480:16:480:19 | name |
|
||||
| main.rs:481:9:485:9 | if cond {...} | main.rs:480:31:486:5 | { ... } |
|
||||
| main.rs:481:17:485:9 | { ... } | main.rs:481:9:485:9 | if cond {...} |
|
||||
| main.rs:482:17:482:17 | [SSA] n | main.rs:483:18:483:18 | n |
|
||||
| main.rs:482:17:482:17 | n | main.rs:482:17:482:17 | [SSA] n |
|
||||
| main.rs:482:17:482:17 | n | main.rs:482:17:482:17 | n |
|
||||
|
||||
@@ -163,8 +163,9 @@ edges
|
||||
| main.rs:352:11:352:12 | s1 [A] | main.rs:356:11:356:12 | s1 [A] | provenance | |
|
||||
| main.rs:353:9:353:25 | ...::A(...) [A] | main.rs:353:24:353:24 | n | provenance | |
|
||||
| main.rs:353:24:353:24 | n | main.rs:353:35:353:35 | n | provenance | |
|
||||
| main.rs:356:11:356:12 | s1 [A] | main.rs:357:9:357:25 | ...::A(...) [A] | provenance | |
|
||||
| main.rs:356:11:356:12 | s1 [A] | main.rs:357:9:357:45 | ... \| ... [A] | provenance | |
|
||||
| main.rs:357:9:357:25 | ...::A(...) [A] | main.rs:357:24:357:24 | n | provenance | |
|
||||
| main.rs:357:9:357:45 | ... \| ... [A] | main.rs:357:9:357:25 | ...::A(...) [A] | provenance | |
|
||||
| main.rs:357:24:357:24 | n | main.rs:357:55:357:55 | n | provenance | |
|
||||
| main.rs:368:9:368:10 | s1 [A] | main.rs:370:11:370:12 | s1 [A] | provenance | |
|
||||
| main.rs:368:14:368:26 | A(...) [A] | main.rs:368:9:368:10 | s1 [A] | provenance | |
|
||||
@@ -173,8 +174,9 @@ edges
|
||||
| main.rs:370:11:370:12 | s1 [A] | main.rs:374:11:374:12 | s1 [A] | provenance | |
|
||||
| main.rs:371:9:371:12 | A(...) [A] | main.rs:371:11:371:11 | n | provenance | |
|
||||
| main.rs:371:11:371:11 | n | main.rs:371:22:371:22 | n | provenance | |
|
||||
| main.rs:374:11:374:12 | s1 [A] | main.rs:375:9:375:12 | A(...) [A] | provenance | |
|
||||
| main.rs:374:11:374:12 | s1 [A] | main.rs:375:9:375:19 | ... \| ... [A] | provenance | |
|
||||
| main.rs:375:9:375:12 | A(...) [A] | main.rs:375:11:375:11 | n | provenance | |
|
||||
| main.rs:375:9:375:19 | ... \| ... [A] | main.rs:375:9:375:12 | A(...) [A] | provenance | |
|
||||
| main.rs:375:11:375:11 | n | main.rs:375:29:375:29 | n | provenance | |
|
||||
| main.rs:389:9:389:10 | s1 [C] | main.rs:393:11:393:12 | s1 [C] | provenance | |
|
||||
| main.rs:389:14:391:5 | ...::C {...} [C] | main.rs:389:9:389:10 | s1 [C] | provenance | |
|
||||
@@ -183,8 +185,9 @@ edges
|
||||
| main.rs:393:11:393:12 | s1 [C] | main.rs:397:11:397:12 | s1 [C] | provenance | |
|
||||
| main.rs:394:9:394:38 | ...::C {...} [C] | main.rs:394:36:394:36 | n | provenance | |
|
||||
| main.rs:394:36:394:36 | n | main.rs:394:48:394:48 | n | provenance | |
|
||||
| main.rs:397:11:397:12 | s1 [C] | main.rs:398:9:398:38 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:397:11:397:12 | s1 [C] | main.rs:398:9:398:71 | ... \| ... [C] | provenance | |
|
||||
| main.rs:398:9:398:38 | ...::C {...} [C] | main.rs:398:36:398:36 | n | provenance | |
|
||||
| main.rs:398:9:398:71 | ... \| ... [C] | main.rs:398:9:398:38 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:398:36:398:36 | n | main.rs:398:81:398:81 | n | provenance | |
|
||||
| main.rs:409:9:409:10 | s1 [C] | main.rs:413:11:413:12 | s1 [C] | provenance | |
|
||||
| main.rs:409:14:411:5 | C {...} [C] | main.rs:409:9:409:10 | s1 [C] | provenance | |
|
||||
@@ -193,8 +196,9 @@ edges
|
||||
| main.rs:413:11:413:12 | s1 [C] | main.rs:417:11:417:12 | s1 [C] | provenance | |
|
||||
| main.rs:414:9:414:24 | C {...} [C] | main.rs:414:22:414:22 | n | provenance | |
|
||||
| main.rs:414:22:414:22 | n | main.rs:414:34:414:34 | n | provenance | |
|
||||
| main.rs:417:11:417:12 | s1 [C] | main.rs:418:9:418:24 | C {...} [C] | provenance | |
|
||||
| main.rs:417:11:417:12 | s1 [C] | main.rs:418:9:418:43 | ... \| ... [C] | provenance | |
|
||||
| main.rs:418:9:418:24 | C {...} [C] | main.rs:418:22:418:22 | n | provenance | |
|
||||
| main.rs:418:9:418:43 | ... \| ... [C] | main.rs:418:9:418:24 | C {...} [C] | provenance | |
|
||||
| main.rs:418:22:418:22 | n | main.rs:418:53:418:53 | n | provenance | |
|
||||
| main.rs:430:9:430:12 | arr1 [element] | main.rs:431:14:431:17 | arr1 [element] | provenance | |
|
||||
| main.rs:430:16:430:33 | [...] [element] | main.rs:430:9:430:12 | arr1 [element] | provenance | |
|
||||
@@ -443,6 +447,7 @@ nodes
|
||||
| main.rs:353:35:353:35 | n | semmle.label | n |
|
||||
| main.rs:356:11:356:12 | s1 [A] | semmle.label | s1 [A] |
|
||||
| main.rs:357:9:357:25 | ...::A(...) [A] | semmle.label | ...::A(...) [A] |
|
||||
| main.rs:357:9:357:45 | ... \| ... [A] | semmle.label | ... \| ... [A] |
|
||||
| main.rs:357:24:357:24 | n | semmle.label | n |
|
||||
| main.rs:357:55:357:55 | n | semmle.label | n |
|
||||
| main.rs:368:9:368:10 | s1 [A] | semmle.label | s1 [A] |
|
||||
@@ -454,6 +459,7 @@ nodes
|
||||
| main.rs:371:22:371:22 | n | semmle.label | n |
|
||||
| main.rs:374:11:374:12 | s1 [A] | semmle.label | s1 [A] |
|
||||
| main.rs:375:9:375:12 | A(...) [A] | semmle.label | A(...) [A] |
|
||||
| main.rs:375:9:375:19 | ... \| ... [A] | semmle.label | ... \| ... [A] |
|
||||
| main.rs:375:11:375:11 | n | semmle.label | n |
|
||||
| main.rs:375:29:375:29 | n | semmle.label | n |
|
||||
| main.rs:389:9:389:10 | s1 [C] | semmle.label | s1 [C] |
|
||||
@@ -465,6 +471,7 @@ nodes
|
||||
| main.rs:394:48:394:48 | n | semmle.label | n |
|
||||
| main.rs:397:11:397:12 | s1 [C] | semmle.label | s1 [C] |
|
||||
| main.rs:398:9:398:38 | ...::C {...} [C] | semmle.label | ...::C {...} [C] |
|
||||
| main.rs:398:9:398:71 | ... \| ... [C] | semmle.label | ... \| ... [C] |
|
||||
| main.rs:398:36:398:36 | n | semmle.label | n |
|
||||
| main.rs:398:81:398:81 | n | semmle.label | n |
|
||||
| main.rs:409:9:409:10 | s1 [C] | semmle.label | s1 [C] |
|
||||
@@ -476,6 +483,7 @@ nodes
|
||||
| main.rs:414:34:414:34 | n | semmle.label | n |
|
||||
| main.rs:417:11:417:12 | s1 [C] | semmle.label | s1 [C] |
|
||||
| main.rs:418:9:418:24 | C {...} [C] | semmle.label | C {...} [C] |
|
||||
| main.rs:418:9:418:43 | ... \| ... [C] | semmle.label | ... \| ... [C] |
|
||||
| main.rs:418:22:418:22 | n | semmle.label | n |
|
||||
| main.rs:418:53:418:53 | n | semmle.label | n |
|
||||
| main.rs:430:9:430:12 | arr1 [element] | semmle.label | arr1 [element] |
|
||||
|
||||
@@ -16,7 +16,7 @@ module MyFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CallExpr call |
|
||||
call.getFunction().(PathExpr).getPath().getSegment().getIdentifier().getText() = "sink"
|
||||
).getArgList().getAnArg() = sink.asExpr().getExpr()
|
||||
).getArgList().getAnArg() = sink.asExpr()
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
|
||||
@@ -13,7 +13,7 @@ module SensitiveDataConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CallExpr call |
|
||||
call.getFunction().(PathExpr).getPath().getSegment().getIdentifier().getText() = "sink"
|
||||
).getArgList().getAnArg() = sink.asExpr().getExpr()
|
||||
).getArgList().getAnArg() = sink.asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,17 +10,17 @@ query predicate definition(Ssa::Definition def, Variable v) {
|
||||
toBeTested(v.getEnclosingCfgScope()) and def.getSourceVariable() = v
|
||||
}
|
||||
|
||||
query predicate read(Ssa::Definition def, Variable v, CfgNode read) {
|
||||
query predicate read(Ssa::Definition def, Variable v, Expr read) {
|
||||
toBeTested(v.getEnclosingCfgScope()) and def.getSourceVariable() = v and read = def.getARead()
|
||||
}
|
||||
|
||||
query predicate firstRead(Ssa::Definition def, Variable v, CfgNode read) {
|
||||
query predicate firstRead(Ssa::Definition def, Variable v, Expr read) {
|
||||
toBeTested(v.getEnclosingCfgScope()) and
|
||||
def.getSourceVariable() = v and
|
||||
read = def.getAFirstRead()
|
||||
}
|
||||
|
||||
query predicate adjacentReads(Ssa::Definition def, Variable v, CfgNode read1, CfgNode read2) {
|
||||
query predicate adjacentReads(Ssa::Definition def, Variable v, Expr read1, Expr read2) {
|
||||
toBeTested(v.getEnclosingCfgScope()) and
|
||||
def.getSourceVariable() = v and
|
||||
def.hasAdjacentReads(read1, read2)
|
||||
@@ -54,4 +54,4 @@ query predicate ultimateDef(Ssa::Definition def, Definition ult) {
|
||||
ult != def
|
||||
}
|
||||
|
||||
query predicate assigns(Ssa::WriteDefinition def, CfgNode value) { def.assigns(value) }
|
||||
query predicate assigns(Ssa::WriteDefinition def, Expr value) { def.assigns(value) }
|
||||
|
||||
Reference in New Issue
Block a user