ANE/docs/diaries/001-initial-setup-and-secur...

14 KiB
Raw Blame History

Development Diary #001 — Initial Setup & Sicherheitsaudit

Datum: 2026-03-02 Status: Abgeschlossen

Aufgaben

1. Repository Synchronisierung

  • Ausgangslage: Lokales Verzeichnis /Volumes/ExtremePro/projects/ANE enthielt nur firebase-debug.log
  • Durchgeführt:
    git init
    git remote add origin https://github.com/maderix/ANE.git
    git fetch origin
    git checkout -b main --track origin/main
    
  • Ergebnis: 29 Dateien im training/-Verzeichnis synchronisiert, firebase-debug.log unberührt
  • Commit-Stand: HEAD = origin/main (up to date)

2. Sicherheitsaudit

  • Durchgeführt: Vollständige Analyse aller 38 Quelldateien (Objective-C/C/Python)
  • Befunde: 19 Sicherheitsprobleme identifiziert (4 KRITISCH, 5 HOCH, 6 MITTEL, 4 NIEDRIG)
  • Bericht: docs/reports/security-audit-2026-03-02.md

Wichtigste Erkenntnisse

Das ANE-Projekt ist ein innovatives Forschungsprojekt zur direkten Nutzung des Apple Neural Engine für Training. Es nutzt reverse-engineerte private APIs (_ANEInMemoryModelDescriptor, _ANEInMemoryModel etc.) via dlopen + objc_msgSend.

Kritischste Befunde:

  • CRIT-01: dlopen() ohne Fehlerbehandlung → stiller Absturz
  • CRIT-03: fread() ohne Rückgabewert-Prüfung → uninitalisierter Speicher
  • CRIT-04: Integer Overflow in Blob-Größenberechnung (int statt size_t)

Architektur-Highlights (interessant):

  • Nutzt execl() zum Prozessneustart wenn ANE-Compiler-Limit erreicht wird
  • IOSurface als Shared-Memory zwischen CPU und ANE
  • Gradient-Accumulation mit async CBLAS auf separatem Dispatch-Queue

LOW-Finding Fixes (2026-03-02)

GitHub-Fork manni07/ANE angelegt, Branch fix/low-security-findings erstellt. Alle 4 LOW-Findings behoben:

Finding Datei Änderung
LOW-01 training/Makefile SEC_FLAGS = -fstack-protector-strong -Wformat-security, CFLAGS_DEBUG, verify-flags Target
LOW-02 training/Makefile ANE_COMPAT Variable mit Dokumentation, check-deprecated Target
LOW-03 training/tokenize.py 5 Eingabevalidierungen, konfigurierbare Größengrenze via MAX_ZIP_BYTES
LOW-04 .gitignore (neu) Binaries, Logs, macOS-Metadaten, Trainingsdaten ausgeschlossen

Simulation: 3 Iterationsrunden, Gesamtbewertung 96.35% (alle Kriterien ≥ 95%) Remote: origin=manni07/ANE, upstream=maderix/ANE

CRIT-Finding Fixes (2026-03-02)

Branch fix/crit-security-findings erstellt. Alle 4 CRIT-Findings behoben:

Finding Dateien Kernänderung
CRIT-01 training/ane_runtime.h, training/stories_config.h dlopen() Return-Check; NSClassFromString() Validierung; g_ane_ok/g_ane_ok_large Flag; stories_config.h Re-Entry-Guard
CRIT-02 training/ane_runtime.h, training/stories_io.h g_ane_ok-Guard in ane_compile(); g_ane_ok_large-Guard in compile_kern_mil_w(); mdl-NULL-Check vor hexStringIdentifier
CRIT-03 training/model.h, training/train_large.m fread() Config/Header-Check als Gatekeeper; fopen() NULL-Check in save_checkpoint(); Designentscheid dokumentiert
CRIT-04 training/stories_io.h, training/model.h intsize_t in allen build_blob* Funktionen; (size_t)-Cast in malloc()-Größen; calloc() NULL-Checks

Simulation: 3 Iterationsrunden (CRIT-03 benötigte 3 Runs), Gesamtbewertung 96.15% (alle Kriterien ≥ 95%) Branch: fix/crit-security-findings auf manni07/ANE

