Rust: Initial version of the query.

This commit is contained in:
Geoffrey White
2025-03-13 17:04:48 +00:00
parent a139b3734c
commit dcd016f5be
7 changed files with 144 additions and 6 deletions

View File

@@ -26,3 +26,11 @@ extensions:
- ["lang:core", "crate::ptr::write_volatile", "Argument[1]", "Argument[0].Reference", "value", "manual"]
# Str
- ["lang:core", "<str>::parse", "Argument[self]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sourceModel
data:
# Alloc
- ["lang:core", "crate::ptr::dangling", "ReturnValue", "pointer-invalidate", "manual"]
- ["lang:core", "crate::ptr::dangling_mut", "ReturnValue", "pointer-invalidate", "manual"]
- ["lang:core", "crate::ptr::null", "ReturnValue", "pointer-invalidate", "manual"]

View File

@@ -0,0 +1,58 @@
/**
* Provides classes and predicates for reasoning about accesses to invalid
* pointers.
*/
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
/**
* Provides default sources, sinks and barriers for detecting accesses to
* invalid pointers, as well as extension points for adding your own.
*/
module AccessInvalidPointer {
/**
* A data flow source for invalid pointer accesses, that is, an operation
* where a pointer becomes invalid.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for invalid pointer accesses, that is, a pointer
* dereference.
*/
abstract class Sink extends QuerySink::Range {
override string getSinkType() { result = "AccessInvalidPointer" }
}
/**
* A barrier for invalid pointer accesses.
*/
abstract class Barrier extends DataFlow::Node { }
/**
* A pointer invalidation from model data.
*/
private class ModelsAsDataSource extends Source {
ModelsAsDataSource() { sourceNode(this, "pointer-invalidate") }
}
/**
* A pointer access using the unary `*` operator.
*/
private class DereferenceSink extends Sink {
DereferenceSink() {
exists(PrefixExpr p | p.getOperatorName() = "*" and p.getExpr() = this.asExpr().getExpr())
}
}
/**
* A pointer access from model data.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "pointer-access") }
}
}

View File

@@ -0,0 +1,35 @@
/**
* @name Access of invalid pointer
* @description Dereferencing an invalid or dangling pointer is undefined behavior and may cause memory corruption.
* @kind path-problem
* @problem.severity error
* @security-severity TODO
* @precision TODO
* @id rust/access-invalid-pointer
* @tags reliability
* security
* external/cwe/cwe-476
* external/cwe/cwe-825
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.security.AccessInvalidPointerExtensions
import AccessInvalidPointerFlow::PathGraph
/**
* A data flow configuration for accesses to invalid pointers.
*/
module AccessInvalidPointerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof AccessInvalidPointer::Source }
predicate isSink(DataFlow::Node node) { node instanceof AccessInvalidPointer::Sink }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof AccessInvalidPointer::Barrier }
}
module AccessInvalidPointerFlow = DataFlow::Global<AccessInvalidPointerConfig>;
from AccessInvalidPointerFlow::PathNode sourceNode, AccessInvalidPointerFlow::PathNode sinkNode
where AccessInvalidPointerFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This operation dereferences a pointer that may be $@.", sourceNode.getNode(), "invalid"

View File

@@ -12,6 +12,7 @@ private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency
private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency
private import codeql.rust.Concepts
// import all query extensions files, so that all extensions of `QuerySink` are found
private import codeql.rust.security.AccessInvalidPointerExtensions
private import codeql.rust.security.CleartextLoggingExtensions
private import codeql.rust.security.SqlInjectionExtensions
private import codeql.rust.security.WeakSensitiveDataHashingExtensions

View File

