# Rusts Ownership-Modell: Speichersicherheit ohne Garbage Collector

Rund 70 % der schweren Sicherheitslücken in C und C++ sind Speicherverletzungen. Rusts Ownership-System schließt sie zur Compile-Zeit aus, ohne Laufzeitkollektor — und die Branche zieht endlich nach.

Published: 3. Oktober 2024
Canonical HTML: https://glazastov.de/rust-ownership-model
Markdown: https://glazastov.de/rust-ownership-model.md

Dreißig Jahre lang lebte die Systemprogrammierung mit einem Trade-off, der grundlegend wirkte: entweder manuelle Speicherverwaltung samt ihrer Fehler, oder ein Garbage Collector samt seiner Latenz. Rust verweigerte die Wahl. Sein _Ownership-Modell_ liefert die Sicherheit einer verwalteten Sprache und die Layout-Kontrolle von C — vollständig zur Compile-Zeit bezahlt. Der Mechanismus besteht aus wenigen Regeln und einem Compiler, der sturköpfig genug ist, sie durchzusetzen.

## Der Preis, der die Idee nötig machte

Speicherfehler sind kein ästhetischer Einwand. Sie sind die dominante Quelle ferngesteuert ausnutzbarer Sicherheitslücken in C- und C++-Code. Microsofts Security Response Center hat es beziffert:

> „Rund 70 % der von Microsoft jährlich vergebenen CVEs sind weiterhin Speicherfehler." — Matt Miller, _Trends, Challenges, and Shifts in Software Vulnerability Mitigation_, BlueHat IL, Februar 2019.

Googles Chromium-Team berichtet unabhängig dieselbe Quote:

> „Etwa 70 % unserer schwerwiegenden Sicherheitsfehler sind Speicherprobleme." — _The Chromium Projects, Memory safety_, fortlaufend.

Im Februar 2024 ging das Office of the National Cyber Director im Weißen Haus über die bloße Beschreibung hinaus:

> „Speichersicherheitslücken sind eine Klasse von Schwachstellen, die betrifft, wie Speicher gelesen, geschrieben, alloziert oder freigegeben wird. Vor allem aber sind sie vermeidbar. Der wirksamste Weg, diese gesamte Klasse zu eliminieren, ist, dass Softwarehersteller speichersichere Programmiersprachen einsetzen." — ONCD, _Back to the Building Blocks: A Path Toward Secure and Measurable Software_, Februar 2024.

Die empirische Bestätigung kam von Android. Indem Google neuen Plattformcode konsequent in Rust schrieb und den alten C/C++-Code unangetastet ließ, sank der Anteil speichersicherheitsrelevanter CVEs von **76 % aller jährlichen Android-Schwachstellen 2019 auf 24 % 2024**:

> „Der Anteil speichersicherheitsrelevanter Schwachstellen in Android sank von 76 % im Jahr 2019 auf 24 % 2024 — deutlich unter den 70 % der Branche." — Jeff Vander Stoep, _Eliminating Memory Safety Vulnerabilities at the Source_, Google Security Blog, September 2024.

Alter Code altert weiter; neuer Code produziert schlicht keine neuen Fehler dieser Klasse.

Vor diesem Hintergrund existiert Ownership. Es ist kein Sprachfeature. Es ist ein Sicherheitsargument.

## Die drei Regeln

Jeder Wert in Rust gehorcht drei Regeln:

1. Jeder Wert hat genau **einen Eigentümer** (eine Bindung).
2. Verlässt der Eigentümer den Geltungsbereich, wird der Wert **freigegeben** — sein Destruktor läuft, sein Speicher wird freigegeben.
3. Referenzen auf einen Wert unterliegen der Regel **Aliasing XOR Mutabilität**: zu jedem Zeitpunkt gibt es entweder eine veränderliche Referenz oder beliebig viele unveränderliche, niemals beides.

Die ersten beiden Regeln liefern deterministische Zerstörung (RAII, geerbt von C++). Die dritte Regel — Exklusivität des schreibenden Zugriffs — ist der eigene Beitrag und der Grund, weshalb Data Races und die meisten Iterator-Invalidierungen statisch unmöglich werden.

Formal gilt für zwei lebende Referenzen $r_1, r_2$ auf denselben Wert:

$$
\neg \bigl( \mathrm{mut}(r_1) \wedge \mathrm{alive}(r_2) \wedge r_1 \neq r_2 \bigr)
$$

