Skip to content

Commit dcd016f

Browse files
committed
Rust: Initial version of the query.
1 parent a139b37 commit dcd016f

7 files changed

Lines changed: 144 additions & 6 deletions

File tree

rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,11 @@ extensions:
2626
- ["lang:core", "crate::ptr::write_volatile", "Argument[1]", "Argument[0].Reference", "value", "manual"]
2727
# Str
2828
- ["lang:core", "<str>::parse", "Argument[self]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"]
29+
- addsTo:
30+
pack: codeql/rust-all
31+
extensible: sourceModel
32+
data:
33+
# Alloc
34+
- ["lang:core", "crate::ptr::dangling", "ReturnValue", "pointer-invalidate", "manual"]
35+
- ["lang:core", "crate::ptr::dangling_mut", "ReturnValue", "pointer-invalidate", "manual"]
36+
- ["lang:core", "crate::ptr::null", "ReturnValue", "pointer-invalidate", "manual"]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Provides classes and predicates for reasoning about accesses to invalid
3+
* pointers.
4+
*/
5+
6+
import rust
7+
private import codeql.rust.dataflow.DataFlow
8+
private import codeql.rust.dataflow.FlowSource
9+
private import codeql.rust.dataflow.FlowSink
10+
private import codeql.rust.Concepts
11+
12+
/**
13+
* Provides default sources, sinks and barriers for detecting accesses to
14+
* invalid pointers, as well as extension points for adding your own.
15+
*/
16+
module AccessInvalidPointer {
17+
/**
18+
* A data flow source for invalid pointer accesses, that is, an operation
19+
* where a pointer becomes invalid.
20+
*/
21+
abstract class Source extends DataFlow::Node { }
22+
23+
/**
24+
* A data flow sink for invalid pointer accesses, that is, a pointer
25+
* dereference.
26+
*/
27+
abstract class Sink extends QuerySink::Range {
28+
override string getSinkType() { result = "AccessInvalidPointer" }
29+
}
30+
31+
/**
32+
* A barrier for invalid pointer accesses.
33+
*/
34+
abstract class Barrier extends DataFlow::Node { }
35+
36+
/**
37+
* A pointer invalidation from model data.
38+
*/
39+
private class ModelsAsDataSource extends Source {
40+
ModelsAsDataSource() { sourceNode(this, "pointer-invalidate") }
41+
}
42+
43+
/**
44+
* A pointer access using the unary `*` operator.
45+
*/
46+
private class DereferenceSink extends Sink {
47+
DereferenceSink() {
48+
exists(PrefixExpr p | p.getOperatorName() = "*" and p.getExpr() = this.asExpr().getExpr())
49+
}
50+
}
51+
52+
/**
53+
* A pointer access from model data.
54+
*/
55+
private class ModelsAsDataSink extends Sink {
56+
ModelsAsDataSink() { sinkNode(this, "pointer-access") }
57+
}
58+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @name Access of invalid pointer
3+
* @description Dereferencing an invalid or dangling pointer is undefined behavior and may cause memory corruption.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity TODO
7+
* @precision TODO
8+
* @id rust/access-invalid-pointer
9+
* @tags reliability
10+
* security
11+
* external/cwe/cwe-476
12+
* external/cwe/cwe-825
13+
*/
14+
15+
import rust
16+
import codeql.rust.dataflow.DataFlow
17+
import codeql.rust.security.AccessInvalidPointerExtensions
18+
import AccessInvalidPointerFlow::PathGraph
19+
20+
/**
21+
* A data flow configuration for accesses to invalid pointers.
22+
*/
23+
module AccessInvalidPointerConfig implements DataFlow::ConfigSig {
24+
predicate isSource(DataFlow::Node node) { node instanceof AccessInvalidPointer::Source }
25+
26+
predicate isSink(DataFlow::Node node) { node instanceof AccessInvalidPointer::Sink }
27+
28+
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof AccessInvalidPointer::Barrier }
29+
}
30+
31+
module AccessInvalidPointerFlow = DataFlow::Global<AccessInvalidPointerConfig>;
32+
33+
from AccessInvalidPointerFlow::PathNode sourceNode, AccessInvalidPointerFlow::PathNode sinkNode
34+
where AccessInvalidPointerFlow::flowPath(sourceNode, sinkNode)
35+
select sinkNode.getNode(), sourceNode, sinkNode, "This operation dereferences a pointer that may be $@.", sourceNode.getNode(), "invalid"

