Skip to content

Commit 7248fb7

Browse files
authored
Merge pull request #18394 from paldepind/rust-format
Rust: Value flow and taint flow through formatting strings
2 parents 01a7a53 + c55b256 commit 7248fb7

38 files changed

+358
-99
lines changed

rust/ql/.generated.list

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

+47
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,53 @@ final class MethodCallExprCfgNode extends CallExprBaseCfgNode, Nodes::MethodCall
173173
*/
174174
final class CallExprCfgNode extends CallExprBaseCfgNode, Nodes::CallExprCfgNode { }
175175

176+
/**
177+
* A FormatArgsExpr. For example:
178+
* ```rust
179+
* format_args!("no args");
180+
* format_args!("{} foo {:?}", 1, 2);
181+
* format_args!("{b} foo {a:?}", a=1, b=2);
182+
* let (x, y) = (1, 42);
183+
* format_args!("{x}, {y}");
184+
* ```
185+
*/
186+
final class FormatArgsExprCfgNode extends Nodes::FormatArgsExprCfgNode {
187+
private FormatArgsExprChildMapping node;
188+
189+
FormatArgsExprCfgNode() { node = this.getAstNode() }
190+
191+
/** Gets the `i`th argument of this format arguments expression (0-based). */
192+
ExprCfgNode getArgumentExpr(int i) {
193+
any(ChildMapping mapping).hasCfgChild(node, node.getArg(i).getExpr(), this, result)
194+
}
195+
196+
/** Gets a format argument of the `i`th format of this format arguments expression (0-based). */
197+
FormatTemplateVariableAccessCfgNode getFormatTemplateVariableAccess(int i) {
198+
exists(FormatTemplateVariableAccess v |
199+
v.getArgument() = node.getFormat(i).getArgument() and
200+
result.getFormatTemplateVariableAccess() = v and
201+
any(ChildMapping mapping).hasCfgChild(node, v, this, result)
202+
)
203+
}
204+
}
205+
206+
/**
207+
* A MacroCall. For example:
208+
* ```rust
209+
* todo!()
210+
* ```
211+
*/
212+
final class MacroCallCfgNode extends Nodes::MacroCallCfgNode {
213+
private MacroCallChildMapping node;
214+
215+
MacroCallCfgNode() { node = this.getAstNode() }
216+
217+
/** Gets the CFG node for the expansion of this macro call, if it exists. */
218+
CfgNode getExpandedNode() {
219+
any(ChildMapping mapping).hasCfgChild(node, node.getExpanded(), this, result)
220+
}
221+
}
222+
176223
/**
177224
* A record expression. For example:
178225
* ```rust

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

+4
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ class RecordPatChildMapping extends ParentAstNode, RecordPat {
7474
}
7575
}
7676

77+
class MacroCallChildMapping extends ParentAstNode, MacroCall {
78+
override predicate relevantChild(AstNode child) { child = this.getExpanded() }
79+
}
80+
7781
class FormatArgsExprChildMapping extends ParentAstNode, CfgImpl::ExprTrees::FormatArgsExprTree {
7882
override predicate relevantChild(AstNode child) { child = this.getChildNode(_) }
7983
}

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

+2-18
Original file line numberDiff line numberDiff line change
@@ -131,24 +131,8 @@ class LetStmtTree extends PreOrderTree, LetStmt {
131131
}
132132
}
133133

134-
class MacroCallTree extends ControlFlowTree, MacroCall {
135-
override predicate first(AstNode first) {
136-
first(this.getExpanded(), first)
137-
or
138-
not exists(this.getExpanded()) and first = this
139-
}
140-
141-
override predicate last(AstNode last, Completion c) {
142-
last(this.getExpanded(), last, c)
143-
or
144-
not exists(this.getExpanded()) and
145-
last = this and
146-
completionIsValidFor(c, last)
147-
}
148-
149-
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
150-
151-
override predicate propagatesAbnormal(AstNode child) { child = this.getExpanded() }
134+
class MacroCallTree extends StandardPostOrderTree, MacroCall {
135+
override AstNode getChildNode(int i) { i = 0 and result = this.getExpanded() }
152136
}
153137

154138
class MacroStmtsTree extends StandardPreOrderTree, MacroStmts {

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

+74-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

+1
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
522522
result = e.(BreakExprCfgNode).getExpr() or
523523
result = e.(BlockExprCfgNode).getTailExpr() or
524524
result = e.(MatchExprCfgNode).getArmExpr(_) or
525+
result = e.(MacroExprCfgNode).getMacroCall().(MacroCallCfgNode).getExpandedNode() or
525526
result.(BreakExprCfgNode).getTarget() = e
526527
}
527528

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

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
4646
RustDataFlow::readStep(pred, cs, succ) and
4747
cs.getContent() instanceof ArrayElementContent
4848
)
49+
or
50+
exists(FormatArgsExprCfgNode format | succ.asExpr() = format |
51+
pred.asExpr() = [format.getArgumentExpr(_), format.getFormatTemplateVariableAccess(_)]
52+
)
4953
)
5054
or
5155
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred.(Node::FlowSummaryNode).getSummaryNode(),

rust/ql/lib/codeql/rust/elements/Format.qll

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/FormatArgsArg.qll

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/FormatArgsArgImpl.qll

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/FormatImpl.qll

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ module Impl {
2323
* ```rust
2424
* println!("Hello {}", "world");
2525
* ```
26+
* or the `{value:#width$.precision$}` in:
27+
* ```rust
28+
* println!("Value {value:#width$.precision$}");
29+
* ```
2630
*/
2731
class Format extends Generated::Format {
2832
private Raw::FormatArgsExpr parent;

rust/ql/lib/codeql/rust/elements/internal/generated/Format.qll

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/generated/FormatArgsArg.qll

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml

+4
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ extensions:
1313
- ["lang:core", "<crate::result::Result>::unwrap_or", "Argument[0]", "ReturnValue", "value", "manual"]
1414
# String
1515
- ["lang:alloc", "<crate::string::String>::as_str", "Argument[self]", "ReturnValue", "taint", "manual"]
16+
# Hint
17+
- ["lang:core", "crate::hint::must_use", "Argument[0]", "ReturnValue", "value", "manual"]
18+
# Fmt
19+
- ["lang:alloc", "crate::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"]

rust/ql/test/extractor-tests/generated/.generated_tests.list

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)