Skip to content

Commit ff7dd62

Browse files
committed
wip
1 parent 014b925 commit ff7dd62

File tree

80 files changed

+1454
-1387
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1454
-1387
lines changed

rust/ql/examples/snippets/simple_constant_password.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ module ConstantPasswordConfig implements DataFlow::ConfigSig {
3030

3131
predicate isSink(DataFlow::Node node) {
3232
// `node` is an argument whose corresponding parameter name matches the pattern "pass%"
33-
exists(CallExpr call, Function target, int argIndex, Variable v |
33+
exists(FunctionCall call, Function target, int argIndex, Variable v |
3434
call.getStaticTarget() = target and
3535
v.getParameter() = target.getParam(argIndex) and
3636
v.getText().matches("pass%") and
37-
call.getArg(argIndex) = node.asExpr()
37+
call.getArgument(argIndex) = node.asExpr()
3838
)
3939
}
4040
}

rust/ql/examples/snippets/simple_sql_injection.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ module SqlInjectionConfig implements DataFlow::ConfigSig {
2323

2424
predicate isSink(DataFlow::Node node) {
2525
// `node` is the first argument of a call to `sqlx_core::query::query`
26-
exists(CallExpr call |
26+
exists(FunctionCall call |
2727
call.getStaticTarget().getCanonicalPath() = "sqlx_core::query::query" and
28-
call.getArg(0) = node.asExpr()
28+
call.getArgument(0) = node.asExpr()
2929
)
3030
}
3131
}

rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -201,28 +201,23 @@ final class BreakExprCfgNode extends Nodes::BreakExprCfgNode {
201201
}
202202

203203
/**
204-
* A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details.
204+
* A method call expression. For example:
205+
* ```rust
206+
* x.foo(42);
207+
* x.foo::<u32, u64>(42);
208+
* ```
205209
*/
206-
final class CallExprBaseCfgNode extends Nodes::CallExprBaseCfgNode {
207-
private CallExprBaseChildMapping node;
210+
final class MethodCallExprCfgNode extends Nodes::MethodCallExprCfgNode {
211+
private MethodCallExprChildMapping node;
208212

209-
CallExprBaseCfgNode() { node = this.getAstNode() }
213+
MethodCallExprCfgNode() { node = this.getAstNode() }
210214

211215
/** Gets the `i`th argument of this call. */
212216
ExprCfgNode getArgument(int i) {
213217
any(ChildMapping mapping).hasCfgChild(node, node.getArgList().getArg(i), this, result)
214218
}
215219
}
216220

217-
/**
218-
* A method call expression. For example:
219-
* ```rust
220-
* x.foo(42);
221-
* x.foo::<u32, u64>(42);
222-
* ```
223-
*/
224-
final class MethodCallExprCfgNode extends CallExprBaseCfgNode, Nodes::MethodCallExprCfgNode { }
225-
226221
/**
227222
* A CFG node that calls a function.
228223
*
@@ -242,8 +237,8 @@ final class CallCfgNode extends ExprCfgNode {
242237
}
243238

244239
/** Gets the `i`th argument of this call, if any. */
245-
ExprCfgNode getPositionalArgument(int i) {
246-
any(ChildMapping mapping).hasCfgChild(node, node.getPositionalArgument(i), this, result)
240+
ExprCfgNode getArgument(int i) {
241+
any(ChildMapping mapping).hasCfgChild(node, node.getArgument(i), this, result)
247242
}
248243
}
249244

@@ -256,7 +251,16 @@ final class CallCfgNode extends ExprCfgNode {
256251
* foo(1) = 4;
257252
* ```
258253
*/
259-
final class CallExprCfgNode extends CallExprBaseCfgNode, Nodes::CallExprCfgNode { }
254+
final class CallExprCfgNode extends Nodes::CallExprCfgNode {
255+
private CallExprChildMapping node;
256+
257+
CallExprCfgNode() { node = this.getAstNode() }
258+
259+
/** Gets the `i`th argument of this call. */
260+
ExprCfgNode getArgument(int i) {
261+
any(ChildMapping mapping).hasCfgChild(node, node.getArgList().getArg(i), this, result)
262+
}
263+
}
260264

261265
/**
262266
* A FormatArgsExpr. For example:

rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ class BreakExprTargetChildMapping extends ParentAstNode, Expr {
5757
override predicate relevantChild(AstNode child) { child.(BreakExpr).getTarget() = this }
5858
}
5959

60-
class CallExprBaseChildMapping extends ParentAstNode, CallExprBase {
61-
override predicate relevantChild(AstNode child) { child = this.getAnArg() }
60+
class CallExprChildMapping extends ParentAstNode, CallExpr {
61+
override predicate relevantChild(AstNode child) { child = this.getArgList().getAnArg() }
62+
}
63+
64+
class MethodCallExprChildMapping extends ParentAstNode, MethodCallExpr {
65+
override predicate relevantChild(AstNode child) { child = this.getArgList().getAnArg() }
6266
}
6367

6468
class StructExprChildMapping extends ParentAstNode, StructExpr {

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ module ExprTrees {
512512

513513
class MethodCallExprTree extends StandardPostOrderTree, MethodCallExpr {
514514
override AstNode getChildNode(int i) {
515-
if i = 0 then result = this.getReceiver() else result = this.getArg(i - 1)
515+
if i = 0 then result = this.getReceiver() else result = this.getArgList().getArg(i - 1)
516516
}
517517
}
518518

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowConsistency.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ private module Input implements InputSig<Location, RustDataFlow> {
2121
or
2222
// We allow flow into post-update node for receiver expressions (from the
2323
// synthetic post receiever node).
24-
n.(Node::PostUpdateNode).getPreUpdateNode().asExpr() = any(Node::ReceiverNode r).getReceiver()
24+
n.(Node::PostUpdateNode).getPreUpdateNode().asExpr() = any(Node::DerefBorrowNode r).getNode()
2525
or
2626
n.(Node::PostUpdateNode).getPreUpdateNode().asExpr() = getPostUpdateReverseStep(_, _)
2727
or

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 45 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ private import codeql.rust.elements.Call
1212
private import SsaImpl as SsaImpl
1313
private import codeql.rust.controlflow.internal.Scope as Scope
1414
private import codeql.rust.internal.PathResolution
15-
private import codeql.rust.internal.TypeInference as TypeInference
1615
private import codeql.rust.controlflow.ControlFlowGraph
1716
private import codeql.rust.dataflow.Ssa
1817
private import codeql.rust.dataflow.FlowSummary
@@ -58,8 +57,8 @@ final class DataFlowCallable extends TDataFlowCallable {
5857
}
5958

6059
final class DataFlowCall extends TDataFlowCall {
61-
/** Gets the underlying call in the CFG, if any. */
62-
Call asCall() { this = TCall(result) }
60+
/** Gets the underlying function call, if any. */
61+
FunctionCall asFunctionCall() { this = TFunctionCall(result) }
6362

6463
predicate isSummaryCall(
6564
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
@@ -68,13 +67,13 @@ final class DataFlowCall extends TDataFlowCall {
6867
}
6968

7069
DataFlowCallable getEnclosingCallable() {
71-
result.asCfgScope() = this.asCall().getEnclosingCfgScope()
70+
result.asCfgScope() = this.asFunctionCall().getEnclosingCfgScope()
7271
or
7372
this.isSummaryCall(result.asSummarizedCallable(), _)
7473
}
7574

7675
string toString() {
77-
result = this.asCall().toString()
76+
result = this.asFunctionCall().toString()
7877
or
7978
exists(
8079
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
@@ -84,13 +83,13 @@ final class DataFlowCall extends TDataFlowCall {
8483
)
8584
}
8685

87-
Location getLocation() { result = this.asCall().getLocation() }
86+
Location getLocation() { result = this.asFunctionCall().getLocation() }
8887
}
8988

9089
/**
9190
* The position of a parameter in a function.
9291
*
93-
* In Rust there is a 1-to-1 correspondence between parameter positions and
92+
* In Rust there is a 1-to-1 correspondence between parameter positions and
9493
* arguments positions, so we use the same underlying type for both.
9594
*/
9695
final class ParameterPosition extends TParameterPosition {
@@ -133,26 +132,18 @@ final class ParameterPosition extends TParameterPosition {
133132
final class ArgumentPosition extends ParameterPosition {
134133
/** Gets the argument of `call` at this position, if any. */
135134
Expr getArgument(Call call) {
136-
result = call.getPositionalArgument(this.getPosition())
135+
result = call.getArgument(this.getPosition())
137136
or
138-
result = call.getReceiver() and this.isSelf()
137+
this.isSelf() and
138+
result = call.getReceiver()
139139
}
140140
}
141141

142142
/**
143143
* Holds if `arg` is an argument of `call` at the position `pos`.
144-
*
145-
* Note that this does not hold for the receiever expression of a method call
146-
* as the synthetic `ReceiverNode` is the argument for the `self` parameter.
147144
*/
148-
predicate isArgumentForCall(Expr arg, Call call, ParameterPosition pos) {
149-
// TODO: Handle index expressions as calls in data flow.
150-
not call instanceof IndexExpr and
151-
(
152-
call.getPositionalArgument(pos.getPosition()) = arg
153-
or
154-
call.getReceiver() = arg and pos.isSelf() and not call.receiverImplicitlyBorrowed()
155-
)
145+
predicate isArgumentForCall(Expr arg, FunctionCall call, ArgumentPosition pos) {
146+
arg = pos.getArgument(call)
156147
}
157148

158149
/** Provides logic related to SSA. */
@@ -283,14 +274,6 @@ module LocalFlow {
283274
or
284275
nodeFrom.asPat().(OrPat).getAPat() = nodeTo.asPat()
285276
or
286-
// Simple value step from receiver expression to receiver node, in case
287-
// there is no implicit deref or borrow operation.
288-
nodeFrom.asExpr() = nodeTo.(ReceiverNode).getReceiver()
289-
or
290-
// The dual step of the above, for the post-update nodes.
291-
nodeFrom.(PostUpdateNode).getPreUpdateNode().(ReceiverNode).getReceiver() =
292-
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr()
293-
or
294277
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() =
295278
getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr(), true)
296279
}
@@ -309,10 +292,8 @@ predicate lambdaCreationExpr(Expr creation) {
309292
* Holds if `call` is a lambda call of kind `kind` where `receiver` is the
310293
* invoked expression.
311294
*/
312-
predicate lambdaCallExpr(CallExpr call, LambdaCallKind kind, Expr receiver) {
295+
predicate lambdaCallExpr(ClosureCall call, LambdaCallKind kind, Expr receiver) {
313296
receiver = call.getFunction() and
314-
// All calls to complex expressions and local variable accesses are lambda call.
315-
(receiver instanceof PathExpr implies receiver = any(Variable v).getAnAccess()) and
316297
exists(kind)
317298
}
318299

@@ -380,7 +361,7 @@ module RustDataFlow implements InputSig<Location> {
380361
node.(FlowSummaryNode).getSummaryNode().isHidden() or
381362
node instanceof CaptureNode or
382363
node instanceof ClosureParameterNode or
383-
node instanceof ReceiverNode or
364+
node instanceof DerefBorrowNode or
384365
node.asExpr() instanceof ParenExpr or
385366
nodeIsHidden(node.(PostUpdateNode).getPreUpdateNode())
386367
}
@@ -422,7 +403,7 @@ module RustDataFlow implements InputSig<Location> {
422403

423404
/** Gets a viable implementation of the target of the given `Call`. */
424405
DataFlowCallable viableCallable(DataFlowCall call) {
425-
exists(Call c | c = call.asCall() |
406+
exists(FunctionCall c | c = call.asFunctionCall() |
426407
result.asCfgScope() = c.getARuntimeTarget()
427408
or
428409
exists(SummarizedCallable sc, Function staticTarget |
@@ -520,16 +501,16 @@ module RustDataFlow implements InputSig<Location> {
520501
}
521502

522503
pragma[nomagic]
523-
private predicate implicitDerefToReceiver(Node node1, ReceiverNode node2, ReferenceContent c) {
524-
TypeInference::receiverHasImplicitDeref(node1.asExpr()) and
525-
node1.asExpr() = node2.getReceiver() and
504+
private predicate implicitDeref(Node node1, DerefBorrowNode node2, ReferenceContent c) {
505+
not node2.isBorrow() and
506+
node1.asExpr() = node2.getNode() and
526507
exists(c)
527508
}
528509

529510
pragma[nomagic]
530-
private predicate implicitBorrowToReceiver(Node node1, ReceiverNode node2, ReferenceContent c) {
531-
TypeInference::receiverHasImplicitBorrow(node1.asExpr()) and
532-
node1.asExpr() = node2.getReceiver() and
511+
private predicate implicitBorrow(Node node1, DerefBorrowNode node2, ReferenceContent c) {
512+
node2.isBorrow() and
513+
node1.asExpr() = node2.getNode() and
533514
exists(c)
534515
}
535516

@@ -539,6 +520,15 @@ module RustDataFlow implements InputSig<Location> {
539520
exists(c)
540521
}
541522

523+
private Node getFieldExprContainerNode(FieldExpr fe) {
524+
exists(Expr container | container = fe.getContainer() |
525+
not any(DerefBorrowNode n).getNode() = container and
526+
result.asExpr() = container
527+
or
528+
result.(DerefBorrowNode).getNode() = container
529+
)
530+
}
531+
542532
pragma[nomagic]
543533
additional predicate readContentStep(Node node1, Content c, Node node2) {
544534
exists(TupleStructPat pat, int pos |
@@ -563,9 +553,9 @@ module RustDataFlow implements InputSig<Location> {
563553
node1.asPat().(RefPat).getPat() = node2.asPat()
564554
or
565555
exists(FieldExpr access |
566-
node1.asExpr() = access.getContainer() and
567556
node2.asExpr() = access and
568-
access = c.(FieldContent).getAnAccess()
557+
access = c.(FieldContent).getAnAccess() and
558+
node1 = getFieldExprContainerNode(access)
569559
)
570560
or
571561
exists(IndexExpr arr |
@@ -616,12 +606,10 @@ module RustDataFlow implements InputSig<Location> {
616606
referenceExprToExpr(node2.(PostUpdateNode).getPreUpdateNode(),
617607
node1.(PostUpdateNode).getPreUpdateNode(), c)
618608
or
619-
// Step from receiver expression to receiver node, in case of an implicit
620-
// dereference.
621-
implicitDerefToReceiver(node1, node2, c)
609+
implicitDeref(node1, node2, c)
622610
or
623611
// A read step dual to the store step for implicit borrows.
624-
implicitBorrowToReceiver(node2.(PostUpdateNode).getPreUpdateNode(),
612+
implicitBorrow(node2.(PostUpdateNode).getPreUpdateNode(),
625613
node1.(PostUpdateNode).getPreUpdateNode(), c)
626614
or
627615
VariableCapture::readStep(node1, c, node2)
@@ -657,7 +645,7 @@ module RustDataFlow implements InputSig<Location> {
657645
exists(AssignmentExpr assignment, FieldExpr access |
658646
assignment.getLhs() = access and
659647
node1.asExpr() = assignment.getRhs() and
660-
node2.asExpr() = access.getContainer() and
648+
node2 = getFieldExprContainerNode(access) and
661649
access = c.getAnAccess()
662650
)
663651
}
@@ -676,7 +664,7 @@ module RustDataFlow implements InputSig<Location> {
676664
pragma[nomagic]
677665
additional predicate storeContentStep(Node node1, Content c, Node node2) {
678666
exists(CallExpr call, int pos |
679-
node1.asExpr() = call.getArg(pragma[only_bind_into](pos)) and
667+
node1.asExpr() = call.getArgument(pragma[only_bind_into](pos)) and
680668
node2.asExpr() = call and
681669
c = TTupleFieldContent(call.getTupleField(pragma[only_bind_into](pos)))
682670
)
@@ -729,9 +717,11 @@ module RustDataFlow implements InputSig<Location> {
729717
or
730718
VariableCapture::storeStep(node1, c, node2)
731719
or
732-
// Step from receiver expression to receiver node, in case of an implicit
733-
// borrow.
734-
implicitBorrowToReceiver(node1, node2, c)
720+
implicitBorrow(node1, node2, c)
721+
or
722+
// A store step dual to the read step for implicit dereferences.
723+
implicitDeref(node2.(PostUpdateNode).getPreUpdateNode(),
724+
node1.(PostUpdateNode).getPreUpdateNode(), c)
735725
}
736726

737727
/**
@@ -835,11 +825,7 @@ module RustDataFlow implements InputSig<Location> {
835825
*/
836826
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
837827
(
838-
receiver.asExpr() = call.asCall().(CallExpr).getFunction() and
839-
// All calls to complex expressions and local variable accesses are lambda call.
840-
exists(Expr f | f = receiver.asExpr() |
841-
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
842-
)
828+
receiver.asExpr() = call.asFunctionCall().(ClosureCall).getFunction()
843829
or
844830
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode())
845831
) and
@@ -1001,11 +987,9 @@ private module Cached {
1001987

1002988
cached
1003989
newtype TDataFlowCall =
1004-
TCall(Call call) {
990+
TFunctionCall(FunctionCall call) {
1005991
Stages::DataFlowStage::ref() and
1006-
call.hasEnclosingCfgScope() and
1007-
// TODO: Handle index expressions as calls in data flow.
1008-
not call instanceof IndexExpr
992+
call.hasEnclosingCfgScope()
1009993
} or
1010994
TSummaryCall(
1011995
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
@@ -1033,10 +1017,8 @@ private module Cached {
10331017
cached
10341018
newtype TParameterPosition =
10351019
TPositionalParameterPosition(int i) {
1036-
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
1037-
or
1038-
FlowSummaryImpl::ParsePositions::isParsedArgumentPosition(_, i)
1039-
or
1020+
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] or
1021+
FlowSummaryImpl::ParsePositions::isParsedArgumentPosition(_, i) or
10401022
FlowSummaryImpl::ParsePositions::isParsedParameterPosition(_, i)
10411023
} or
10421024
TClosureSelfParameterPosition() or

0 commit comments

Comments
 (0)