Der Compiler beweist diese Eigenschaft für jede Referenz im Programm. Eine Laufzeitprüfung gibt es nicht.

Den vollständigen Beweis, dass die Regeln solide sind — dass sicheres Rust wirklich kein undefiniertes Verhalten erzeugen kann —, lieferte das Projekt RustBelt, das eine substantielle Teilmenge der Sprache und ihrer Standardbibliothek im Beweisassistenten Coq formalisierte.

> „RustBelt ist die erste formale Verifikation der Sprache Rust und prüft nicht nur das Typsystem, sondern auch eine repräsentative Sammlung von Bibliotheken aus Rusts Standardbibliothek." — Jung, Jourdan, Krebbers, Dreyer, _RustBelt: Securing the Foundations of the Rust Programming Language_, POPL 2018.

## Move-Semantik und RAII

```rust
fn main() {
    let s1 = String::from("hallo");
    let s2 = s1; // s1 wird in s2 BEWEGT

    // println!("{}", s1); // error[E0382]: Verwendung nach Move

    println!("{}", s2); // s2 ist Eigentümer; beim Verlassen genau einmal verworfen
}
```

Die Zuweisung `let s2 = s1` kopiert nicht den Heap-Puffer, sondern überträgt das Eigentum. Der Compiler verfolgt anschließend, dass `s1` uninitialisiert ist. Verlässt `s2` den Geltungsbereich, läuft `Drop::drop` einmal. Es gibt keine Reference Counts, keinen Tracing Collector, kein manuelles `free`.

Es ist dasselbe RAII-Muster, das C++ seit 1985 kennt — nur durchgesetzt. In C++ verursachen ein nachlässiger Kopierkonstruktor oder ein vergessenes `std::move` Doppelfreigaben oder Leaks. In Rust verweigert der Borrow-Checker schon die Übersetzung.

## Borrowing: Aliasing XOR Mutabilität

Eine Referenz in Rust hat zwei Formen:

| Form                       | Schreibweise | Fähigkeit                                      |
| -------------------------- | ------------ | ---------------------------------------------- |
| Gemeinsam (unveränderlich) | `&T`         | Beliebig viele gleichzeitig; nur lesend        |
| Exklusiv (veränderlich)    | `&mut T`     | Maximal eine zeitgleich; lesend und schreibend |

Der Borrow-Checker erzwingt diese Eigenschaften als statischen Typzustand jeder Bindung. Der Gewinn ist nicht nur Speichersicherheit: Der Optimierer darf annehmen, dass `&T`-Referenzen frei von Aliasing mit jeder `&mut T` auf denselben Speicher sind. Das ist die `noalias`-Annotation, die LLVM in C nie zuverlässig erhält. Rust liefert sie qua Konstruktion.

Der Preis ist die berüchtigte Lernkurve. Muster, die in Java oder Go trivial kompilieren — eine doppelt verkettete Liste, ein Graph mit Eltern-Zeigern, eine Closure, die eine veränderliche Referenz über den Geltungsbereich hinaus einfängt — lassen sich ohne `unsafe`, `Rc<RefCell<T>>` oder einen Umentwurf nicht ausdrücken. Der Community-Konsens lautet: das ist ein Feature, kein Bug — diese Muster waren meistens selbst der Fehler.

## Lifetimes

Eine Referenz darf nicht länger leben als ihre Daten. Rust drückt das mit **Lifetime-Parametern** aus, die über Geltungsbereiche generisch sind:

```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}
```

Die Signatur erklärt, dass die zurückgegebene Referenz aus derselben Region `'a` stammt wie die Eingaben. Die Beziehung zwischen Lifetimes nutzt Subtyping: `'a: 'b` bedeutet, dass `'a` `'b` überlebt. Die meisten Lifetime-Annotationen leitet der Compiler aus den Elisionsregeln ab; explizit erscheinen sie nur, wenn das Verhältnis zwischen Ein- und Ausgang wirklich mehrdeutig ist.

Lifetimes werden zur Compile-Zeit gelöscht. Sie erzeugen keinen Code und kosten zur Laufzeit kein Byte. Sie existieren nur als Beweispflicht für den Typ-Checker.

## Send, Sync und furchtlose Nebenläufigkeit

Die Marker-Traits `Send` und `Sync` erweitern Ownership-Reasoning auf Threads:

- `T: Send` — Werte vom Typ `T` dürfen Thread-Grenzen überschreiten.
- `T: Sync` — `&T` darf zwischen Threads geteilt werden (äquivalent: `&T: Send`).

Diese Traits werden anhand der strukturellen Komposition eines Typs automatisch abgeleitet. `Rc<T>` (nicht-atomarer Referenzzähler) ist `!Send`, weil zwei Threads, die den Zähler gleichzeitig dekrementieren, eine Race bildeten. `Arc<T>` ist `Send + Sync`, weil der Zähler atomar ist. Der Compiler weigert sich zur Compile-Zeit, einen Thread mit einem nicht-`Send`-Wert zu starten.

Zusammen mit Aliasing-XOR-Mutabilität ergibt das, was die Community **fearless concurrency** nennt: derselbe Borrow-Checker, der einfädige Iterator-Invalidierungen verhindert, verhindert auch mehrfädige Data Races — und aus demselben Grund.

## Was das kostet

Das Ownership-Modell hat Kosten, die jede ehrliche Darstellung nennen muss.

- **Async-Lifetimes.** Borrows über `await`-Punkte laufen in das `Pin` / self-referential-Generator-Problem, das die Sprache noch nicht abschließend gelöst hat. Async-Funktionen in Traits, Ende 2023 stabilisiert, weisen weiterhin Ergonomielücken auf, die fortgeschrittene Muster mit Crates wie `async-trait` umgehen.
- **Verkettete Datenstrukturen.** Klassische Graphen oder Bäume ohne `unsafe` verlangen Arena-Allocator oder Index- statt Zeigerdarstellungen. Korrekt, aber nicht das, was ein C-Programmierer erwartet.
- **Compile-Zeit.** Monomorphisierung plus Borrow-Analyse machen Rust langsam zu übersetzen. Saubere Builds eines mittleren Workspaces dauern Minuten, nicht Sekunden.
- **Lernkurve.** Programmierer, die eine andere Systemsprache fließend beherrschen, brauchen üblicherweise mehrere Monate, bis sie aufhören, gegen den Borrow-Checker zu kämpfen.
- **`unsafe`.** Eine Korpusstudie von 2020 fand, dass rund **29 % der Crates auf crates.io mindestens einen `unsafe`-Block enthalten**, und die Standardbibliothek ist intern stark `unsafe`. Ownership ist eine Garantie über _sicheres_ Rust; `unsafe` ist die Falltür, an der die Garantie nicht greift und an der menschliche Prüfung übernehmen muss.

Keine dieser Kosten ist tödlich. Alle sind real.

## Wo Rust heute steht

| Bereich                       | Status                                                                                                         |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Linux-Kernel                  | Rust-Unterstützung in 6.1 gemerged, Oktober 2022; Treiber und `rust-for-linux`-Subsysteme wachsen              |
| Windows                       | Rust-Module in DWriteCore, Win32 GDI / GDI+ Region-Engine und Teilen von win32k (2023–24)                      |
| Android-Plattform             | Neuer nativer Code in Rust; Anteil speichersicherheitsrelevanter CVEs von 76 % (2019) auf 24 % (2024) gesunken |
| Chromium                      | Rust seit Januar 2023 für Drittbibliotheken zugelassen; First-Party-Einsatz wächst                             |
| AWS Firecracker, Bottlerocket | Produktion-VMM und -OS für AWS Lambda und Fargate, in Rust geschrieben                                         |
| Kryptografie & TLS            | `rustls`, `ring`, `dalek-cryptography`, `RustCrypto`; auditiert und im Produktivbetrieb                        |
| Eingebettet                   | `embedded-hal`-Ökosystem stabil; Tock OS im Einsatz, Hubris in der Oxide-Cloud-Computer-Hardware               |

Die meistzitierte Branchenstimme kam vom CTO von Microsoft Azure:

> „Was Sprachen angeht, ist es Zeit, keine neuen Projekte mehr in C/C++ zu beginnen und Rust dort einzusetzen, wo eine Nicht-GC-Sprache erforderlich ist. Aus Sicherheits- und Zuverlässigkeitsgründen sollte die Branche diese Sprachen als veraltet erklären." — Mark Russinovich, September 2022.

CISA, NSA und ONCD in den USA haben Leitlinien veröffentlicht, die für neuen Code in kritischen Systemen speichersichere Sprachen empfehlen. Rust ist die einzige systemtaugliche Sprache dieser Kategorie mit produktionsreifen Einsatznachweisen.