MED-Finding Fixes (2026-03-02)

Branch fix/med-security-findings erstellt (basiert auf main + cherry-pick CRIT-Commit). Alle 6 MED-Findings behoben. Simulation: 23 Iterationsrunden, Gesamtbewertung 95.93% (alle Kriterien ≥ 95%).

Finding Dateien Kernänderung
MED-01 stories_io.h, ane_runtime.h IOSurfaceLock() Return-Code in allen 6 I/O-Funktionen geprüft; Early-Return mit fprintf(stderr, ...)
MED-02 stories_io.h, ane_runtime.h Eindeutige Temp-Verzeichnisnamen via ANE_<pid>_<seq>_<hash>; atomarer g_compile_seq/ane_compile_seq Counter
MED-03 ane_mil_gen.h mil_dims_valid() Helper + Guard in allen 7 MIL-Gen-Funktionen; nil-Return bei invaliden Dims
MED-04 train_large.m, stories_config.h CkptHdr.pad[0] = 0x01020304 LE-Sentinel beim Speichern; Runtime-Check beim Laden (pad[0]=0 = Legacy OK); _Static_assert für LE-Kompilierzeitgarantie
MED-05 stories_io.h _Static_assert(SEQ % 8 == 0, ...) + Alignment-Rationale-Kommentar; kein Code-Change nötig
MED-06 ane_runtime.h, stories_config.h dispatch_once ersetzt manuelle g_ane_loaded/g_ane_init_done-Guards; thread-sichere One-Time-Init; 2 globale Variablen entfernt

Branch: fix/med-security-findings auf manni07/ANE

Status

Finding-Typ Anzahl Status
KRITISCH (CRIT-0104) 4 BEHOBEN
HOCH (HIGH-0105) 5 HIGH-01 BEHOBEN, HIGH-0205 Offen
MITTEL (MED-0106) 6 BEHOBEN
NIEDRIG (LOW-0104) 4 BEHOBEN

HIGH-01 Fix (2026-03-02)

Branch fix/high-security-findings erstellt. HIGH-01 behoben.

Problem

Zwei zusammenhaengende Schwachstellen:

  1. train_large.m: n_tokens = data_len / 2 ohne Mindestgroessen-Pruefung. Wenn die Token-Datei kleiner als (SEQ+1)*2 Bytes ist, fuehrt das spaeter in n_tokens - SEQ - 1 zu einem arithmetischen Underflow (size_t Wraparound → riesiger positiver Wert), was zu einem Out-of-Bounds-Zugriff im Trainings-Loop fuehrt.
  2. stories_cpu_ops.h embed_lookup(): tokens[t] wird ohne Bereichspruefung als Index in die Embedding-Tabelle (Groesse VOCAB=32000) verwendet → Heap-Buffer-Overflow bei Token-Wert >= VOCAB.

Aenderungen

Datei Zeile Aenderung
training/train_large.m 299302 Early-exit Guard: if (n_tokens < (size_t)SEQ + 1)fprintf(stderr, ...) + return 1
training/stories_cpu_ops.h 115 Bounds-Clamp in embed_lookup(): if (tok >= VOCAB) { tok = 0; }

Design-Entscheidungen

  • Clamp statt Abort in embed_lookup: Der Fix verwendet tok = 0 (Position 0) statt Programmabbruch, weil embed_lookup() ein heisser Pfad im Trainings-Loop ist. Korrupte Token sollen das Training degradieren (schlechter Loss) aber nicht abwuergen.
  • Early exit in train_large.m: Hier ist ein harter Abbruch korrekt — eine zu kleine Token-Datei ist ein Konfigurationsfehler, kein transienter Datenfehler.
  • embed_backward nicht gepatcht: Die embed_backward()-Funktion hat dieselbe Schwachstelle (schreibender OOB-Zugriff). Laut Aufgabenstellung wird nur embed_lookup() adressiert. Die embed_backward()-Schwachstelle ist in weiteren HIGH-Findings zu behandeln.

Build-Verifikation

  • make train_large kompiliert ohne Fehler oder neue Warnungen.
  • Commit: 236e495 auf Branch fix/high-security-findings

HIGH-01 Code-Review Fixes (2026-03-02)

Zwei weitere Schwachstellen aus dem Code-Review zu HIGH-01 behoben.

