Skip to content

Commit 896358d

Browse files
committed
Rust: Restrict the scope of DereferenceSink to dereferences of raw pointers
1 parent 359a28e commit 896358d

File tree

3 files changed

+29
-135
lines changed

3 files changed

+29
-135
lines changed

rust/ql/lib/codeql/rust/security/AccessInvalidPointerExtensions.qll

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ private import codeql.rust.dataflow.FlowSink
1010
private import codeql.rust.Concepts
1111
private import codeql.rust.dataflow.internal.Node
1212
private import codeql.rust.security.Barriers as Barriers
13+
private import codeql.rust.internal.TypeInference as TypeInference
14+
private import codeql.rust.internal.Type
1315

1416
/**
1517
* Provides default sources, sinks and barriers for detecting accesses to
@@ -47,16 +49,22 @@ module AccessInvalidPointer {
4749
ModelsAsDataSource() { sourceNode(this, "pointer-invalidate") }
4850
}
4951

50-
/**
51-
* A pointer access using the unary `*` operator.
52-
*/
52+
/** A raw pointer access using the unary `*` operator. */
5353
private class DereferenceSink extends Sink {
54-
DereferenceSink() { any(DerefExpr p).getExpr() = this.asExpr() }
54+
DereferenceSink() {
55+
exists(Expr p, DerefExpr d | p = d.getExpr() and p = this.asExpr() |
56+
// Dereferencing a raw pointer is an unsafe operation. Hence relevant
57+
// dereferences must occur inside code marked as unsafe.
58+
// See: https://doc.rust-lang.org/reference/types/pointer.html#r-type.pointer.raw.safety
59+
(p.getEnclosingBlock*().isUnsafe() or p.getEnclosingCallable().(Function).isUnsafe()) and
60+
// We are only interested in dereferences of raw pointers, as other uses
61+
// of `*` are safe.
62+
(not exists(TypeInference::inferType(p)) or TypeInference::inferType(p) instanceof PtrType)
63+
)
64+
}
5565
}
5666

57-
/**
58-
* A pointer access from model data.
59-
*/
67+
/** A pointer access from model data. */
6068
private class ModelsAsDataSink extends Sink {
6169
ModelsAsDataSink() { sinkNode(this, "pointer-access") }
6270
}

rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,18 @@ module AccessAfterLifetimeConfig implements DataFlow::ConfigSig {
2626
predicate isSource(DataFlow::Node node) {
2727
node instanceof AccessAfterLifetime::Source and
2828
// exclude cases with sources in macros, since these results are difficult to interpret
29-
not node.asExpr().isFromMacroExpansion()
29+
not node.asExpr().isFromMacroExpansion() and
30+
AccessAfterLifetime::sourceValueScope(node, _, _)
3031
}
3132

3233
predicate isSink(DataFlow::Node node) {
3334
node instanceof AccessAfterLifetime::Sink and
34-
// exclude cases with sinks in macros, since these results are difficult to interpret
35+
// Exclude cases with sinks in macros, since these results are difficult to interpret
3536
not node.asExpr().isFromMacroExpansion() and
36-
// include only results inside `unsafe` blocks, as other results tend to be false positives
37-
(
38-
node.asExpr().getEnclosingBlock*().isUnsafe() or
39-
node.asExpr().getEnclosingCallable().(Function).isUnsafe()
40-
)
37+
// TODO: Remove this condition if it can be done without negatively
38+
// impacting performance. This condition only include nodes with
39+
// corresponding to an expression. This excludes sinks from models-as-data.
40+
exists(node.asExpr())
4141
}
4242

4343
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof AccessAfterLifetime::Barrier }

0 commit comments

Comments
 (0)