Skip to content

Commit b569633

Browse files
committed
Rust: Add barriers for rust/access-invalid-pointer
1 parent 6ddb9c7 commit b569633

File tree

1 file changed

+47
-4
lines changed

1 file changed

+47
-4
lines changed

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

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
*/
55

66
import rust
7+
private import codeql.rust.elements.Call
78
private import codeql.rust.dataflow.DataFlow
89
private import codeql.rust.dataflow.FlowSource
910
private import codeql.rust.dataflow.FlowSink
1011
private import codeql.rust.Concepts
1112
private import codeql.rust.dataflow.internal.Node
1213
private import codeql.rust.security.Barriers as Barriers
14+
private import codeql.rust.internal.TypeInference as TypeInference
15+
private import codeql.rust.internal.Type
1316

1417
/**
1518
* Provides default sources, sinks and barriers for detecting accesses to
@@ -47,11 +50,17 @@ module AccessInvalidPointer {
4750
ModelsAsDataSource() { sourceNode(this, "pointer-invalidate") }
4851
}
4952

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

5766
/**
@@ -61,6 +70,40 @@ module AccessInvalidPointer {
6170
ModelsAsDataSink() { sinkNode(this, "pointer-access") }
6271
}
6372

73+
private class BarrierCall extends Barrier {
74+
BarrierCall() {
75+
exists(Call call, ArgumentPosition pos, string canonicalName |
76+
call.getStaticTarget().getCanonicalPath() = canonicalName and
77+
this.asExpr() = call.getArgument(pos)
78+
|
79+
canonicalName = "<core::ptr::non_null::NonNull>::new" and pos.asPosition() = 0
80+
)
81+
}
82+
}
83+
84+
private class NumericTypeBarrier extends Barrier instanceof Barriers::NumericTypeBarrier { }
85+
86+
private class BooleanTypeBarrier extends Barrier instanceof Barriers::BooleanTypeBarrier { }
87+
88+
private class FieldlessEnumTypeBarrier extends Barrier instanceof Barriers::FieldlessEnumTypeBarrier
89+
{ }
90+
91+
private class DefaultBarrier extends Barrier {
92+
DefaultBarrier() {
93+
// A barrier for calls that statically resolve to the `Default::default`
94+
// trait function. Such calls are imprecise, and can always resolve to the
95+
// implementations for raw pointers that return a null pointer. This
96+
// creates many false positives in combination with other inaccuracies
97+
// (too many `pointer-access` sinks created by the model generator).
98+
//
99+
// We could try removing this barrier in the future when either 1/ the
100+
// model generator creates fewer spurious sinks or 2/ data flow for calls
101+
// to trait functions is more precise.
102+
this.asExpr().(Call).getStaticTarget().getCanonicalPath() =
103+
"<_ as core::default::Default>::default"
104+
}
105+
}
106+
64107
/**
65108
* A barrier for invalid pointer access vulnerabilities for values checked to
66109
* be non-`null`.

0 commit comments

Comments
 (0)