@@ -0,0 +1,32 @@
#select
| deallocation.rs:96:14:96:15 | p1 | deallocation.rs:89:23:89:40 | ...::dangling | deallocation.rs:96:14:96:15 | p1 | This operation dereferences a pointer that may be $@. | deallocation.rs:89:23:89:40 | ...::dangling | invalid |
| deallocation.rs:97:14:97:15 | p2 | deallocation.rs:90:21:90:42 | ...::dangling_mut | deallocation.rs:97:14:97:15 | p2 | This operation dereferences a pointer that may be $@. | deallocation.rs:90:21:90:42 | ...::dangling_mut | invalid |
| deallocation.rs:98:14:98:15 | p3 | deallocation.rs:91:23:91:36 | ...::null | deallocation.rs:98:14:98:15 | p3 | This operation dereferences a pointer that may be $@. | deallocation.rs:91:23:91:36 | ...::null | invalid |
edges
| deallocation.rs:89:6:89:7 | p1 | deallocation.rs:96:14:96:15 | p1 | provenance | |
| deallocation.rs:89:23:89:40 | ...::dangling | deallocation.rs:89:23:89:42 | ...::dangling(...) | provenance | Src:MaD:1 MaD:1 |
| deallocation.rs:89:23:89:42 | ...::dangling(...) | deallocation.rs:89:6:89:7 | p1 | provenance | |
| deallocation.rs:90:6:90:7 | p2 | deallocation.rs:97:14:97:15 | p2 | provenance | |
| deallocation.rs:90:21:90:42 | ...::dangling_mut | deallocation.rs:90:21:90:44 | ...::dangling_mut(...) | provenance | Src:MaD:2 MaD:2 |
| deallocation.rs:90:21:90:44 | ...::dangling_mut(...) | deallocation.rs:90:6:90:7 | p2 | provenance | |
| deallocation.rs:91:6:91:7 | p3 | deallocation.rs:98:14:98:15 | p3 | provenance | |
| deallocation.rs:91:23:91:36 | ...::null | deallocation.rs:91:23:91:38 | ...::null(...) | provenance | Src:MaD:3 MaD:3 |
| deallocation.rs:91:23:91:38 | ...::null(...) | deallocation.rs:91:6:91:7 | p3 | provenance | |
models
| 1 | Source: lang:core; crate::ptr::dangling; pointer-invalidate; ReturnValue |
| 2 | Source: lang:core; crate::ptr::dangling_mut; pointer-invalidate; ReturnValue |
| 3 | Source: lang:core; crate::ptr::null; pointer-invalidate; ReturnValue |
nodes
| deallocation.rs:89:6:89:7 | p1 | semmle.label | p1 |
| deallocation.rs:89:23:89:40 | ...::dangling | semmle.label | ...::dangling |
| deallocation.rs:89:23:89:42 | ...::dangling(...) | semmle.label | ...::dangling(...) |
| deallocation.rs:90:6:90:7 | p2 | semmle.label | p2 |
| deallocation.rs:90:21:90:42 | ...::dangling_mut | semmle.label | ...::dangling_mut |
| deallocation.rs:90:21:90:44 | ...::dangling_mut(...) | semmle.label | ...::dangling_mut(...) |
| deallocation.rs:91:6:91:7 | p3 | semmle.label | p3 |
| deallocation.rs:91:23:91:36 | ...::null | semmle.label | ...::null |
| deallocation.rs:91:23:91:38 | ...::null(...) | semmle.label | ...::null(...) |
| deallocation.rs:96:14:96:15 | p1 | semmle.label | p1 |
| deallocation.rs:97:14:97:15 | p2 | semmle.label | p2 |
| deallocation.rs:98:14:98:15 | p3 | semmle.label | p3 |
subpaths

View File

@@ -0,0 +1,4 @@
query: queries/security/CWE-825/AccessInvalidPointer.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -86,16 +86,16 @@ pub fn test_libc() {
// --- std::ptr ---
pub fn test_ptr_invalid(do_dangerous_accesses: bool) {
let p1: *const i64 = std::ptr::dangling();
let p2: *mut i64 = std::ptr::dangling_mut();
let p3: *const i64 = std::ptr::null();
let p1: *const i64 = std::ptr::dangling(); // $ Source=dangling
let p2: *mut i64 = std::ptr::dangling_mut(); // $ Source=dangling_mut
let p3: *const i64 = std::ptr::null(); // $ Source=null
if do_dangerous_accesses {
unsafe {
// (a segmentation fault occurs in the code below)
let v1 = *p1; // $ MISSING: Alert
let v2 = *p2; // $ MISSING: Alert
let v3 = *p3; // $ MISSING: Alert
let v1 = *p1; // $ Alert[rust/access-invalid-pointer]=dangling
let v2 = *p2; // $ Alert[rust/access-invalid-pointer]=dangling_mut
let v3 = *p3; // $ Alert[rust/access-invalid-pointer]=null
println!(" v1 = {v1} (!)");
println!(" v2 = {v2} (!)");
println!(" v3 = {v3} (!)");