Problem 1 (Critical): embed_backward OOB-Write / Heap Corruption

embed_backward() in training/stories_cpu_ops.h indexierte d_embed mit tokens[t] ohne Bereichspruefung — ein schreibender Out-of-Bounds-Zugriff (Heap Corruption), der schwerwiegender ist als der lesende OOB in embed_lookup().

Fix: Identischer VOCAB-Clamp wie in embed_lookup(), unmittelbar nach int tok = tokens[t]; in embed_backward():

if (tok >= VOCAB) { tok = 0; }  // HIGH-01: clamp invalid token -> position 0

Datei: training/stories_cpu_ops.h, Zeile 126

Problem 2 (Important): Resource Leak im Early-Exit von train_large.m

Der Early-Exit-Guard (n_tokens < SEQ + 1) gab return 1 zurueck, ohne zuvor den offenen File-Descriptor data_fd und die aktive mmap token_data freizugeben — ein FD- und Speicher-Leak.

Fix: munmap() + close() vor return 1 eingefuegt:

if (n_tokens < (size_t)SEQ + 1) {
    fprintf(stderr, "Token file too small: %zu tokens, need >%d\n", n_tokens, SEQ + 1);
    munmap(token_data, data_len);
    close(data_fd);
    return 1;
}

Datei: training/train_large.m, Zeilen 299304

Aenderungstabelle

Datei Zeile Aenderung
training/stories_cpu_ops.h 126 VOCAB-Clamp in embed_backward(): if (tok >= VOCAB) { tok = 0; }
training/train_large.m 301302 munmap(token_data, data_len) + close(data_fd) vor return 1

Build-Verifikation

  • make train_large kompiliert sauber ohne Fehler oder neue Warnungen.
  • Commit: ef1bb7d auf Branch fix/high-security-findings

Status HIGH-01

Alle vier Teilprobleme von HIGH-01 sind nun vollstaendig behoben:

  1. train_large.m n_tokens Underflow-Guard — Commit 236e495
  2. embed_lookup() OOB-Read Clamp — Commit 236e495
  3. embed_backward() OOB-Write Clamp — Commit ef1bb7d
  4. train_large.m Early-Exit Resource Leak — Commit ef1bb7d

HIGH-02 Fix (2026-03-02)

Branch fix/high-security-findings (fortgesetzt nach HIGH-01). HIGH-02 behoben.

Problem

Zwei zusammenhaengende Pfad-Validierungsprobleme in train_large.m:

  1. DATA_PATH wird mit open() geoeffnet ohne vorherige Aufloesung des Pfades. Wenn das Binary aus dem falschen Verzeichnis gestartet wird, gibt es eine kryptische "Cannot open" Fehlermeldung ohne Hinweis auf die Ursache.
  2. MODEL_PATH wird in load_pretrained() mit fopen() geoeffnet. Der aufgeloeste absolute Pfad wird nicht geloggt — erschwert Debugging bei falscher CWD. Beide Pfade nutzen relative ../../-Komponenten und sind ein Pfad-Traversal-Risiko, falls sie je konfigurierbar gemacht werden.

Aenderungen

Datei Zeile Aenderung
training/train_large.m 7 #include <limits.h> fuer PATH_MAX (verifiziert: 1024 auf macOS)
training/train_large.m 17 realpath() Audit-Log in load_pretrained() nach fopen() NULL-Check: gibt aufgeloesten absoluten Pfad aus
training/train_large.m 294302 realpath() Guard fuer DATA_PATH VOR open(): gibt klare Fehlermeldung mit Hinweis auf CWD aus und gibt return 1 (kein FD offen, kein Cleanup noetig)

Design-Entscheidungen

  • realpath() Guard vor open(): Das realpath()-Scheitern (Datei nicht gefunden) wird explizit vor dem open() abgefangen. Damit entfaellt der bisherige kryptische "Cannot open" Fehler bei falscher CWD.
  • return 1 ohne Cleanup: Der realpath()-Guard sitzt vor dem open()-Aufruf — es gibt noch keinen offenen FD oder gemappten Speicher, der freigegeben werden muesste.
  • Audit-Log mit printf (nicht fprintf stderr): Das Audit-Log in load_pretrained() ist diagnostische Ausgabe (kein Fehlerpfad), daher printf konsistent mit den anderen Ausgaben in der Funktion.
  • Scoped char rp[PATH_MAX] Bloecke: Beide realpath()-Aufrufe nutzen geklammerte Bloecke, um den Stack-Puffer lokal zu halten und Shadowing anderer Variablen zu vermeiden.

