Skip to content

Commit 9ab7f87

Browse files
authored
Merge pull request #20776 from geoffw0/rustexamples
Rust: Add example queries
2 parents b90d0fd + 9598772 commit 9ab7f87

File tree

7 files changed

+121
-0
lines changed

7 files changed

+121
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
- `CodeQL queries for Rust <https://github.com/github/codeql/tree/main/rust/ql/src>`__
2+
- `Example queries for Rust <https://github.com/github/codeql/tree/main/rust/ql/examples>`__
23
- `CodeQL library reference for Rust <https://codeql.github.com/codeql-standard-libraries/rust/>`__

rust/ql/examples/qlpack.lock.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
dependencies: {}
3+
compiled: false
4+
lockVersion: 1.0.0

rust/ql/examples/qlpack.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: codeql/rust-examples
2+
groups:
3+
- rust
4+
- examples
5+
dependencies:
6+
codeql/rust-all: ${workspace}
7+
warnOnImplicitThis: true
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @name Empty 'if' expression
3+
* @description Finds 'if' expressions where the "then" branch is empty and no
4+
* "else" branch exists.
5+
* @id rust/examples/empty-if
6+
* @tags example
7+
*/
8+
9+
import rust
10+
11+
// find 'if' expressions...
12+
from IfExpr ifExpr
13+
where
14+
// where the 'then' branch is empty
15+
ifExpr.getThen().getStmtList().getNumberOfStmtOrExpr() = 0 and
16+
// and no 'else' branch exists
17+
not ifExpr.hasElse()
18+
select ifExpr, "This 'if' expression is redundant."
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* @name Constant password
3+
* @description Finds places where a string literal is used in a function call
4+
* argument that looks like a password.
5+
* @id rust/examples/simple-constant-password
6+
* @tags example
7+
*/
8+
9+
import rust
10+
import codeql.rust.dataflow.DataFlow
11+
import codeql.rust.dataflow.TaintTracking
12+
13+
/**
14+
* A data flow configuration for tracking flow from a string literal to a function
15+
* call argument that looks like a password. For example:
16+
* ```
17+
* fn set_password(password: &str) { ... }
18+
*
19+
* ...
20+
*
21+
* let pwd = "123456"; // source
22+
* set_password(pwd); // sink (argument 0)
23+
* ```
24+
*/
25+
module ConstantPasswordConfig implements DataFlow::ConfigSig {
26+
predicate isSource(DataFlow::Node node) {
27+
// `node` is a string literal
28+
node.asExpr().getExpr() instanceof StringLiteralExpr
29+
}
30+
31+
predicate isSink(DataFlow::Node node) {
32+
// `node` is an argument whose corresponding parameter name matches the pattern "pass%"
33+
exists(CallExpr call, Function target, int argIndex, Variable v |
34+
call.getStaticTarget() = target and
35+
v.getParameter() = target.getParam(argIndex) and
36+
v.getText().matches("pass%") and
37+
call.getArg(argIndex) = node.asExpr().getExpr()
38+
)
39+
}
40+
}
41+
42+
// instantiate the data flow configuration as a global taint tracking module
43+
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;
44+
45+
// report flows from sources to sinks
46+
from DataFlow::Node sourceNode, DataFlow::Node sinkNode
47+
where ConstantPasswordFlow::flow(sourceNode, sinkNode)
48+
select sinkNode, "The value $@ is used as a constant password.", sourceNode, sourceNode.toString()
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @name Database query built from user-controlled sources
3+
* @description Finds places where a value from a remote or local user input
4+
* is used as the first argument of a call to `sqlx_core::query::query`.
5+
* @id rust/examples/simple-sql-injection
6+
* @tags example
7+
*/
8+
9+
import rust
10+
import codeql.rust.dataflow.DataFlow
11+
import codeql.rust.dataflow.TaintTracking
12+
import codeql.rust.Concepts
13+
14+
/**
15+
* A data flow configuration for tracking flow from a user input (threat model
16+
* source) to the first argument of a call to `sqlx_core::query::query`.
17+
*/
18+
module SqlInjectionConfig implements DataFlow::ConfigSig {
19+
predicate isSource(DataFlow::Node node) {
20+
// `node` is a user input (threat model source)
21+
node instanceof ActiveThreatModelSource
22+
}
23+
24+
predicate isSink(DataFlow::Node node) {
25+
// `node` is the first argument of a call to `sqlx_core::query::query`
26+
exists(CallExpr call |
27+
call.getStaticTarget().getCanonicalPath() = "sqlx_core::query::query" and
28+
call.getArg(0) = node.asExpr().getExpr()
29+
)
30+
}
31+
}
32+
33+
// instantiate the data flow configuration as a global taint tracking module
34+
module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>;
35+
36+
// report flows from sources to sinks
37+
from DataFlow::Node sourceNode, DataFlow::Node sinkNode
38+
where SqlInjectionFlow::flow(sourceNode, sinkNode)
39+
select sinkNode, "This query depends on a $@.", sourceNode, "user-provided value"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: newQuery
3+
---
4+
* Added three example queries (`rust/examples/empty-if`, `rust/examples/simple-sql-injection` and `rust/examples/simple-constant-password`) to help developers learn to write CodeQL queries for Rust.

0 commit comments

Comments
 (0)