rust-safety · git:20261103.3acb4ab · 2026-11-03 · sha256 4e5a66cecc75c312
rust-safety git:20261103.3acb4abA
Immutable. This exact content never changes and is served at /api/v1/blob/4e5a66cecc75c312.
--- name: rust-safety description: > Use when auditing Rust safety or security, writing unsafe abstractions or C FFI/C-ABI bridges to C++, or investigating panic- or recursion-driven denial of service, resource/raw-handle ownership, untrusted input, filesystem/process boundaries, or concurrency invariant failures. Covers soundness proofs, MaybeUninit, Drop, Send/Sync, ABI/layout, C strings, allocator ownership, callbacks, FFI unwinding, Rust 2024 unsafe syntax, cancellation, and Miri/sanitizer evidence. Not a general Rust tutorial, style review, cryptographic design, or secret-memory erasure guide. --- # Rust Safety and Security Review the invariant and its observable consequences, not the presence of `unsafe`, `unwrap`, or a suspicious API. Safe Rust can have availability and logic vulnerabilities; a soundness defect is not automatically a remote exploit. ## Quick reference: load only the relevant guide | Task or symptom | Read | First question | |---|---|---| | Raw pointers, provenance, unions, packed fields | [Safety and initialization](references/safety-and-initialization.md) | Can a safe owner/slice express it; if not, what proves the raw operation? | | `MaybeUninit`, manual allocation, panic during `Drop` | [Safety and initialization](references/safety-and-initialization.md#initialization-and-destruction) | What remains live and initialized on every exit? | | Unsafe traits, hostile safe callbacks, pinning | [Safety and initialization](references/safety-and-initialization.md#unsafe-traits-and-pinning) | Can any safe client break the invariant? | | C ABI/layout, strings, foreign ownership, callbacks | [C boundaries](references/c-boundaries.md) | Who owns the allocation, and when does foreign access end? | | FFI panic/exception, Rust 2024 extern/unsafe-attribute warning | [Syntax and unwinding](references/c-boundaries.md#rust-2024-syntax-and-unwinding) | Which ABI and panic policy apply before the boundary is crossed? | | Panic, recursive values, memory/work exhaustion | [Availability and resources](references/availability-and-resources.md) | Can untrusted input exhaust the deployed process or its shared capacity? | | Deadlocks, atomic protocols, cancellation | [Availability and resources](references/availability-and-resources.md#concurrency-and-cancellation) | Which state or resource survives interruption? | | Lengths, encodings, paths, process arguments | [Input and OS boundaries](references/input-and-os-boundaries.md) | Which authority or identity does this input select? | | Raw descriptors, handoff errors, handle leaks | [Descriptor ownership](references/input-and-os-boundaries.md#raw-descriptors-are-resources-not-arbitrary-integers) | Who owns the resource on each success, failure, and interruption path? | | Write/flush errors, partial output, durability | [Output and persistence](references/input-and-os-boundaries.md#output-and-persistence) | Was output delivered, and what persistence guarantee was actually promised? | | Reproducer, Miri, sanitizers, fuzzing, dependency warnings | [Verification and traps](references/verification-and-traps.md) | What does this evidence establish, and what did not run? | The bundle is self-contained. Source links support the local guidance; routine use does not require fetching every source. [Sources and decisions](references/sources-and-decisions.md) records research provenance and rejected claims, not an extra prerequisite. ## Workflow 1. **Scope the contract.** Establish library versus application, actors and trust boundaries, public safe API, MSRV/edition, targets, features, dependency/native versions, build flags, panic strategy, resource promises, and concurrent or reentrant calls. Ask only for consequential intent or authority the repository cannot establish. Track pending, reviewed, and blocked areas for multi-file work. 2. **Map the whole boundary.** Trace constructors, mutators, exposed fields, callbacks, returned borrows, ownership transfers, and destruction. Include generated/macro-expanded code and relevant dependencies: an empty `unsafe` search is not proof of a safe implementation. 3. **State the proof or failure condition.** For each unsafe operation identify allocation/extent, alignment, initialization/validity, lifetime, aliasing, provenance, destruction, and thread obligations. For safe-code hazards identify controllable input/state, the violated limit or invariant, and the harmed consumer. Separate documented facts, project assumptions, and unresolved claims. 4. **Try to refute it.** Follow actual validation, type/private invariants, wrappers, configuration, and containment. A safe API needs no redundant runtime check when its types or established invariants already prove the obligation. Keep unsafe blocks small. A `SAFETY:` comment must name where a fact is established and how long it holds, not merely say “pointer is valid.” Document the shared module invariant when several safe methods participate. Restore invariants before calling user code; use unwind guards where needed to preserve memory safety on interruption. 5. **Choose the smallest correction.** Prefer existing safe std/library APIs, typed ownership, checked arithmetic, bounded work, and explicit errors. If callers must prove memory validity, expose a precise unsafe contract rather than a safe raw-pointer API with a null check. New unsafe code needs a concrete capability requirement or measured motivation; unsafe is not inherently faster. Do not add a partial collection or framework just to wrap one foreign call. 6. **Exercise failure and interruption.** Cover malformed/maximum/empty inputs, errors, partial initialization, user `Clone`/`Drop`, panics, reentrancy, cancellation, and repeated ownership cycles as applicable. Verify actual native or deployed behavior; use isolated subprocesses for expected aborts. Never deliberately execute UB in an ordinary regression test. 7. **Report honestly.** Classify soundness defects, reachable vulnerabilities, correctness defects, and hardening observations separately. Provide location, violated contract, triggering path, impact, minimal correction, and exercised evidence. Missing context or an unrun check is **unverified**, not safe/cleared. Resolve confirmed defects or explicitly report the remaining blocker. ## Critical guards - **Any safe caller:** a safe abstraction must prevent UB for arbitrary safe clients, including surprising callbacks and safe trait implementations. Soundness does not depend on finding a network exploit. Safe code can encounter UB through an unsound dependency; successful compilation is not a safety proof. `unsafe` does not disable the borrow checker or relax Rust's validity rules. - **Pointer proofs are conjunctive:** nullness or `NonNull` alone does not prove extent, alignment, initialized valid values, lifetime, aliasing, or provenance. Raw slice constructors still need non-null aligned pointers for empty slices. - **Initialization is a transition:** capacity is not initialized length; publish only successfully initialized elements. A post-call bound check cannot undo a foreign out-of-bounds write. Keep interruption from exposing invalid slots. - **Lifetime and destruction:** keep `CString` and other borrowed owners alive; pair transfers with the matching allocator/release function exactly once. Safe `mem::forget` must not create dangling callbacks. Unregistering is not enough without callback quiescence. - **ABI is not a wire format:** `repr(C)` does not make nested Rust containers C-compatible, initialize padding, or validate enums. Contain recoverable Rust panics inside a non-unwinding callback boundary, not outside it. - **Build settings matter:** `debug_assert!` cannot be the sole safety enforcer when disabled; overflow and panic behavior depend on the effective build. Parser protection does not automatically cover formatting, serialization, composed values, or destruction. - **Concurrency is more than data races:** `Send`/`Sync`, atomics, and `Arc` do not prove protocol atomicity, progress, fairness, cancellation safety, or shutdown. - **Boundaries stay boundaries:** `Path::join` is not confinement; argument separation is not a guarantee about the invoked program; lossy text is not an identity-preserving conversion. - **Verification is not a sandbox or certificate:** inspect untrusted build scripts/proc macros before execution and use an approved isolated environment. Passing tests, Miri, sanitizers, or an advisory scan does not prove soundness. Exact aliasing/provenance models remain partly unsettled; follow documented contracts and state model-specific uncertainty. ## Completion gate - Safe interfaces preserve the shared invariants; remaining caller obligations are explicit on unsafe interfaces. Every unsafe operation, trait impl, extern declaration, and unsafe attribute has a specific justification. - Relevant boundary and interruption cases are exercised, including initialization, cleanup, callback quiescence, allocator/thread policy, and unwinding where present. - Rust-only, native, and deployed checks are distinguished. Findings carry the contract, trigger, consequence, correction, and actual evidence; skipped/blocked areas and unverified targets stay visible rather than becoming a clean verdict. ## Versions and boundaries Runnable examples target edition 2024, Rust 1.85+, unless explicitly marked Unix-only. Preserve the consuming project's MSRV and edition unless migration is requested; newer documentation is not permission to use newer APIs or guarantees. Nightly tooling is separate. Rust 2024 extern blocks/unsafe attributes and explicit unsafe operations are covered in [C boundaries](references/c-boundaries.md#rust-2024-syntax-and-unwinding). Out of scope: business authorization, cryptographic protocol design, secret-memory erasure, smart-contract semantics, kernel/device policy, and browser/Wasm security. Rust unsafe/FFI inside such systems can still be reviewed here without certifying their domain security. Platform-specific conclusions need the real platform and contracts; a local probe cannot establish all targets. Optional handoffs, if installed: **rust-concurrency** for synchronization/runtime implementation; **rust-idiomatic** for ordinary ownership/errors/I/O; **rust-api-design** for API ergonomics; **rust-type-diagnostics** for advanced lifetime/variance/drop-check diagnostics; **rust-tdd** for test-first workflow; **rust-performance** for measured optimization; **rust-wasm** for JS/WASI boundaries.