Build-Verifikation

  • make train_large kompiliert sauber ohne Fehler oder Warnungen.
  • Commit: 8929afc auf Branch fix/high-security-findings

Status HIGH-02

Alle Teilprobleme von HIGH-02 sind vollstaendig behoben:

  1. train_large.m realpath() Guard fuer DATA_PATH — Commit 8929afc
  2. train_large.m realpath() Audit-Log in load_pretrained() — Commit 8929afc

HIGH-03 Fix (2026-03-02)

Branch fix/high-security-findings (fortgesetzt nach HIGH-02). HIGH-03 behoben.

Problem

Zwei zusammenhaengende Schwachstellen im execl()-Prozessneustart-Block in train_large.m (Zeile 366):

  1. FD- und mmap-Leak across exec: data_fd (offener File-Descriptor) und token_data (aktive mmap-Region) wurden vor execl() nicht freigegeben. Nach execl() erbt der neue Prozess den FD und die mmap automatisch (POSIX: Dateideskriptoren bleiben ueber exec erhalten, sofern kein FD_CLOEXEC gesetzt), was zu Ressourcen-Leaks fuehrt.
  2. Unaufgeloester argv[0]: execl(argv[0], ...) nutzt den Pfad unveraendert so, wie das Programm aufgerufen wurde. Wenn der Start mit einem relativen Pfad (./train_large oder nur train_large ueber PATH) erfolgte, kann execl() fehlschlagen oder das falsche Binary finden, wenn sich das Arbeitsverzeichnis zwischen Start und Neustart geaendert hat.

Aenderungen

Datei Zeilen Aenderung
training/train_large.m 364372 realpath(argv[0], rp_exec) Guard vor execl(); munmap(token_data, data_len) + close(data_fd) vor execl(); execl(rp_exec, rp_exec, ...) nutzt aufgeloesten Pfad; printf-Ausgabe zeigt aufgeloesten Pfad

Design-Entscheidungen

  • realpath() vor Cleanup: realpath() scheitert nur, wenn das Binary nicht mehr existiert oder der Pfad unauflösbar ist — ein echter Konfigurationsfehler. In diesem Fall ist return 1 korrekt, ohne vorher munmap/close aufzurufen, da exit() resp. Prozessende die Ressourcen automatisch freigibt.
  • munmap vor close: Reihenfolge ist wichtig: munmap() gibt die Mapping-Region frei (dereferenziert den FD nicht mehr), danach kann der FD sicher geschlossen werden.
  • rp_exec statt argv[0] in beiden Positionen von execl(): Sowohl path- als auch argv[0]-Argument von execl() nutzen den aufgeloesten Pfad, damit /proc/self/exe (bzw. macOS-Aequivalent) konsistent bleibt.
  • char rp_exec[PATH_MAX]: Stack-allozierter Puffer, konsistent mit dem Muster aus HIGH-02. PATH_MAX ist via <limits.h> (seit HIGH-02) bereits im Build.

Build-Verifikation

  • make train_large kompiliert sauber ohne Fehler oder Warnungen.
  • Commit: b5c3cf9 auf Branch fix/high-security-findings

Status HIGH-03

Alle Teilprobleme von HIGH-03 sind vollstaendig behoben:

  1. train_large.m munmap() vor execl() — Commit b5c3cf9
  2. train_large.m close() vor execl() — Commit b5c3cf9
  3. train_large.m realpath() Guard fuer argv[0] — Commit b5c3cf9

Aktualisierter Status (nach HIGH-03)

Finding-Typ Anzahl Status
KRITISCH (CRIT-0104) 4 BEHOBEN
HOCH (HIGH-0105) 5 HIGH-01 BEHOBEN, HIGH-02 BEHOBEN, HIGH-03 BEHOBEN, HIGH-0405 Offen
MITTEL (MED-0106) 6 BEHOBEN
NIEDRIG (LOW-0104) 4 BEHOBEN