Sicherer Post-Patching Runtime-Verifier: Liest die .meta_safe-ELF-Section aus /proc/self/exe, re-berechnet CRC32-Prüfsummen für jede Code-Page (4 096 Bytes) und meldet, ob das Binary seit dem Kompilieren unverändert ist. Die Section wird vom Compiler-Pass ms_appendMetaSafe() automatisch erzeugt, wenn --meta-safe gesetzt ist — kein manuelles Linking erforderlich. Auf x86_64 steht ein optimierter Fast-Path zur Verfügung.
→ Standard Library · std.alloc
Was diese Unit prüft — und was nicht (gemessen mit lyxc 1.1.14A):
* Sie liest die Datei/proc/self/exeund rechnet über deren Inhalt. Erkannt wird damit eine Manipulation des Programms auf dem Datenträger (Post-Patching). Ein Bit-Flip in einer bereits geladenen Codeseite im RAM wird davon nicht erfasst — für den SEU-Schutz, den die Safety-Guides beschreiben, reicht das nicht (#1879).
* Sie läuft nur, wenn das Programm sie selbst ruft. Einen periodischen Sweep gibt es hier nicht — den bringt seit 1.1.15A@integrity(mode: scrubbed, interval: …)mit, und der prüft die geladenen Codeseiten, nicht die Datei (→ Memory Scrubbing). Zwei Wege, zwei Fragen.
* Sie erkennt, sie korrigiert nicht. Die Hashtabelle liegt inzwischen im Format v2 (METASAF2) dreifach ab, sodass die Mehrheit über einen verfälschten Eintrag entscheidet (#1877).
Nachgemessen: ohne--meta-safeliefertMetaSafeVerify()-1(Sektion fehlt), mit--meta-safe0; nach dem Kippen eines einzelnen Byte im Codebereich der Datei wieder-1.
Der Lyx-Compiler legt beim Build eine ELF-Section .meta_safe an, die für jede 4 096-Byte-Page im .text-Segment einen Eintrag enthält:
| Offset | Größe | Inhalt |
|---|---|---|
| 0 | 4 Bytes | Magic 0x4D455441 („META„) |
| 4 | 4 Bytes | Anzahl Pages (pageCount) |
| 8 | 8 Bytes | Tatsächliche .text-Länge in Bytes (codeLen) |
| 16 + n×8 | 4 Bytes | Page-Offset von .text-Start |
| 16 + n×8 + 4 | 4 Bytes | Gespeicherter CRC32 dieser Page |
MetaSafeVerify öffnet /proc/self/exe, liest das gesamte Binary, lokalisiert die .meta_safe-Section über den ELF-Section-Header-Table, re-berechnet den CRC32 jeder Page und vergleicht mit den gespeicherten Werten.
| Signatur | Beschreibung |
|---|---|
MetaSafeVerify(): int64 | Prüft alle Code-Pages. Gibt 0 zurück wenn alle CRC32-Prüfsummen stimmen, −1 bei Fehler (korrupte Page, fehlende Section, kein Lesezugriff auf /proc/self/exe). |
MetaSafeGetPageHash(pageIdx: int64): int64 | Gibt den gespeicherten CRC32-Wert für Page pageIdx (0-basiert) zurück, oder −1 wenn pageIdx außerhalb des gültigen Bereichs liegt. |
import std.meta_safe;
import std.io;
fn main(): void {
var r := MetaSafeVerify();
if (r != 0) {
PrintLn("WARNUNG: Binary-Integrität verletzt!");
// Sicherheitsreaktion: Abbruch, Logging, Alert …
exit(1);
}
// Normaler Programmstart …
}
import std.meta_safe;
import std.io;
fn PrintPageHashes(count: int64): void {
var i: int64 := 0;
while (i < count) {
var crc := MetaSafeGetPageHash(i);
if (crc < 0) { break; }
Print(StrConcat(StrConcat("Page ", IntToStr(i)), ": CRC32 = 0x"));
// CRC als Hex ausgeben …
PrintLn(IntToStr(crc));
i := i + 1;
}
}
import std.meta_safe;
import std.thread;
fn IntegrityWatchdog(): void {
// In einem separaten Thread periodisch prüfen
while (1 == 1) {
if (MetaSafeVerify() != 0) {
// Alarm schlagen …
}
sleep(30000); // alle 30 Sekunden
}
}
Die verwendete Polynomkonstante ist 0xEDB88320 (ISO 3309, PKZIP-kompatibel). Die Implementierung spiegelt exakt den Compiler-seitigen ms_crc32:
// CRC32 über len Bytes ab data:
// crc = 0xFFFFFFFF
// für jedes Byte b: crc = (crc >> 1) ^ (0xEDB88320 falls LSB gesetzt)
// Rückgabe: crc ^ 0xFFFFFFFF
MetaSafeVerify öffnet /proc/self/exe und liest das gesamte Binary in den Heap — bei großen Binaries (> 10 MB) entsprechend Speicher einplanen.MetaSafeVerify gibt −1 zurück wenn die .meta_safe-Section fehlt (d. h. das Binary wurde nicht mit --meta-safe gebaut oder der Abschnitt wurde gestripped).--integrity-check: --integrity-check (getriggert durch @integrity) erzeugt ein festes 8232-Byte-Format mit drei CRC32-Kopien des gesamten Code-Segments (TMR-Schema). --meta-safe erzeugt eine variable Section mit einem CRC32 pro 4 096-Byte-Page — feiner granular, direkt zugänglich via MetaSafeGetPageHash.MetaSafeVerify() → 0 bei unverändert, −1 bei korrumpierter Page oder fehlender Section; MetaSafeGetPageHash(invalidIdx) → −1.std.alloc — Speicherverwaltung (wird intern von MetaSafeVerify genutzt)std.fs_ext — Fstat, Dateilesen
Letzte Aktualisierung: 2026-09-05 (#1908, gemessen mit lyxc 1.1.18A) — Kasten gezogen: der periodische Sweep existiert seit 1.1.15A über @integrity(mode: scrubbed) (prüft die geladenen Codeseiten, nicht die Datei), und die Hashtabelle liegt im Format v2 dreifach ab.
Vorherige letzte Aktualisierung: 2026-06-06
Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).
Letzte Aktualisierung: 2026-08-30 — Reichweite der Prüfung gegen lyxc 1.1.14A nachgemessen und eingeordnet (Datei statt RAM, kein Sweep, keine Korrektur).