-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: Add example queries #20776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Rust: Add example queries #20776
Changes from 6 commits
84b5060
6ce0a0d
49aefe2
7b6e06e
7e3ab99
61481b5
4b21223
109abdd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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/>`__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| dependencies: {} | ||
| compiled: false | ||
| lockVersion: 1.0.0 |
| 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 |
| 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 | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * "else" branch exists. | ||
| * @id rust/examples/empty-if | ||
| * @tags example | ||
| */ | ||
|
|
||
| import rust | ||
|
|
||
| // find 'if' statements... | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| from IfExpr ifExpr | ||
| where | ||
| // where the 'then' branch is empty | ||
| ifExpr.getThen().(BlockExpr).getStmtList().getNumberOfStmtOrExpr() = 0 and | ||
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show fixed
Hide fixed
|
||
| // and no 'else' branch exists | ||
| not exists(ifExpr.getElse()) | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| select ifExpr, "This 'if' expression is redundant." | ||
| 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() |
| 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" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: newQuery | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would've thought
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's the conclusion I came to. It felt more appropriate than I'm not sure though, I'll request a docs review... |
||
| --- | ||
| * 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. | ||
Uh oh!
There was an error while loading. Please reload this page.