## Der stille Teil

Das Ownership-Modell wird oft als cleverer Trick beschrieben. Das ist es nicht. Es ist die operative Konsequenz einer weit älteren Idee: **lineare Typen**, aus Girards linearer Logik (1987) und Wadlers „Linear Types Can Change the World!" (1990) — Typsysteme, die Ressourcennutzung verfolgen, sodass Werte nicht stillschweigend dupliziert oder verworfen werden können. Was Rust geleistet hat, war nicht die Theorie zu erfinden. Es war, die Theorie ergonomisch genug zu machen, dass Systemprogrammierer sie akzeptieren.

Genau das hat zwanzig Jahre gedauert. Der Borrow-Checker ist die leichte Hälfte; die Syntax, die Fehlermeldungen, die Editorintegration, die Standardbibliothek und das kulturelle Beharren darauf, dass kompilierender Code der Boden und nicht die Decke ist — das machte die Adoption möglich. Jeder andere Versuch linearer Typen in einer Mainstream-Sprache scheiterte nicht am Typsystem, sondern an der Unzumutbarkeit der Benutzung.

> „Kryptografie wird selten gebrochen; sie wird umgangen."
> — Adi Shamir

Dasselbe gilt für Sicherheit in Systemcode. C und C++ sind nicht unsicher, weil ihre Typsysteme schwach sind. Sie sind unsicher, weil der sichere Pfad eine Wachsamkeit verlangt, die kein Mensch über eine Million Zeilen aufrechterhält. Ownership beseitigt diese Forderung.

## Quellen

1. Miller, M. _Trends, Challenges, and Shifts in Software Vulnerability Mitigation_. BlueHat IL, Microsoft Security Response Center, Februar 2019. [github.com/Microsoft/MSRC-Security-Research](https://github.com/Microsoft/MSRC-Security-Research/blob/master/presentations/2019_02_BlueHatIL/2019_01%20-%20BlueHatIL%20-%20Trends%2C%20challenge%2C%20and%20shifts%20in%20software%20vulnerability%20mitigation.pdf)
2. The Chromium Projects. _Memory safety_. [www.chromium.org/Home/chromium-security/memory-safety](https://www.chromium.org/Home/chromium-security/memory-safety/)
3. Office of the National Cyber Director. _Back to the Building Blocks: A Path Toward Secure and Measurable Software_. Weißes Haus, Februar 2024. [bidenwhitehouse.archives.gov/.../Final-ONCD-Technical-Report.pdf](https://bidenwhitehouse.archives.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf)
4. Vander Stoep, J. _Eliminating Memory Safety Vulnerabilities at the Source_. Google Security Blog, September 2024. [security.googleblog.com](https://security.googleblog.com/2024/09/eliminating-memory-safety-vulnerabilities-Android.html)
5. NSA. _Software Memory Safety Cybersecurity Information Sheet_. November 2022. [media.defense.gov](https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI_SOFTWARE_MEMORY_SAFETY.PDF)
6. Jung, R.; Jourdan, J.-H.; Krebbers, R.; Dreyer, D. _RustBelt: Securing the Foundations of the Rust Programming Language_. POPL 2018. [plv.mpi-sws.org/rustbelt](https://plv.mpi-sws.org/rustbelt/)
7. Astrauskas, V.; Matheja, C.; Poli, F.; Müller, P.; Summers, A. _How Do Programmers Use Unsafe Rust?_ OOPSLA 2020. [doi.org/10.1145/3428204](https://doi.org/10.1145/3428204)
8. Girard, J.-Y. _Linear Logic_. Theoretical Computer Science 50(1), 1987.
9. Wadler, P. _Linear Types Can Change the World!_ In _Programming Concepts and Methods_, North-Holland, 1990.
10. Klabnik, S.; Nichols, C. _The Rust Programming Language_. No Starch Press / rust-lang.org. [doc.rust-lang.org/book](https://doc.rust-lang.org/book/)
11. Torvalds, L. Merge des initialen Rust-Supports, Linux 6.1, Oktober 2022. [git.kernel.org](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8aebac82933ff1a7c8eede18cab11e1115e2062b)
12. Russinovich, M. Öffentliche Stellungnahme zur Rust-Adoption, 19. September 2022. [twitter.com/markrussinovich/status/1571995117233504257](https://web.archive.org/web/20220920000839/https://twitter.com/markrussinovich/status/1571995117233504257)
