2026-02-25 21:16:36 -05:00
|
|
|
use crate::evidence::Confidence;
|
|
|
|
|
use crate::patterns::{Pattern, PatternCategory, PatternTier, Severity};
|
2025-06-17 01:17:48 +02:00
|
|
|
|
2026-02-25 21:16:36 -05:00
|
|
|
/// Rust AST patterns.
|
|
|
|
|
///
|
|
|
|
|
/// Rust taint rules already cover `Command::new`/`arg`/`status`/`output` sinks
|
|
|
|
|
/// and `env::var` / `fs::read_to_string` sources, so we do NOT duplicate those.
|
|
|
|
|
/// Patterns here focus on **unsafe memory**, **panicking APIs**, and structural
|
|
|
|
|
/// code-quality signals specific to Rust.
|
2025-06-17 01:17:48 +02:00
|
|
|
pub const PATTERNS: &[Pattern] = &[
|
2026-02-25 21:16:36 -05:00
|
|
|
// ── Tier A: Memory Safety (unsafe) ─────────────────────────────────
|
2025-06-24 20:27:06 +02:00
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.transmute",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "std::mem::transmute performs unchecked type reinterpretation",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (scoped_identifier
|
|
|
|
|
path: (identifier) @p (#eq? @p "mem")
|
|
|
|
|
name: (identifier) @f (#eq? @f "transmute")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.copy_nonoverlapping",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "ptr::copy_nonoverlapping is a raw pointer memcpy",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (scoped_identifier
|
|
|
|
|
path: (identifier) @p (#eq? @p "ptr")
|
|
|
|
|
name: (identifier) @f (#eq? @f "copy_nonoverlapping")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.get_unchecked",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "get_unchecked / get_unchecked_mut performs unchecked indexing",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (field_expression
|
|
|
|
|
field: (field_identifier) @m
|
|
|
|
|
(#match? @m "^get_unchecked(_mut)?$")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.mem_zeroed",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "std::mem::zeroed is UB for non-POD types since the zero pattern may not be a valid value",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (scoped_identifier
|
|
|
|
|
path: (identifier) @p (#eq? @p "mem")
|
|
|
|
|
name: (identifier) @n (#eq? @n "zeroed")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.ptr_read",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "ptr::read / ptr::read_volatile dereferences a raw pointer",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (scoped_identifier
|
|
|
|
|
path: (identifier) @p (#eq? @p "ptr")
|
|
|
|
|
name: (identifier) @n (#match? @n "^read(_volatile)?$")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
2026-02-25 21:16:36 -05:00
|
|
|
// ── Tier A: Code quality / robustness ──────────────────────────────
|
2025-06-24 20:27:06 +02:00
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.quality.unsafe_block",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "unsafe block carries a manual memory safety obligation",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: "(unsafe_block) @vuln",
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::Medium,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.quality.unsafe_fn",
|
|
|
|
|
description: "unsafe fn declaration",
|
|
|
|
|
query: r#"(function_item
|
|
|
|
|
(function_modifiers) @mods
|
|
|
|
|
(#match? @mods "^unsafe"))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::Medium,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.quality.unwrap",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: ".unwrap() panics on None/Err",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (field_expression
|
|
|
|
|
field: (field_identifier) @name (#eq? @name "unwrap")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::Low,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeQuality,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.quality.expect",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: ".expect() panics on None/Err",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (field_expression
|
|
|
|
|
field: (field_identifier) @name (#eq? @name "expect")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::Low,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeQuality,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.quality.panic_macro",
|
|
|
|
|
description: "panic! macro invocation",
|
|
|
|
|
query: r#"(macro_invocation (identifier) @id (#eq? @id "panic")) @vuln"#,
|
|
|
|
|
severity: Severity::Low,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeQuality,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.quality.todo",
|
|
|
|
|
description: "todo!() / unimplemented!() placeholder left in code",
|
|
|
|
|
query: r#"(macro_invocation
|
|
|
|
|
(identifier) @id
|
|
|
|
|
(#match? @id "^(todo|unimplemented)$"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::Low,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeQuality,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
2026-02-25 21:16:36 -05:00
|
|
|
// ── Tier A: Narrowing cast ─────────────────────────────────────────
|
2025-06-24 20:27:06 +02:00
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.narrow_cast",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "`as` cast to 8/16-bit integer can truncate",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(type_cast_expression
|
|
|
|
|
type: (primitive_type) @to
|
|
|
|
|
(#match? @to "^(u8|i8|u16|i16)$"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::Low,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::Medium,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "rs.memory.mem_forget",
|
2026-04-29 00:58:38 -04:00
|
|
|
description: "std::mem::forget can leak resources",
|
2026-02-25 21:16:36 -05:00
|
|
|
query: r#"(call_expression
|
|
|
|
|
function: (scoped_identifier
|
|
|
|
|
path: (identifier) @p (#eq? @p "mem")
|
|
|
|
|
name: (identifier) @n (#eq? @n "forget")))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::Low,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::MemorySafety,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
2025-06-17 01:17:48 +02:00
|
|
|
];
|