Memory Scrubbing

Memory Scrubbing ist ein präventiver Integritätsmechanismus, der das Code-Segment im RAM periodisch auf Bit-Flips prüft — bevor korrumpierte Instruktionen ausgeführt werden. Er läuft als Hintergrundprozess und ist auf Systemen sinnvoll, die kosmischer Strahlung ausgesetzt sind (Luft- und Raumfahrt) oder bei denen SRAM-Fehler durch Alterung und Temperatur auftreten können.

Im Unterschied zu Software Lockstep schützt Memory Scrubbing nicht die Berechnung (CPU-Ebene), sondern den gespeicherten Maschinencode (Speicher-Ebene). Beide Mechanismen sind komplementär.

→ Verwandt: TMR · Software Lockstep · .meta_safe ELF-Sektion · DO-178C Hauptseite


1. Aktivierung

// Unit-Level — schützt alle Funktionen der Unit
@integrity(mode: scrubbed, interval: 100)
unit nav.core;

import std.io;

  • mode: scrubbed — aktiviert den periodischen CRC32-Sweep des Code-Segments
  • interval: 100 — alle 100 ms einen vollständigen Sweep durchführen

Der interval-Wert ist ein Richtwert für die Runtime/den Scheduler. Auf Bare-Metal-Targets mit SysTick wird der Sweep in der SysTick-ISR ausgelöst.


2. Wie der Compiler vorbereitet

Der Scrubbing-Mechanismus setzt voraus, dass der Compiler beim Build eine kryptographische Referenz des Code-Segments einbettet:

  1. Code-Generierung: Backend erzeugt vollständigen Maschinencode.
  2. Sektion anlegen: Die .meta_safe ELF-Sektion wird mit Platzhaltern angelegt.
  3. CRC32-Berechnung: Der Compiler berechnet den CRC32 (IEEE 802.3) über das fertige Code-Segment.
  4. Post-Patching: Die drei Hashslots in .meta_safe werden mit dem echten Wert überschrieben.

Die drei Kopien liegen 4096 Byte voneinander entfernt — ein lokaler Speicherdefekt kann nicht alle drei gleichzeitig korrumpieren.

→ Vollständige Struktur der .meta_safe Sektion: .meta_safe ELF-Sektion


3. Laufzeit-Ablauf

Beim Programmstart und in regelmäßigen Abständen:

Code-Segment im RAM
  ┌─────────────────────────────────────────────────────┐
  │  fn ComputeFlightPath() { … }                       │
  │  fn ReadIMU() { … }                                 │
  │  … alle Instruktionen der Unit …                    │
  └─────────────────────────────────────────────────────┘
             │
             │ CRC32 berechnen (periodisch)
             ▼
        Ist-Hash (neu berechnet)
             │
             │ Vergleich gegen alle drei Referenzen
             ▼
  .meta_safe ELF-Sektion
  ┌────────────────────────────────────────────────────┐
  │  hash_copy_1 @ Offset 32    (CRC32: 0xA3F2...)    │
  │  [4096 Byte Padding]                               │
  │  hash_copy_2 @ Offset 4128  (CRC32: 0xA3F2...)    │
  │  [4096 Byte Padding]                               │
  │  hash_copy_3 @ Offset 8224  (CRC32: 0xA3F2...)    │
  └────────────────────────────────────────────────────┘
             │
     Mehrheitsentscheid (TMR):
     ≥ 2 von 3 stimmen überein → ✅ OK
     < 2 übereinstimmend       → ⚠ Integritätsfehler


4. VerifyIntegrity()

Das Builtin VerifyIntegrity() löst einen sofortigen manuellen Sweep aus und gibt bool zurück:

@integrity(mode: scrubbed, interval: 100)
unit flight_control;

import std.io;

fn StartupCheck(): void {
    if (VerifyIntegrity() = false) {
        // Bit-Flip erkannt — vor dem normalen Betrieb
        PrintStr("INTEGRITY FAILURE — switching to backup\n");
        ActivateBackupComputer();
        HaltPrimary();
    }
    PrintStr("Code integrity verified\n");
}