rust/ql/src/queries/summary/Stats.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency
1212
private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency
1313
private import codeql.rust.Concepts
1414
// import all query extensions files, so that all extensions of `QuerySink` are found
15+
private import codeql.rust.security.AccessInvalidPointerExtensions
1516
private import codeql.rust.security.CleartextLoggingExtensions
1617
private import codeql.rust.security.SqlInjectionExtensions
1718
private import codeql.rust.security.WeakSensitiveDataHashingExtensions
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#select
2+
| 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 |
3+
| 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 |
4+
| 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 |
5+
edges
6+
| deallocation.rs:89:6:89:7 | p1 | deallocation.rs:96:14:96:15 | p1 | provenance | |
7+
| deallocation.rs:89:23:89:40 | ...::dangling | deallocation.rs:89:23:89:42 | ...::dangling(...) | provenance | Src:MaD:1 MaD:1 |
8+
| deallocation.rs:89:23:89:42 | ...::dangling(...) | deallocation.rs:89:6:89:7 | p1 | provenance | |
9+
| deallocation.rs:90:6:90:7 | p2 | deallocation.rs:97:14:97:15 | p2 | provenance | |
10+
| deallocation.rs:90:21:90:42 | ...::dangling_mut | deallocation.rs:90:21:90:44 | ...::dangling_mut(...) | provenance | Src:MaD:2 MaD:2 |
11+
| deallocation.rs:90:21:90:44 | ...::dangling_mut(...) | deallocation.rs:90:6:90:7 | p2 | provenance | |
12+
| deallocation.rs:91:6:91:7 | p3 | deallocation.rs:98:14:98:15 | p3 | provenance | |
13+
| deallocation.rs:91:23:91:36 | ...::null | deallocation.rs:91:23:91:38 | ...::null(...) | provenance | Src:MaD:3 MaD:3 |
14+
| deallocation.rs:91:23:91:38 | ...::null(...) | deallocation.rs:91:6:91:7 | p3 | provenance | |
15+
models
16+
| 1 | Source: lang:core; crate::ptr::dangling; pointer-invalidate; ReturnValue |
17+
| 2 | Source: lang:core; crate::ptr::dangling_mut; pointer-invalidate; ReturnValue |
18+
| 3 | Source: lang:core; crate::ptr::null; pointer-invalidate; ReturnValue |
19+
nodes
20+
| deallocation.rs:89:6:89:7 | p1 | semmle.label | p1 |
21+
| deallocation.rs:89:23:89:40 | ...::dangling | semmle.label | ...::dangling |
22+
| deallocation.rs:89:23:89:42 | ...::dangling(...) | semmle.label | ...::dangling(...) |
23+
| deallocation.rs:90:6:90:7 | p2 | semmle.label | p2 |
24+
| deallocation.rs:90:21:90:42 | ...::dangling_mut | semmle.label | ...::dangling_mut |
25+
| deallocation.rs:90:21:90:44 | ...::dangling_mut(...) | semmle.label | ...::dangling_mut(...) |
26+
| deallocation.rs:91:6:91:7 | p3 | semmle.label | p3 |
27+
| deallocation.rs:91:23:91:36 | ...::null | semmle.label | ...::null |
28+
| deallocation.rs:91:23:91:38 | ...::null(...) | semmle.label | ...::null(...) |
29+
| deallocation.rs:96:14:96:15 | p1 | semmle.label | p1 |
30+
| deallocation.rs:97:14:97:15 | p2 | semmle.label | p2 |
31+
| deallocation.rs:98:14:98:15 | p3 | semmle.label | p3 |
32+
subpaths
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
query: queries/security/CWE-825/AccessInvalidPointer.ql
2+
postprocess:
3+
- utils/test/PrettyPrintModels.ql
4+
- utils/test/InlineExpectationsTestQuery.ql

rust/ql/test/query-tests/security/CWE-825/deallocation.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,16 @@ pub fn test_libc() {
8686
// --- std::ptr ---
8787

8888
pub fn test_ptr_invalid(do_dangerous_accesses: bool) {
89-
let p1: *const i64 = std::ptr::dangling();
90-
let p2: *mut i64 = std::ptr::dangling_mut();
91-
let p3: *const i64 = std::ptr::null();
89+
let p1: *const i64 = std::ptr::dangling(); // $ Source=dangling
90+
let p2: *mut i64 = std::ptr::dangling_mut(); // $ Source=dangling_mut
91+
let p3: *const i64 = std::ptr::null(); // $ Source=null
9292

9393
if do_dangerous_accesses {
9494
unsafe {
9595
// (a segmentation fault occurs in the code below)
96-
let v1 = *p1; // $ MISSING: Alert
97-
let v2 = *p2; // $ MISSING: Alert
98-
let v3 = *p3; // $ MISSING: Alert
96+
let v1 = *p1; // $ Alert[rust/access-invalid-pointer]=dangling
97+
let v2 = *p2; // $ Alert[rust/access-invalid-pointer]=dangling_mut
98+
let v3 = *p3; // $ Alert[rust/access-invalid-pointer]=null
9999
println!(" v1 = {v1} (!)");
100100
println!(" v2 = {v2} (!)");
101101
println!(" v3 = {v3} (!)");

0 commit comments

Comments
 (0)