Merge pull request #20740 from geoffw0/rustbarriers

Rust: Add numeric type barriers for three queries
This commit is contained in:
Geoffrey White
2025-11-04 10:08:46 +00:00
committed by GitHub
16 changed files with 232 additions and 112 deletions

View File

@@ -31,6 +31,27 @@ class BuiltinType extends Struct {
string getName() { result = super.getName().getText() }
}
/**
* A numerical type, such as `i64`, `usize`, `f32` or `f64`.
*/
abstract private class NumericTypeImpl extends BuiltinType { }
final class NumericType = NumericTypeImpl;
/**
* An integral numerical type, such as `i64` or `usize`.
*/
abstract private class IntegralTypeImpl extends NumericTypeImpl { }
final class IntegralType = IntegralTypeImpl;
/**
* A floating-point numerical type, such as `f32` or `f64`.
*/
abstract private class FloatingPointTypeImpl extends NumericTypeImpl { }
final class FloatingPointType = FloatingPointTypeImpl;
/** The builtin `bool` type. */
class Bool extends BuiltinType {
Bool() { this.getName() = "bool" }
@@ -47,71 +68,71 @@ class Str extends BuiltinType {
}
/** The builtin `i8` type. */
class I8 extends BuiltinType {
class I8 extends IntegralTypeImpl {
I8() { this.getName() = "i8" }
}
/** The builtin `i16` type. */
class I16 extends BuiltinType {
class I16 extends IntegralTypeImpl {
I16() { this.getName() = "i16" }
}
/** The builtin `i32` type. */
class I32 extends BuiltinType {
class I32 extends IntegralTypeImpl {
I32() { this.getName() = "i32" }
}
/** The builtin `i64` type. */
class I64 extends BuiltinType {
class I64 extends IntegralTypeImpl {
I64() { this.getName() = "i64" }
}
/** The builtin `i128` type. */
class I128 extends BuiltinType {
class I128 extends IntegralTypeImpl {
I128() { this.getName() = "i128" }
}
/** The builtin `u8` type. */
class U8 extends BuiltinType {
class U8 extends IntegralTypeImpl {
U8() { this.getName() = "u8" }
}
/** The builtin `u16` type. */
class U16 extends BuiltinType {
class U16 extends IntegralTypeImpl {
U16() { this.getName() = "u16" }
}
/** The builtin `u32` type. */
class U32 extends BuiltinType {
class U32 extends IntegralTypeImpl {
U32() { this.getName() = "u32" }
}
/** The builtin `u64` type. */
class U64 extends BuiltinType {
class U64 extends IntegralTypeImpl {
U64() { this.getName() = "u64" }
}
/** The builtin `u128` type. */
class U128 extends BuiltinType {
class U128 extends IntegralTypeImpl {
U128() { this.getName() = "u128" }
}
/** The builtin `usize` type. */
class Usize extends BuiltinType {
class Usize extends IntegralTypeImpl {
Usize() { this.getName() = "usize" }
}
/** The builtin `isize` type. */
class Isize extends BuiltinType {
class Isize extends IntegralTypeImpl {
Isize() { this.getName() = "isize" }
}
/** The builtin `f32` type. */
class F32 extends BuiltinType {
class F32 extends FloatingPointTypeImpl {
F32() { this.getName() = "f32" }
}
/** The builtin `f64` type. */
class F64 extends BuiltinType {
class F64 extends FloatingPointTypeImpl {
F64() { this.getName() = "f64" }
}

View File

@@ -0,0 +1,42 @@
/**
* Classes to represent barriers commonly used in dataflow and taint tracking
* configurations.
*/
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.internal.Type
private import codeql.rust.frameworks.stdlib.Builtins
/**
* A node whose type is a numeric or boolean type, which may be an appropriate
* taint flow barrier for some queries.
*/
class NumericTypeBarrier extends DataFlow::Node {
NumericTypeBarrier() {
exists(StructType t, Struct s |
t = TypeInference::inferType(this.asExpr().getExpr()) and
s = t.getStruct()
|
s instanceof NumericType or
s instanceof Bool
)
}
}
/**
* A node whose type is an integral (integer) or boolean type, which may be an
* appropriate taint flow barrier for some queries.
*/
class IntegralOrBooleanTypeBarrier extends DataFlow::Node {
IntegralOrBooleanTypeBarrier() {
exists(StructType t, Struct s |
t = TypeInference::inferType(this.asExpr().getExpr()) and
s = t.getStruct()
|
s instanceof IntegralType or
s instanceof Bool
)
}
}

View File

@@ -8,6 +8,7 @@ private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.util.Unit
private import codeql.rust.security.Barriers as Barriers
/**
* Provides default sources, sinks and barriers for detecting log injection
@@ -42,4 +43,10 @@ module LogInjection {
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "log-injection") }
}
/**
* A barrier for log injection vulnerabilities for nodes whose type is a
* numeric or boolean type, which is unlikely to expose any vulnerability.
*/
private class NumericTypeBarrier extends Barrier instanceof Barriers::NumericTypeBarrier { }
}

View File

@@ -9,6 +9,7 @@ private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.util.Unit
private import codeql.rust.security.Barriers as Barriers
/**
* Provides default sources, sinks and barriers for detecting SQL injection
@@ -57,4 +58,10 @@ module SqlInjection {
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "sql-injection") }
}
/**
* A barrier for SQL injection vulnerabilities for nodes whose type is a numeric or
* boolean type, which is unlikely to expose any vulnerability.
*/
private class NumericTypeBarrier extends Barrier instanceof Barriers::NumericTypeBarrier { }
}

View File

@@ -9,6 +9,7 @@ private import codeql.rust.dataflow.DataFlow
private import codeql.rust.controlflow.CfgNodes
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.rust.security.Barriers as Barriers
/**
* Provides default sources, sinks and barriers for detecting regular expression
@@ -87,4 +88,14 @@ module RegexInjection {
.getText() = "escape"
}
}
/**
* A barrier for regular expression injection vulnerabilities for nodes whose
* type is an integral or boolean type, which is unlikely to expose any vulnerability.
*
* We don't include floating point types in this barrier, as `.` is a special character
* in regular expressions.
*/
private class IntegralOrBooleanTypeBarrier extends Barrier instanceof Barriers::IntegralOrBooleanTypeBarrier
{ }
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Taint flow barriers have been added to the `rust/regex-injection`, `rust/sql-injection` and `rust/log-injection`, reducing the frequency of false positive results for these queries.

View File

@@ -0,0 +1,17 @@
| struct bool | |
| struct char | |
| struct f32 | FloatingPointType, NumericType |
| struct f64 | FloatingPointType, NumericType |
| struct i8 | IntegralType, NumericType |
| struct i16 | IntegralType, NumericType |
| struct i32 | IntegralType, NumericType |
| struct i64 | IntegralType, NumericType |
| struct i128 | IntegralType, NumericType |
| struct isize | IntegralType, NumericType |
| struct str | |
| struct u8 | IntegralType, NumericType |
| struct u16 | IntegralType, NumericType |
| struct u32 | IntegralType, NumericType |
| struct u64 | IntegralType, NumericType |
| struct u128 | IntegralType, NumericType |
| struct usize | IntegralType, NumericType |

View File

@@ -0,0 +1,14 @@
import rust
import codeql.rust.frameworks.stdlib.Builtins
import codeql.rust.internal.Type
string describe(BuiltinType t) {
t instanceof NumericType and result = "NumericType"
or
t instanceof IntegralType and result = "IntegralType"
or
t instanceof FloatingPointType and result = "FloatingPointType"
}
from BuiltinType t
select t.toString(), concat(describe(t), ", ")

View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "test"
version = "0.0.1"

View File

@@ -0,0 +1,5 @@
// --- tests ---
fn test_types() {
}

View File

@@ -1,2 +1,3 @@
| main.rs:6:25:6:30 | &regex |
| main.rs:14:25:14:30 | &regex |
| main.rs:21:25:21:30 | &regex |

View File

@@ -7,7 +7,7 @@ fn simple_bad(hay: &str) -> Option<bool> {
Some(re.is_match(hay))
}
fn simple_good(hay: &str) -> Option<bool> {
fn simple_good_escaped(hay: &str) -> Option<bool> {
let username = std::env::var("USER").unwrap_or("".to_string());
let escaped = regex::escape(&username);
let regex = format!("foo{}bar", escaped);
@@ -15,6 +15,13 @@ fn simple_good(hay: &str) -> Option<bool> {
Some(re.is_match(hay))
}
fn simple_good_numeric(hay: &str) -> Option<bool> {
let user_number = std::env::var("USER").unwrap_or("0".to_string()).parse::<u64>().unwrap_or(0);
let regex = format!("foo{}bar", user_number);
let re = Regex::new(&regex).unwrap();
Some(re.is_match(hay))
}
fn not_a_sink_literal() -> Option<bool> {
let username = std::env::var("USER").unwrap_or("".to_string());
let re = Regex::new("literal string").unwrap();
@@ -30,7 +37,8 @@ fn not_a_sink_raw_literal() -> Option<bool> {
fn main() {
let hay = "a string";
simple_bad(hay);
simple_good(hay);
simple_good_escaped(hay);
simple_good_numeric(hay);
not_a_sink_literal();
not_a_sink_raw_literal();
}

View File

@@ -21,7 +21,6 @@
| mysql.rs:121:14:121:22 | query_map | mysql.rs:97:33:97:54 | ...::get | mysql.rs:121:14:121:22 | query_map | This query depends on a $@. | mysql.rs:97:33:97:54 | ...::get | user-provided value |
| mysql.rs:149:26:149:29 | prep | mysql.rs:97:33:97:54 | ...::get | mysql.rs:149:26:149:29 | prep | This query depends on a $@. | mysql.rs:97:33:97:54 | ...::get | user-provided value |
| mysql.rs:154:15:154:24 | query_drop | mysql.rs:97:33:97:54 | ...::get | mysql.rs:154:15:154:24 | query_drop | This query depends on a $@. | mysql.rs:97:33:97:54 | ...::get | user-provided value |
| sqlx.rs:77:13:77:23 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:13:77:23 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:78:13:78:23 | ...::query | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:13:78:23 | ...::query | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value |
| sqlx.rs:80:17:80:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:17:80:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:81:17:81:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:81:17:81:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
@@ -37,7 +36,7 @@ edges
| mysql.rs:12:13:12:29 | mut remote_string | mysql.rs:18:71:18:83 | remote_string | provenance | |
| mysql.rs:12:33:12:54 | ...::get | mysql.rs:12:33:12:77 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
| mysql.rs:12:33:12:77 | ...::get(...) [Ok] | mysql.rs:12:33:13:21 | ... .unwrap() | provenance | MaD:31 |
| mysql.rs:12:33:13:21 | ... .unwrap() | mysql.rs:12:33:14:19 | ... .text() [Ok] | provenance | MaD:35 |
| mysql.rs:12:33:13:21 | ... .unwrap() | mysql.rs:12:33:14:19 | ... .text() [Ok] | provenance | MaD:34 |
| mysql.rs:12:33:14:19 | ... .text() [Ok] | mysql.rs:12:33:15:40 | ... .unwrap_or(...) | provenance | MaD:32 |
| mysql.rs:12:33:15:40 | ... .unwrap_or(...) | mysql.rs:12:13:12:29 | mut remote_string | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:25:38:25:49 | unsafe_query | provenance | |
@@ -114,7 +113,7 @@ edges
| mysql.rs:97:13:97:29 | mut remote_string | mysql.rs:103:71:103:83 | remote_string | provenance | |
| mysql.rs:97:33:97:54 | ...::get | mysql.rs:97:33:97:77 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
| mysql.rs:97:33:97:77 | ...::get(...) [Ok] | mysql.rs:97:33:98:21 | ... .unwrap() | provenance | MaD:31 |
| mysql.rs:97:33:98:21 | ... .unwrap() | mysql.rs:97:33:99:19 | ... .text() [Ok] | provenance | MaD:35 |
| mysql.rs:97:33:98:21 | ... .unwrap() | mysql.rs:97:33:99:19 | ... .text() [Ok] | provenance | MaD:34 |
| mysql.rs:97:33:99:19 | ... .text() [Ok] | mysql.rs:97:33:100:40 | ... .unwrap_or(...) | provenance | MaD:32 |
| mysql.rs:97:33:100:40 | ... .unwrap_or(...) | mysql.rs:97:13:97:29 | mut remote_string | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:110:38:110:49 | unsafe_query | provenance | |
@@ -173,25 +172,14 @@ edges
| sqlx.rs:47:22:47:37 | ...::args(...) [element] | sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | provenance | MaD:25 |
| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | provenance | MaD:30 |
| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | sqlx.rs:47:9:47:18 | arg_string | provenance | |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:34 |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:34 |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:55:84:55:96 | remote_string | provenance | |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:59:17:59:72 | MacroExpr | provenance | |
| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:31 |
| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:35 |
| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:34 |
| sqlx.rs:48:25:48:85 | ... .text() [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | |
| sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | |
| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:36 | safe_query_3 | provenance | |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:29 |
| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:32:52:87 | { ... } | provenance | |
| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | |
| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:36 |
| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:37 |
| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | |
| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | |
@@ -212,11 +200,8 @@ edges
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:29 |
| sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:17:59:72 | { ... } | provenance | |
| sqlx.rs:59:17:59:72 | ...::must_use(...) | sqlx.rs:56:9:56:22 | unsafe_query_4 | provenance | |
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:36 |
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:37 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:35 |
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:36 |
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:81:29:81:42 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() [&ref] | provenance | MaD:29 |
@@ -228,7 +213,7 @@ edges
| sqlx.rs:100:9:100:21 | remote_string | sqlx.rs:102:84:102:96 | remote_string | provenance | |
| sqlx.rs:100:25:100:46 | ...::get | sqlx.rs:100:25:100:69 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
| sqlx.rs:100:25:100:69 | ...::get(...) [Ok] | sqlx.rs:100:25:100:78 | ... .unwrap() | provenance | MaD:31 |
| sqlx.rs:100:25:100:78 | ... .unwrap() | sqlx.rs:100:25:100:85 | ... .text() [Ok] | provenance | MaD:35 |
| sqlx.rs:100:25:100:78 | ... .unwrap() | sqlx.rs:100:25:100:85 | ... .text() [Ok] | provenance | MaD:34 |
| sqlx.rs:100:25:100:85 | ... .text() [Ok] | sqlx.rs:100:25:100:118 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:100:25:100:118 | ... .unwrap_or(...) | sqlx.rs:100:9:100:21 | remote_string | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:113:31:113:44 | unsafe_query_1 | provenance | |
@@ -270,7 +255,7 @@ edges
| sqlx.rs:173:9:173:21 | remote_string | sqlx.rs:175:84:175:96 | remote_string | provenance | |
| sqlx.rs:173:25:173:46 | ...::get | sqlx.rs:173:25:173:69 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
| sqlx.rs:173:25:173:69 | ...::get(...) [Ok] | sqlx.rs:173:25:173:78 | ... .unwrap() | provenance | MaD:31 |
| sqlx.rs:173:25:173:78 | ... .unwrap() | sqlx.rs:173:25:173:85 | ... .text() [Ok] | provenance | MaD:35 |
| sqlx.rs:173:25:173:78 | ... .unwrap() | sqlx.rs:173:25:173:85 | ... .text() [Ok] | provenance | MaD:34 |
| sqlx.rs:173:25:173:85 | ... .text() [Ok] | sqlx.rs:173:25:173:118 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:173:25:173:118 | ... .unwrap_or(...) | sqlx.rs:173:9:173:21 | remote_string | provenance | |
| sqlx.rs:175:9:175:22 | unsafe_query_1 | sqlx.rs:188:29:188:42 | unsafe_query_1 | provenance | |
@@ -318,10 +303,9 @@ models
| 31 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 32 | Summary: <core::result::Result>::unwrap_or; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 33 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |
| 34 | Summary: <core::str>::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
| 35 | Summary: <reqwest::blocking::response::Response>::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
| 36 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 37 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
| 34 | Summary: <reqwest::blocking::response::Response>::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
| 35 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 36 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
nodes
| mysql.rs:12:13:12:29 | mut remote_string | semmle.label | mut remote_string |
| mysql.rs:12:33:12:54 | ...::get | semmle.label | ...::get |
@@ -444,14 +428,6 @@ nodes
| sqlx.rs:48:25:48:78 | ... .unwrap() | semmle.label | ... .unwrap() |
| sqlx.rs:48:25:48:85 | ... .text() [Ok] | semmle.label | ... .text() [Ok] |
| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) |
| sqlx.rs:49:9:49:21 | remote_number | semmle.label | remote_number |
| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | semmle.label | remote_string.parse() [Ok] |
| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) |
| sqlx.rs:52:9:52:20 | safe_query_3 | semmle.label | safe_query_3 |
| sqlx.rs:52:32:52:87 | ...::format(...) | semmle.label | ...::format(...) |
| sqlx.rs:52:32:52:87 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| sqlx.rs:52:32:52:87 | MacroExpr | semmle.label | MacroExpr |
| sqlx.rs:52:32:52:87 | { ... } | semmle.label | { ... } |
| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | semmle.label | unsafe_query_1 [&ref] |
| sqlx.rs:53:26:53:36 | &arg_string [&ref] | semmle.label | &arg_string [&ref] |
| sqlx.rs:53:27:53:36 | arg_string | semmle.label | arg_string |
@@ -468,10 +444,6 @@ nodes
| sqlx.rs:59:17:59:72 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| sqlx.rs:59:17:59:72 | MacroExpr | semmle.label | MacroExpr |
| sqlx.rs:59:17:59:72 | { ... } | semmle.label | { ... } |
| sqlx.rs:77:13:77:23 | ...::query | semmle.label | ...::query |
| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | semmle.label | safe_query_3.as_str() [&ref] |
| sqlx.rs:78:13:78:23 | ...::query | semmle.label | ...::query |
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | semmle.label | unsafe_query_1.as_str() [&ref] |
| sqlx.rs:80:17:80:27 | ...::query | semmle.label | ...::query |

View File

@@ -74,7 +74,7 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err
// prepared queries
let _ = sqlx::query(safe_query_1.as_str()).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(safe_query_2.as_str()).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(safe_query_3.as_str()).execute(&pool).await?; // $ sql-sink $ SPURIOUS: Alert[rust/sql-injection]=remote1
let _ = sqlx::query(safe_query_3.as_str()).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(unsafe_query_1.as_str()).execute(&pool).await?; // $ sql-sink Alert[rust/sql-injection]=args1
if enable_remote {
let _ = sqlx::query(unsafe_query_2.as_str()).execute(&pool).await?; // $ sql-sink Alert[rust/sql-injection]=remote1

View File

@@ -3,14 +3,14 @@
| main.rs:17:5:17:10 | ...::log | main.rs:11:23:11:44 | ...::get | main.rs:17:5:17:10 | ...::log | Log entry depends on a $@. | main.rs:11:23:11:44 | ...::get | user-provided value |
| main.rs:19:5:19:10 | ...::log | main.rs:10:22:10:34 | ...::var | main.rs:19:5:19:10 | ...::log | Log entry depends on a $@. | main.rs:10:22:10:34 | ...::var | user-provided value |
| main.rs:30:5:30:9 | ...::log | main.rs:11:23:11:44 | ...::get | main.rs:30:5:30:9 | ...::log | Log entry depends on a $@. | main.rs:11:23:11:44 | ...::get | user-provided value |
| main.rs:108:9:108:13 | ...::log | main.rs:105:25:105:38 | ...::args | main.rs:108:9:108:13 | ...::log | Log entry depends on a $@. | main.rs:105:25:105:38 | ...::args | user-provided value |
| main.rs:109:9:109:13 | ...::log | main.rs:105:25:105:38 | ...::args | main.rs:109:9:109:13 | ...::log | Log entry depends on a $@. | main.rs:105:25:105:38 | ...::args | user-provided value |
| main.rs:110:9:110:14 | ...::log | main.rs:105:25:105:38 | ...::args | main.rs:110:9:110:14 | ...::log | Log entry depends on a $@. | main.rs:105:25:105:38 | ...::args | user-provided value |
| main.rs:111:9:111:14 | ...::log | main.rs:105:25:105:38 | ...::args | main.rs:111:9:111:14 | ...::log | Log entry depends on a $@. | main.rs:105:25:105:38 | ...::args | user-provided value |
| main.rs:112:9:112:14 | ...::log | main.rs:105:25:105:38 | ...::args | main.rs:112:9:112:14 | ...::log | Log entry depends on a $@. | main.rs:105:25:105:38 | ...::args | user-provided value |
| main.rs:115:9:115:13 | ...::log | main.rs:105:25:105:38 | ...::args | main.rs:115:9:115:13 | ...::log | Log entry depends on a $@. | main.rs:105:25:105:38 | ...::args | user-provided value |
| main.rs:122:9:122:16 | ...::_print | main.rs:119:25:119:37 | ...::var | main.rs:122:9:122:16 | ...::_print | Log entry depends on a $@. | main.rs:119:25:119:37 | ...::var | user-provided value |
| main.rs:123:9:123:17 | ...::_eprint | main.rs:119:25:119:37 | ...::var | main.rs:123:9:123:17 | ...::_eprint | Log entry depends on a $@. | main.rs:119:25:119:37 | ...::var | user-provided value |
| main.rs:112:9:112:13 | ...::log | main.rs:109:25:109:38 | ...::args | main.rs:112:9:112:13 | ...::log | Log entry depends on a $@. | main.rs:109:25:109:38 | ...::args | user-provided value |
| main.rs:113:9:113:13 | ...::log | main.rs:109:25:109:38 | ...::args | main.rs:113:9:113:13 | ...::log | Log entry depends on a $@. | main.rs:109:25:109:38 | ...::args | user-provided value |
| main.rs:114:9:114:14 | ...::log | main.rs:109:25:109:38 | ...::args | main.rs:114:9:114:14 | ...::log | Log entry depends on a $@. | main.rs:109:25:109:38 | ...::args | user-provided value |
| main.rs:115:9:115:14 | ...::log | main.rs:109:25:109:38 | ...::args | main.rs:115:9:115:14 | ...::log | Log entry depends on a $@. | main.rs:109:25:109:38 | ...::args | user-provided value |
| main.rs:116:9:116:14 | ...::log | main.rs:109:25:109:38 | ...::args | main.rs:116:9:116:14 | ...::log | Log entry depends on a $@. | main.rs:109:25:109:38 | ...::args | user-provided value |
| main.rs:119:9:119:13 | ...::log | main.rs:109:25:109:38 | ...::args | main.rs:119:9:119:13 | ...::log | Log entry depends on a $@. | main.rs:109:25:109:38 | ...::args | user-provided value |
| main.rs:126:9:126:16 | ...::_print | main.rs:123:25:123:37 | ...::var | main.rs:126:9:126:16 | ...::_print | Log entry depends on a $@. | main.rs:123:25:123:37 | ...::var | user-provided value |
| main.rs:127:9:127:17 | ...::_eprint | main.rs:123:25:123:37 | ...::var | main.rs:127:9:127:17 | ...::_eprint | Log entry depends on a $@. | main.rs:123:25:123:37 | ...::var | user-provided value |
edges
| main.rs:10:9:10:18 | user_input | main.rs:16:11:16:44 | MacroExpr | provenance | |
| main.rs:10:9:10:18 | user_input | main.rs:19:12:19:39 | MacroExpr | provenance | |
@@ -28,29 +28,29 @@ edges
| main.rs:17:12:17:46 | MacroExpr | main.rs:17:5:17:10 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:19:12:19:39 | MacroExpr | main.rs:19:5:19:10 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:30:11:30:66 | MacroExpr | main.rs:30:5:30:9 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:105:13:105:21 | user_data | main.rs:108:15:108:35 | MacroExpr | provenance | |
| main.rs:105:13:105:21 | user_data | main.rs:109:15:109:38 | MacroExpr | provenance | |
| main.rs:105:13:105:21 | user_data | main.rs:110:16:110:37 | MacroExpr | provenance | |
| main.rs:105:13:105:21 | user_data | main.rs:111:16:111:37 | MacroExpr | provenance | |
| main.rs:105:13:105:21 | user_data | main.rs:112:16:112:37 | MacroExpr | provenance | |
| main.rs:105:13:105:21 | user_data | main.rs:115:15:115:75 | MacroExpr | provenance | |
| main.rs:105:25:105:38 | ...::args | main.rs:105:25:105:40 | ...::args(...) [element] | provenance | Src:MaD:5 |
| main.rs:105:25:105:40 | ...::args(...) [element] | main.rs:105:25:105:47 | ... .nth(...) [Some] | provenance | MaD:7 |
| main.rs:105:25:105:47 | ... .nth(...) [Some] | main.rs:105:25:105:67 | ... .unwrap_or_default() | provenance | MaD:8 |
| main.rs:105:25:105:67 | ... .unwrap_or_default() | main.rs:105:13:105:21 | user_data | provenance | |
| main.rs:108:15:108:35 | MacroExpr | main.rs:108:9:108:13 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:109:15:109:38 | MacroExpr | main.rs:109:9:109:13 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:110:16:110:37 | MacroExpr | main.rs:110:9:110:14 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:111:16:111:37 | MacroExpr | main.rs:111:9:111:14 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:112:16:112:37 | MacroExpr | main.rs:112:9:112:14 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:115:15:115:75 | MacroExpr | main.rs:115:9:115:13 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:119:13:119:21 | user_data | main.rs:122:18:122:38 | MacroExpr | provenance | |
| main.rs:119:13:119:21 | user_data | main.rs:123:19:123:49 | MacroExpr | provenance | |
| main.rs:119:25:119:37 | ...::var | main.rs:119:25:119:45 | ...::var(...) [Ok] | provenance | Src:MaD:6 |
| main.rs:119:25:119:45 | ...::var(...) [Ok] | main.rs:119:25:119:65 | ... .unwrap_or_default() | provenance | MaD:11 |
| main.rs:119:25:119:65 | ... .unwrap_or_default() | main.rs:119:13:119:21 | user_data | provenance | |
| main.rs:122:18:122:38 | MacroExpr | main.rs:122:9:122:16 | ...::_print | provenance | MaD:3 Sink:MaD:3 |
| main.rs:123:19:123:49 | MacroExpr | main.rs:123:9:123:17 | ...::_eprint | provenance | MaD:2 Sink:MaD:2 |
| main.rs:109:13:109:21 | user_data | main.rs:112:15:112:35 | MacroExpr | provenance | |
| main.rs:109:13:109:21 | user_data | main.rs:113:15:113:38 | MacroExpr | provenance | |
| main.rs:109:13:109:21 | user_data | main.rs:114:16:114:37 | MacroExpr | provenance | |
| main.rs:109:13:109:21 | user_data | main.rs:115:16:115:37 | MacroExpr | provenance | |
| main.rs:109:13:109:21 | user_data | main.rs:116:16:116:37 | MacroExpr | provenance | |
| main.rs:109:13:109:21 | user_data | main.rs:119:15:119:75 | MacroExpr | provenance | |
| main.rs:109:25:109:38 | ...::args | main.rs:109:25:109:40 | ...::args(...) [element] | provenance | Src:MaD:5 |
| main.rs:109:25:109:40 | ...::args(...) [element] | main.rs:109:25:109:47 | ... .nth(...) [Some] | provenance | MaD:7 |
| main.rs:109:25:109:47 | ... .nth(...) [Some] | main.rs:109:25:109:67 | ... .unwrap_or_default() | provenance | MaD:8 |
| main.rs:109:25:109:67 | ... .unwrap_or_default() | main.rs:109:13:109:21 | user_data | provenance | |
| main.rs:112:15:112:35 | MacroExpr | main.rs:112:9:112:13 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:113:15:113:38 | MacroExpr | main.rs:113:9:113:13 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:114:16:114:37 | MacroExpr | main.rs:114:9:114:14 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:115:16:115:37 | MacroExpr | main.rs:115:9:115:14 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:116:16:116:37 | MacroExpr | main.rs:116:9:116:14 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:119:15:119:75 | MacroExpr | main.rs:119:9:119:13 | ...::log | provenance | MaD:1 Sink:MaD:1 |
| main.rs:123:13:123:21 | user_data | main.rs:126:18:126:38 | MacroExpr | provenance | |
| main.rs:123:13:123:21 | user_data | main.rs:127:19:127:49 | MacroExpr | provenance | |
| main.rs:123:25:123:37 | ...::var | main.rs:123:25:123:45 | ...::var(...) [Ok] | provenance | Src:MaD:6 |
| main.rs:123:25:123:45 | ...::var(...) [Ok] | main.rs:123:25:123:65 | ... .unwrap_or_default() | provenance | MaD:11 |
| main.rs:123:25:123:65 | ... .unwrap_or_default() | main.rs:123:13:123:21 | user_data | provenance | |
| main.rs:126:18:126:38 | MacroExpr | main.rs:126:9:126:16 | ...::_print | provenance | MaD:3 Sink:MaD:3 |
| main.rs:127:19:127:49 | MacroExpr | main.rs:127:9:127:17 | ...::_eprint | provenance | MaD:2 Sink:MaD:2 |
models
| 1 | Sink: log::__private_api::log; Argument[0]; log-injection |
| 2 | Sink: std::io::stdio::_eprint; Argument[0]; log-injection |
@@ -83,29 +83,29 @@ nodes
| main.rs:19:12:19:39 | MacroExpr | semmle.label | MacroExpr |
| main.rs:30:5:30:9 | ...::log | semmle.label | ...::log |
| main.rs:30:11:30:66 | MacroExpr | semmle.label | MacroExpr |
| main.rs:105:13:105:21 | user_data | semmle.label | user_data |
| main.rs:105:25:105:38 | ...::args | semmle.label | ...::args |
| main.rs:105:25:105:40 | ...::args(...) [element] | semmle.label | ...::args(...) [element] |
| main.rs:105:25:105:47 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] |
| main.rs:105:25:105:67 | ... .unwrap_or_default() | semmle.label | ... .unwrap_or_default() |
| main.rs:108:9:108:13 | ...::log | semmle.label | ...::log |
| main.rs:108:15:108:35 | MacroExpr | semmle.label | MacroExpr |
| main.rs:109:9:109:13 | ...::log | semmle.label | ...::log |
| main.rs:109:15:109:38 | MacroExpr | semmle.label | MacroExpr |
| main.rs:110:9:110:14 | ...::log | semmle.label | ...::log |
| main.rs:110:16:110:37 | MacroExpr | semmle.label | MacroExpr |
| main.rs:111:9:111:14 | ...::log | semmle.label | ...::log |
| main.rs:111:16:111:37 | MacroExpr | semmle.label | MacroExpr |
| main.rs:112:9:112:14 | ...::log | semmle.label | ...::log |
| main.rs:112:16:112:37 | MacroExpr | semmle.label | MacroExpr |
| main.rs:115:9:115:13 | ...::log | semmle.label | ...::log |
| main.rs:115:15:115:75 | MacroExpr | semmle.label | MacroExpr |
| main.rs:119:13:119:21 | user_data | semmle.label | user_data |
| main.rs:119:25:119:37 | ...::var | semmle.label | ...::var |
| main.rs:119:25:119:45 | ...::var(...) [Ok] | semmle.label | ...::var(...) [Ok] |
| main.rs:119:25:119:65 | ... .unwrap_or_default() | semmle.label | ... .unwrap_or_default() |
| main.rs:122:9:122:16 | ...::_print | semmle.label | ...::_print |
| main.rs:122:18:122:38 | MacroExpr | semmle.label | MacroExpr |
| main.rs:123:9:123:17 | ...::_eprint | semmle.label | ...::_eprint |
| main.rs:123:19:123:49 | MacroExpr | semmle.label | MacroExpr |
| main.rs:109:13:109:21 | user_data | semmle.label | user_data |
| main.rs:109:25:109:38 | ...::args | semmle.label | ...::args |
| main.rs:109:25:109:40 | ...::args(...) [element] | semmle.label | ...::args(...) [element] |
| main.rs:109:25:109:47 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] |
| main.rs:109:25:109:67 | ... .unwrap_or_default() | semmle.label | ... .unwrap_or_default() |
| main.rs:112:9:112:13 | ...::log | semmle.label | ...::log |
| main.rs:112:15:112:35 | MacroExpr | semmle.label | MacroExpr |
| main.rs:113:9:113:13 | ...::log | semmle.label | ...::log |
| main.rs:113:15:113:38 | MacroExpr | semmle.label | MacroExpr |
| main.rs:114:9:114:14 | ...::log | semmle.label | ...::log |
| main.rs:114:16:114:37 | MacroExpr | semmle.label | MacroExpr |
| main.rs:115:9:115:14 | ...::log | semmle.label | ...::log |
| main.rs:115:16:115:37 | MacroExpr | semmle.label | MacroExpr |
| main.rs:116:9:116:14 | ...::log | semmle.label | ...::log |
| main.rs:116:16:116:37 | MacroExpr | semmle.label | MacroExpr |
| main.rs:119:9:119:13 | ...::log | semmle.label | ...::log |
| main.rs:119:15:119:75 | MacroExpr | semmle.label | MacroExpr |
| main.rs:123:13:123:21 | user_data | semmle.label | user_data |
| main.rs:123:25:123:37 | ...::var | semmle.label | ...::var |
| main.rs:123:25:123:45 | ...::var(...) [Ok] | semmle.label | ...::var(...) [Ok] |
| main.rs:123:25:123:65 | ... .unwrap_or_default() | semmle.label | ... .unwrap_or_default() |
| main.rs:126:9:126:16 | ...::_print | semmle.label | ...::_print |
| main.rs:126:18:126:38 | MacroExpr | semmle.label | MacroExpr |
| main.rs:127:9:127:17 | ...::_eprint | semmle.label | ...::_eprint |
| main.rs:127:19:127:49 | MacroExpr | semmle.label | MacroExpr |
subpaths

View File

@@ -40,10 +40,14 @@ fn main() {
let system_time = std::time::SystemTime::now();
info!("Current time: {:?}", system_time);
// GOOD: Numeric data derived from user input (not directly logged)
// GOOD: Numeric data derived from user input (indirectly)
let user_id = username.len();
info!("User ID length: {}", user_id);
// GOOD: Numeric data derived from user input (directly)
let number = remote_data.parse::<u64>().unwrap_or(0);
info!("Number: {}", number);
// More complex test cases
test_complex_scenarios(&username, &user_input);
test_indirect_flows(&remote_data);