fn main(): int64 {
    StartupCheck();   // Immer zuerst
    // ... normale Betriebslogik ...
    return 0;
}

VerifyIntegrity() ist das erste, was ein DAL-A-System beim Start aufruft — bevor irgendwelche sicherheitskritischen Berechnungen beginnen.


5. Integration mit dem Scheduler / ISR

Auf Bare-Metal-Targets ohne RTOS löst der SysTick-ISR den periodischen Sweep aus:

unit cortexm_scrub;

@volatile var scrub_tick:  int64 := 0;
con SCRUB_INTERVAL_MS: int64 := 100;

@section(".isr_vector")
@no_opt
fn SysTick_Handler(): void {
    scrub_tick := scrub_tick + 1;
}

fn main(): int64 {
    // Startup-Check
    if (VerifyIntegrity() = false) {
        panic("boot integrity failure");
    }

    var last_scrub: int64 := 0;

    while (true) {
        // Anderen Aufgaben verarbeiten ...
        DoControlCycle();

        // Periodischer Scrub
        if (scrub_tick - last_scrub >= SCRUB_INTERVAL_MS) {
            last_scrub := scrub_tick;
            if (VerifyIntegrity() = false) {
                // Bit-Flip im Code erkannt — Recovery
                ActivateBackupSystem();
            }
        }
    }
    return 0;
}

Auf FreeRTOS (ESP32) wird der Sweep in einer dedizierten Low-Priority-Task ausgeführt:

fn ScrubTask(arg: int64): void {
    while (true) {
        vTaskDelay(100);   // 100 RTOS-Ticks ≈ 100 ms
        if (VerifyIntegrity() = false) {
            ActivateBackupSystem();
        }
    }
}


6. Timing-Fenster

Zwischen zwei Sweeps besteht ein ungeschütztes Zeitfenster: Ein Bit-Flip, der nach einem erfolgreichen Sweep entsteht, wird erst beim nächsten Sweep erkannt. Dieses Fenster ist durch interval konfigurierbar.

Interval Ungeschütztes Fenster CRC-Overhead (typisch)
10 ms Max. 10 ms ~5–15 µs pro Sweep (je nach Code-Segment-Größe)
100 ms Max. 100 ms Vernachlässigbar
1000 ms Max. 1 s Minimalster Overhead

Für DAL-A empfiehlt sich ein Interval von 50–100 ms. Der CRC-Overhead ist proportional zur Größe des Code-Segments und liegt bei typischen Avionik-Units (< 64 kB Code) unter 20 µs.


7. Kombination mit anderen Schutzmechanismen

// Maximaler Schutz: Unit mit Scrubbing + kritische Funktionen mit Lockstep + @redundant Daten
@integrity(mode: scrubbed, interval: 50)
unit autopilot.kernel;

@redundant
var flight_mode: int64 := 0;

@dal(A)
@flight_crit
@integrity(mode: software_lockstep, interval: 50)
@wcet(200)
@stack_limit(2048)
fn ComputeFlightCommands(state: ^FlightState): FlightCommands {
    // Berechnung geschützt durch: Lockstep (ALU) + Scrubbing (Code-Segment) + TMR (Daten)
    // Das ist die Dreifach-Absicherung für DAL-A-Kernfunktionen
}

Mechanismus Was er schützt Ergänzt
@integrity(scrubbed) Code-Segment (Bit-Flip in Instruktionen) Lockstep, TMR
@integrity(software_lockstep) Berechnungen (Latch-Fehler in der CPU) Scrubbing, TMR
@redundant Kritische Datenwerte (Bit-Flip im RAM) Scrubbing, Lockstep

8. DAL-Empfehlung

DAL Memory Scrubbing Begründung
A Zwingend Nachweis gegen Single-Point-Failure im Code-Speicher
B Empfohlen SEU-Risiko rechtfertigt Overhead
C Optional Sinnvoll auf strahlungsexponierten Targets
D/E Nicht nötig Kein SEU-Schutz gefordert

Letzte Aktualisierung: 2026-05-22