Skip to content

Commit 212884c

Browse files
authored
Merge pull request #19106 from hvitved/rust/reverse-post-update-steps
Rust: Add reverse post-update flow steps
2 parents 278d251 + f45eca7 commit 212884c

File tree

10 files changed

+378
-246
lines changed

10 files changed

+378
-246
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ private module Input implements InputSig<Location, RustDataFlow> {
1818
// We allow flow into post-update node for receiver expressions (from the
1919
// synthetic post receiever node).
2020
n.(Node::PostUpdateNode).getPreUpdateNode().asExpr() = any(Node::ReceiverNode r).getReceiver()
21+
or
22+
n.(Node::PostUpdateNode).getPreUpdateNode().asExpr() = getPostUpdateReverseStep(_, _)
2123
}
2224

2325
predicate missingLocationExclude(RustDataFlow::Node n) { not exists(n.asExpr().getLocation()) }

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,28 @@ private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
213213
result.(BreakExprCfgNode).getTarget() = e
214214
}
215215

216+
/**
217+
* Holds if a reverse local flow step should be added from the post-update node
218+
* for `e` to the post-update node for the result.
219+
*
220+
* This is needed to allow for side-effects on compound expressions to propagate
221+
* to sub components. For example, in
222+
*
223+
* ```rust
224+
* ({ foo(); &mut a}).set_data(taint);
225+
* ```
226+
*
227+
* we add a reverse flow step from `[post] { foo(); &mut a}` to `[post] &mut a`,
228+
* in order for the side-effect of `set_data` to reach `&mut a`.
229+
*/
230+
ExprCfgNode getPostUpdateReverseStep(ExprCfgNode e, boolean preservesValue) {
231+
result = getALastEvalNode(e) and
232+
preservesValue = true
233+
or
234+
result = e.(CastExprCfgNode).getExpr() and
235+
preservesValue = false
236+
}
237+
216238
module LocalFlow {
217239
predicate flowSummaryLocalStep(Node nodeFrom, Node nodeTo, string model) {
218240
exists(FlowSummaryImpl::Public::SummarizedCallable c |
@@ -274,6 +296,9 @@ module LocalFlow {
274296
// The dual step of the above, for the post-update nodes.
275297
nodeFrom.(PostUpdateNode).getPreUpdateNode().(ReceiverNode).getReceiver() =
276298
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr()
299+
or
300+
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() =
301+
getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr(), true)
277302
}
278303
}
279304

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ abstract class NodePublic extends TNode {
2929
/**
3030
* Gets the expression that corresponds to this node, if any.
3131
*/
32-
ExprCfgNode asExpr() { none() }
32+
final ExprCfgNode asExpr() { this = TExprNode(result) }
3333

3434
/**
3535
* Gets the parameter that corresponds to this node, if any.
@@ -39,7 +39,7 @@ abstract class NodePublic extends TNode {
3939
/**
4040
* Gets the pattern that corresponds to this node, if any.
4141
*/
42-
PatCfgNode asPat() { none() }
42+
final PatCfgNode asPat() { this = TPatNode(result) }
4343
}
4444

4545
abstract class Node extends NodePublic {
@@ -144,16 +144,12 @@ class ExprNode extends AstCfgFlowNode, TExprNode {
144144
override ExprCfgNode n;
145145

146146
ExprNode() { this = TExprNode(n) }
147-
148-
override ExprCfgNode asExpr() { result = n }
149147
}
150148

151149
final class PatNode extends AstCfgFlowNode, TPatNode {
152150
override PatCfgNode n;
153151

154152
PatNode() { this = TPatNode(n) }
155-
156-
override PatCfgNode asPat() { result = n }
157153
}
158154

159155
/** A data flow node that corresponds to a name node in the CFG. */
@@ -467,10 +463,12 @@ newtype TNode =
467463
or
468464
e =
469465
[
470-
any(IndexExprCfgNode i).getBase(), any(FieldExprCfgNode access).getExpr(),
471-
any(TryExprCfgNode try).getExpr(),
472-
any(PrefixExprCfgNode pe | pe.getOperatorName() = "*").getExpr(),
473-
any(AwaitExprCfgNode a).getExpr(), any(MethodCallExprCfgNode mc).getReceiver()
466+
any(IndexExprCfgNode i).getBase(), //
467+
any(FieldExprCfgNode access).getExpr(), //
468+
any(TryExprCfgNode try).getExpr(), //
469+
any(PrefixExprCfgNode pe | pe.getOperatorName() = "*").getExpr(), //
470+
any(AwaitExprCfgNode a).getExpr(), any(MethodCallExprCfgNode mc).getReceiver(), //
471+
getPostUpdateReverseStep(any(PostUpdateNode n).getPreUpdateNode().asExpr(), _)
474472
]
475473
} or
476474
TReceiverNode(MethodCallExprCfgNode mc, Boolean isPost) or

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ import Cached
332332
private import codeql.rust.dataflow.Ssa
333333

334334
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
335+
private import codeql.rust.dataflow.internal.DataFlowImpl as DataFlowImpl
336+
335337
class Expr extends CfgNodes::AstCfgNode {
336338
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
337339
}
@@ -343,14 +345,22 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
343345
none() // handled in `DataFlowImpl.qll` instead
344346
}
345347

348+
private predicate isArg(CfgNodes::CallExprBaseCfgNode call, CfgNodes::ExprCfgNode e) {
349+
call.getArgument(_) = e
350+
or
351+
call.(CfgNodes::MethodCallExprCfgNode).getReceiver() = e
352+
or
353+
exists(CfgNodes::ExprCfgNode mid |
354+
isArg(call, mid) and
355+
e = DataFlowImpl::getPostUpdateReverseStep(mid, _)
356+
)
357+
}
358+
346359
predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) {
347360
exists(CfgNodes::CallExprBaseCfgNode call, Variable v, BasicBlock bb, int i |
348361
def.definesAt(v, bb, i) and
349-
mutablyBorrows(bb.getNode(i).getAstNode(), v)
350-
|
351-
call.getArgument(_) = bb.getNode(i)
352-
or
353-
call.(CfgNodes::MethodCallExprCfgNode).getReceiver() = bb.getNode(i)
362+
mutablyBorrows(bb.getNode(i).getAstNode(), v) and
363+
isArg(call, bb.getNode(i))
354364
)
355365
}
356366

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
5353
exists(FormatArgsExprCfgNode format | succ.asExpr() = format |
5454
pred.asExpr() = [format.getArgumentExpr(_), format.getFormatTemplateVariableAccess(_)]
5555
)
56+
or
57+
succ.(Node::PostUpdateNode).getPreUpdateNode().asExpr() =
58+
getPostUpdateReverseStep(pred.(Node::PostUpdateNode).getPreUpdateNode().asExpr(), false)
5659
)
5760
or
5861
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred.(Node::FlowSummaryNode).getSummaryNode(),

0 commit comments

Comments
 (0)