Section 44: Rust and Memory Safety — Overview
Purpose and Scope
This section examines memory safety as a systems property and Rust as the primary production mechanism for achieving it without runtime overhead. The treatment begins with the memory safety problem: what it is, why it matters statistically (70% of critical security vulnerabilities in large C/C++ codebases are memory safety issues), and why garbage-collected languages are an insufficient answer for systems programming. It then develops Rust's ownership, borrowing, and lifetime model from first principles, covers the role and risks of unsafe, and surveys the growing ecosystem of Rust-based systems software: OS kernels, drivers, embedded firmware, and hypervisors. The goal is to give the systems programmer the conceptual framework to evaluate where Rust is the right tool and where it imposes unjustifiable costs.
Prerequisites
- Section 11: Memory Management — stack vs heap allocation, allocator design, dangling pointers, double-frees
- Section 10: Synchronization — data races, mutex disciplines, shared state concurrency
- Proficiency in C or C++ — this section contrasts Rust with C; fluency in C makes the contrast concrete
- Section 41: Modern Kernel Challenges — Rust-in-Linux context
Learning Objectives
Upon completing this section, the reader will be able to:
- Enumerate the six classes of memory safety bugs (use-after-free, double-free, buffer overflow, buffer over-read, null pointer dereference, use of uninitialized memory) and explain the exploit primitives each enables
- Explain Rust's ownership model: the three rules (each value has one owner; owner is responsible for deallocation; ownership can be transferred), and why they eliminate use-after-free and double-free at compile time
- Explain the borrow checker: shared references (&T) vs exclusive references (&mut T); the aliasing XOR mutability invariant; why this eliminates data races at compile time
- Explain lifetimes: what they annotate, when they must be explicit, and how the borrow checker uses them to prevent dangling references
- Describe the
unsafesubset: the five unsafe superpowers, the meaning of "safe abstraction over unsafe code," and what soundness requires - Survey the Rust OS ecosystem: Redox, Tock, Theseus, writing Linux kernel modules in Rust
- Compare Rust and C for systems programming on the dimensions of safety, performance, ergonomics, ecosystem, and C interoperability
- Explain Rust's async/await model and the executor/reactor pattern; relate it to io_uring integration
Architecture Overview
MEMORY SAFETY BUG TAXONOMY
=============================
C/C++ programs
|
+── use-after-free (UAF) ──────> type confusion, RCE
+── double-free ───────────────> heap metadata corruption
+── buffer overflow (write) ───> stack smashing, heap overflow
+── buffer over-read ──────────> info leak (Heartbleed)
+── null deref ────────────────> crash / info leak
+── uninitialized memory ──────> info leak, logic error
RUST OWNERSHIP RULES
======================
┌─────────────────────────────────────────────────┐
│ Rule 1: Every value has exactly one owner │
│ Rule 2: When owner goes out of scope → drop() │
│ Rule 3: Ownership can be moved, not copied │
│ (unless T: Copy) │
└─────────────────────────────────────────────────┘
|
v these three rules eliminate:
├── use-after-free (no double ownership)
├── double-free (one owner, one drop)
└── memory leaks (owner always drops)
BORROW CHECKER INVARIANT
==========================
At any point in time, for a value v:
EITHER: any number of shared references &v (read-only, Send)
OR: exactly one exclusive reference &mut v (read-write)
NEVER: both simultaneously
This invariant eliminates:
├── data races (&mut v cannot alias; no concurrent writes)
└── iterator invalidation (cannot mutate while borrowed)
RUST LIFETIME FLOW
===================
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str
| |
|<── lifetime 'a means: returned ref ──> |
lives no longer than either input
→ borrow checker rejects dangling return
Key Concepts
- Memory safety: the property that all memory accesses reference valid, live, allocated memory of the correct type; absence of UAF, double-free, buffer overflow, null deref, and uninit read
- Ownership: a single owner responsible for deallocation; transferred (moved) on assignment; guarantees exactly-once deallocation
- Move semantics: when ownership is transferred, the source variable becomes inaccessible; no implicit copying; forces explicit clone when sharing is needed
- Borrow: a temporary, non-owning reference; either shared (&T, multiple readers) or exclusive (&mut T, single writer); the "aliasing XOR mutability" invariant
- Lifetime: a region of code during which a reference is guaranteed valid; inferred by the compiler in most cases; explicit annotations required when the borrow checker cannot infer them
- Borrow checker: the compiler component that enforces ownership and borrowing rules at compile time; no runtime cost
- unsafe Rust: a subset allowing five additional capabilities: dereferencing raw pointers, calling unsafe functions, accessing mutable statics, implementing unsafe traits, and accessing union fields; programmer takes responsibility for upholding safety invariants
- Safe abstraction: an unsafe implementation that presents a safe public API; the contract is that no safe code using the API can trigger undefined behavior; the standard library is built this way
- Soundness: the property that no safe code can cause undefined behavior; an unsafe abstraction is unsound if there exists any safe code using it that triggers UB
- Send and Sync: marker traits;
Sendmeans a type can be transferred to another thread;Syncmeans a type can be shared by reference across threads; the type system enforces these at compile time - Fearless concurrency: the combination of Send, Sync, and the borrow checker eliminates data races at compile time; the compiler rejects programs with concurrent mutable aliasing
- Drop: the destructor trait; called automatically when value goes out of scope; RAII applied universally; no need for manual resource release
- async/await: syntactic sugar over state machines; futures represent asynchronous computations; executor drives them to completion; enables high-concurrency I/O without threads
- Tock OS: embedded OS in Rust; process isolation via hardware MPU; capsules enforce resource limits; safe kernel with untrusted user processes in Rust
- Redox OS: Unix-like OS in Rust; microkernel; drivers in user space; scheme-based IPC; POSIX compatibility layer
Major Historical Milestones
| Year | Event | Significance |
|---|---|---|
| 2006 | Graydon Hoare begins Rust | Personal project addressing C++ safety pain points |
| 2010 | Mozilla sponsors Rust | Language development accelerates; use case: browser engine Servo |
| 2012 | Ownership model stabilizes | Core borrow checker design settles after several major revisions |
| 2015 | Rust 1.0 released | Stability guarantee; ecosystem begins serious growth |
| 2016 | Tock OS 0.1 | First Rust embedded OS; proves viability for resource-constrained systems |
| 2017 | Redox OS 0.1 | First Unix-like OS in Rust; demonstrates full OS is feasible |
| 2018 | Rust 2018 edition | Non-lexical lifetimes; improved ergonomics; async story begins |
| 2018 | NSA, Microsoft, Google endorse memory safety | Major institutional validation; memory safety narrative shifts |
| 2019 | Rust async stabilized | async/await syntax; tokio ecosystem; production-grade async I/O |
| 2019 | Android begins Rust adoption | First Rust code in Android; Bluetooth stack rewritten |
| 2020 | Rust foundation created | Mozilla, AWS, Google, Huawei, Microsoft; organizational stability |
| 2021 | Rust in Linux RFC accepted | Linus accepts principle of Rust as second language |
| 2022 | Linux 6.1: Rust infrastructure merged | First Rust code in mainline Linux; abstractions for kernel APIs |
| 2022 | Android 13: 21% new code in Rust | Demonstrated at scale; zero memory safety vulnerabilities in Rust code |
| 2023 | NSA: switch to memory-safe languages | NSA guidance explicitly recommends Rust for new systems code |
| 2023 | First Rust PHY driver in Linux mainline | Concrete driver in production kernel |
| 2024 | Rust in Windows kernel | Microsoft merges Rust into Windows kernel for selected components |
Modern Relevance
Memory safety is the defining systems quality challenge of the 2020s. The US Cybersecurity and Infrastructure Security Agency (CISA), NSA, and major cloud vendors have all issued guidance recommending a transition away from memory-unsafe languages for new systems code. The empirical case is clear: Google's Project Zero, Microsoft's Security Response Center, and the Android security team all report ~70% of their critical vulnerabilities are memory safety issues.
Rust is not a panacea. unsafe code must be carefully audited. The borrow checker imposes real ergonomic costs, particularly in graph-shaped and self-referential data structures. C interop requires unsafe. Compile times are slow. The ecosystem, while growing rapidly, lacks the decades of battle-hardened libraries that C possesses.
Despite these limitations, the weight of evidence supports Rust as the best available tool for writing new systems software where memory safety matters and garbage collection overhead is unacceptable. The practitioner who understands Rust's model deeply—not just its syntax—is equipped to reason about the safety of both Rust and C code.
File Map
44-rust-and-memory-safety/
├── 00-overview.md ← This file
├── 01-memory-safety-problem.md
├── 02-ownership-model.md
├── 03-borrow-checker.md
├── 04-lifetimes.md
├── 05-unsafe-rust.md
├── 06-rust-in-linux-kernel.md
├── 07-rust-os-redox-theseus-tock.md
├── 08-rust-async-ecosystem.md
├── 09-rust-vs-c-comparison.md
├── 10-safe-concurrency.md
├── 11-rust-for-embedded.md
├── 12-rust-for-drivers.md
├── 13-memory-safety-bugs-prevented.md
├── 14-adoption-challenges.md
└── 15-c-interop-ffi.md
Cross-References
- Section 10 (Synchronization): data races that Rust eliminates at compile time
- Section 11 (Memory Management): allocator design, heap corruption patterns Rust prevents
- Section 26 (Security): UAF and buffer overflow exploitation; Rust as mitigation
- Section 40 (Failure History): historical memory safety disasters (Heartbleed, Shellshock, Morris Worm)
- Section 41 (Modern Kernel Challenges): Rust-in-Linux current status
- Section 42 (Future of Operating Systems): Rust OS landscape (Redox, Tock, Theseus)
- Section 43 (Formal Verification): Rust type system as lightweight formal verification
- Section 48 (Research Papers): Rust ownership paper, Tock OS paper, Theseus paper