Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/codeql/reusables/rust-further-reading.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
- `CodeQL queries for Rust <https://github.com/github/codeql/tree/main/rust/ql/src>`__
- `Example queries for Rust <https://github.com/github/codeql/tree/main/rust/ql/examples>`__
- `CodeQL library reference for Rust <https://codeql.github.com/codeql-standard-libraries/rust/>`__
4 changes: 4 additions & 0 deletions rust/ql/examples/qlpack.lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0
7 changes: 7 additions & 0 deletions rust/ql/examples/qlpack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: codeql/rust-examples
groups:
- rust
- examples
dependencies:
codeql/rust-all: ${workspace}
warnOnImplicitThis: true
18 changes: 18 additions & 0 deletions rust/ql/examples/snippets/empty_if.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @name Empty 'if' statement
* @description Finds 'if' statements where the "then" branch is empty and no
* "else" branch exists.
* @id rust/examples/empty-if
* @tags example
*/

import rust

// find 'if' statements...
from IfExpr ifExpr
where
// where the 'then' branch is empty
ifExpr.getThen().(BlockExpr).getStmtList().getNumberOfStmtOrExpr() = 0 and

Check warning

Code scanning / CodeQL

Redundant cast Warning

Redundant cast to
BlockExpr
.
// and no 'else' branch exists
not exists(ifExpr.getElse())
select ifExpr, "This 'if' expression is redundant."
47 changes: 47 additions & 0 deletions rust/ql/examples/snippets/simple_constant_password.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @name Constant password
* @description Finds places where a string literal is used in a function call
* argument that looks like a password.
* @id rust/examples/simple-constant-password
* @tags example
*/

import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking

/**
* A data flow configuration for tracking flow from a string literal to a function
* call argument that looks like a password. For example:
* ```
* fn set_password(password: &str) { ... }
*
* ...
*
* let pwd = "123456"; // source
* set_password(pwd); // sink (argument 0)
* ```
*/
module ConstantPasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
// `node` is a string literal
node.asExpr().getExpr() instanceof StringLiteralExpr
}

predicate isSink(DataFlow::Node node) {
// `node` is an argument whose corresponding parameter name matches the pattern "pass%"
exists(CallExpr call, Function target, int argIndex |
call.getStaticTarget() = target and
target.getParam(argIndex).getPat().(IdentPat).getName().getText().matches("pass%") and
call.getArg(argIndex) = node.asExpr().getExpr()
)
}
}

// instantiate the data flow configuration as a global taint tracking module
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;

// report flows from sources to sinks
from DataFlow::Node sourceNode, DataFlow::Node sinkNode
where ConstantPasswordFlow::flow(sourceNode, sinkNode)
select sinkNode, "The value $@ is used as a constant password.", sourceNode, sourceNode.toString()
39 changes: 39 additions & 0 deletions rust/ql/examples/snippets/simple_sql_injection.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @name Database query built from user-controlled sources
* @description Finds places where a value from a remote or local user input
* is used as the first argument of a call to `sqlx_core::query::query`.
* @id rust/examples/simple-sql-injection
* @tags example
*/

import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking
import codeql.rust.Concepts

/**
* A data flow configuration for tracking flow from a user input (threat model
* source) to the first argument of a call to `sqlx_core::query::query`.
*/
module SqlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
// `node` is a user input (threat model source)
node instanceof ActiveThreatModelSource
}

predicate isSink(DataFlow::Node node) {
// `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()
)
}
}

// instantiate the data flow configuration as a global taint tracking module
module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>;

// report flows from sources to sinks
from DataFlow::Node sourceNode, DataFlow::Node sinkNode
where SqlInjectionFlow::flow(sourceNode, sinkNode)
select sinkNode, "This query depends on a $@.", sourceNode, "user-provided value"
4 changes: 4 additions & 0 deletions rust/ql/src/change-notes/2025-11-07-example-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: newQuery
---
* 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.