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

27 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 BEHOBEN
MITTEL (MED-0106) 6 BEHOBEN
NIEDRIG (LOW-0104) 4 BEHOBEN

Alle 19 Sicherheitsbefunde vollständig behoben (Stand: 2026-03-02)

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

HIGH-04 Fix (2026-03-02)

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

Problem

Alle malloc() und calloc() Aufrufe in den 5 Alloc-Helperfunktionen von stories_config.h sowie in den direkten Allokationen in train_large.m prueften den Rueckgabewert nicht. Ein NULL-Pointer (OOM) fuehlte sofort zu einem Segfault — statt zu einer verstaendlichen Fehlermeldung. Bei Multi-Stunden-Trainingslaeufen ist OOM ein fataler, nicht behebbarer Zustand.

Aenderungen

Datei Zeile Aenderung
training/stories_config.h 145155 xmf(n) und xcf(n) static inline Helfer hinzugefuegt: rufen abort() mit diagnostischer Stderr-Ausgabe bei OOM auf
training/stories_config.h 156 adam_alloc(): calloc(n,4)xcf(n) (2 Stellen)
training/stories_config.h 161165 layer_weights_alloc(): 8x malloc(X*4)xmf(X)
training/stories_config.h 184192 layer_acts_alloc(): 13x malloc(X*4)xmf(X) (mit (size_t) Cast fuer SEQ*DIM/HIDDEN)
training/stories_config.h 200204 layer_grads_alloc(): 9x calloc(X,4)xcf(X)
training/train_large.m 238241 rms_final, embed, grms_final, gembed: 4 direkte Allokationen → xmf/xcf
training/train_large.m 320335, 495, 518565, 583 27 per-Iteration Temporaer-Puffer: alle malloc(SEQ*X*4)xmf((size_t)SEQ*X) und calloc(SEQ*X,4)xcf((size_t)SEQ*X)

Gesamt: 31 Call-Sites ersetzt.

Design-Entscheidungen

  • abort() statt return NULL: OOM waehrend eines laufenden Trainings bedeutet ein systemweites Problem. Mit NULL weiterzumachen wuerde Gewichte still korrumpieren — viel schlimmer als ein sauberer Abbruch.
  • sizeof(float) statt hartkodiertem 4: Klarheitsgewinn; auf allen unterstuetzten Plattformen identisches Verhalten.
  • (size_t) Cast bei SEQ*DIM/HIDDEN: Verhindert einen potentiellen 32-bit Integer-Overflow bei grossen Sequenzlaengen (auch wenn SEQ/DIM momentan in int-Range liegen).
  • Helfer-Namen xmf/xcf: Kurz und konsistent mit dem tersem Stil des Projekts. xmf = "xmalloc float", xcf = "xcalloc float".
  • layer_adam_alloc() nicht direkt geaendert: Ruft adam_alloc() auf, das nun intern xcf() verwendet — transitiv bereits gesichert.

Build-Verifikation

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

Status HIGH-04

Alle Call-Sites vollstaendig behoben:

  1. stories_config.h adam_alloc() — 2 xcf()-Stellen
  2. stories_config.h layer_weights_alloc() — 8 xmf()-Stellen
  3. stories_config.h layer_acts_alloc() — 13 xmf()-Stellen
  4. stories_config.h layer_grads_alloc() — 9 xcf()-Stellen
  5. train_large.m direkte Allokationen — 4 Stellen (embed, rms_final, grads)
  6. train_large.m per-Iteration Temporaer-Puffer — 27 Stellen

Aktualisierter Status (nach HIGH-04)

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

HIGH-04 Nachtrag: stories_cpu_ops.h (2026-03-02)

Branch fix/high-security-findings (fortgesetzt nach HIGH-04 Code-Review). Code-Review identifizierte 7 weitere rohe malloc/calloc Call-Sites in stories_cpu_ops.h, die beim initialen HIGH-04-Fix nicht erfasst wurden.

Problem

stories_cpu_ops.h enthielt 7 rohe malloc/calloc-Aufrufe ohne NULL-Check. stories_config.h ist in stories_cpu_ops.h via #include eingebunden, sodass xmf()/xcf() bereits verfuegbar waren — die Call-Sites wurden aber initial uebersehen.

Aenderungen

Datei Zeile Vorher Nachher
training/stories_cpu_ops.h 8 (float*)malloc(S*4) xmf(S)
training/stories_cpu_ops.h 9 (float*)calloc(S, sizeof(float)) xcf(S)
training/stories_cpu_ops.h 25 (float*)malloc(S*4) xmf(S)
training/stories_cpu_ops.h 26 (float*)calloc(S, sizeof(float)) xcf(S)
training/stories_cpu_ops.h 33 (float*)malloc(S*4) xmf(S)
training/stories_cpu_ops.h 35 (float*)calloc(S, sizeof(float)) xcf(S)
training/stories_cpu_ops.h 74 (float*)malloc(S * V * 4) xmf((size_t)S * V)

Funktionen betroffen: rmsnorm(), rmsnorm_bwd(), cross_entropy_loss().

Design-Entscheidungen

  • xmf(S) statt malloc(S*4): Semantisch aequivalent (n Floats), aber OOM-sicher durch abort() in xmf(). Kein Schreibfehler-Risiko durch hartkodierte *4.
  • xcf(S) statt calloc(S, sizeof(float)): Identisch — xcf(n) ruft intern calloc(n, sizeof(float)) auf. Zero-Initialisierung bleibt erhalten.
  • (size_t)S * V in cross_entropy_loss: S * V koennte bei int-Multiplikation ueberlaufen (z.B. S=512, V=32000 = 16.384.000 Floats = 62.5 MB — noch in int-Range, aber Praezedenzfall gesetzt). (size_t)-Cast links vor der Multiplikation erzwingt 64-bit-Arithmetik.
  • free() Aufrufe unveraendert: free() funktioniert korrekt auf Pointern, die von xmf()/xcf() zurueckgegeben wurden, da diese intern malloc/calloc aufrufen.

Build-Verifikation

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

Aktualisierter Status HIGH-04

Alle Call-Sites vollstaendig behoben (inkl. Nachtrag):

  1. stories_config.h Alloc-Helfer — 32 Stellen (Commit 78666fc)
  2. train_large.m direkte + per-Iteration Allokationen — 31 Stellen (Commit 78666fc)
  3. stories_cpu_ops.h rmsnorm(), rmsnorm_bwd(), cross_entropy_loss() — 7 Stellen (Commit ce2d68c)

HIGH-04 Nachtrag 2: stories_io.h, ane_runtime.h, ane_mil_gen.h (2026-03-02)

Branch fix/high-security-findings (fortgesetzt nach HIGH-04 Nachtrag 1). Code-Review identifizierte 9 weitere rohe calloc/malloc Call-Sites in 3 weiteren Dateien.

Problem

Nach dem Fix von stories_config.h, train_large.m und stories_cpu_ops.h verblieben 9 ungeschuetzte Allokationen:

  • stories_io.h: 1x calloc(1, sizeof(Kern)) ohne NULL-Check — sofortiger NULL-Deref auf k->model = ...
  • ane_runtime.h: 5x rohe Allokationen fuer ANEKernel, inputBytes, outputBytes, ioInputs, ioOutputs — die ersten 4 memcpy/Array-Zugriffe wuerden bei OOM Heap korrumpieren
  • ane_mil_gen.h: 3x calloc(total, 1) fuer uint8_t *buf ohne NULL-Check — sofortiger NULL-Deref auf buf[0] = 0x01

Aenderungen

Datei Zeile Allokation Guard
training/stories_io.h 142 calloc(1, sizeof(Kern)) if (!k) { fprintf(stderr, "OOM: calloc(Kern)\n"); abort(); }
training/ane_runtime.h 113 calloc(1, sizeof(ANEKernel)) if (!k) { fprintf(stderr, "OOM: calloc(ANEKernel)\n"); abort(); }
training/ane_runtime.h 119 malloc(nInputs * sizeof(size_t)) if (!k->inputBytes) { fprintf(stderr, "OOM: malloc(inputBytes)\n"); abort(); }
training/ane_runtime.h 121 malloc(nOutputs * sizeof(size_t)) if (!k->outputBytes) { fprintf(stderr, "OOM: malloc(outputBytes)\n"); abort(); }
training/ane_runtime.h 127 malloc(nInputs * sizeof(IOSurfaceRef)) if (!k->ioInputs) { fprintf(stderr, "OOM: malloc(ioInputs)\n"); abort(); }
training/ane_runtime.h 129 malloc(nOutputs * sizeof(IOSurfaceRef)) if (!k->ioOutputs) { fprintf(stderr, "OOM: malloc(ioOutputs)\n"); abort(); }
training/ane_mil_gen.h 27 calloc(total, 1) in mil_build_weight_blob if (!buf) { fprintf(stderr, "OOM: calloc(%lu)\n", ...); abort(); }
training/ane_mil_gen.h 160 calloc(total, 1) in mil_build_qkv_weight_blob if (!buf) { fprintf(stderr, "OOM: calloc(%lu)\n", ...); abort(); }
training/ane_mil_gen.h 183 calloc(total, 1) in mil_build_ffn_up_weight_blob if (!buf) { fprintf(stderr, "OOM: calloc(%lu)\n", ...); abort(); }

Design-Entscheidungen

  • Inline NULL-Guards statt xmf/xcf: Die betroffenen Allokationen sind nicht vom Typ float*. Die Helfer xmf()/xcf() sind spezifisch fuer Float-Arrays (malloc(n * sizeof(float))). Fuer Kern*, ANEKernel*, size_t*, IOSurfaceRef* und uint8_t* sind inline Guards die korrekte Wahl.
  • abort() statt return NULL: Konsistent mit dem restlichen HIGH-04-Ansatz. OOM im Kontext eines Multi-Stunden-Trainings ist ein nicht behebbarer Systemfehler — ein sauberer Abbruch mit Diagnoseausgabe ist besser als stilles Speicherkorrumpieren.
  • (unsigned long)total Cast in ane_mil_gen.h: NSUInteger ist auf macOS ein unsigned long. Der Cast verhindert -Wformat-Warnungen beim %lu-Format-Specifier.

Build-Verifikation

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

Aktualisierter Status HIGH-04 (vollstaendig)

Alle Call-Sites vollstaendig behoben (alle Nachwuchsfunde eingeschlossen):

  1. stories_config.h Alloc-Helfer — 32 Stellen (Commit 78666fc)
  2. train_large.m direkte + per-Iteration Allokationen — 31 Stellen (Commit 78666fc)
  3. stories_cpu_ops.h rmsnorm(), rmsnorm_bwd(), cross_entropy_loss() — 7 Stellen (Commit ce2d68c)
  4. stories_io.h, ane_runtime.h, ane_mil_gen.h — 9 Stellen (Commit 87014bd)
  5. stories_mil.h get_mask_blob() Maske — 1 Stelle (Commit 42eae54)

Aktualisierter Status (nach HIGH-04 vollstaendig)

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

HIGH-05 Fix (2026-03-02)

Branch fix/high-security-findings (fortgesetzt nach HIGH-04 vollstaendig). HIGH-05 behoben.

Problem

ane_eval(Kern *k) in stories_io.h war void und ignorierte den BOOL-Rueckgabewert von evaluateWithQoS:options:request:error:. Bei ANE-Ausfuehrungsfehlern (Hardware-Fehler, Modellfehler) lief das Training still mit veralteten/inkorrekten Gradienten weiter.

Aenderungen

Datei Zeile Aenderung
training/stories_io.h 164 static void ane_eval(Kern *k)static bool ane_eval(Kern *k) (HIGH-05 Kommentar); BOOL ok = Rueckgabe-Capture; NSError *e bereits vorhanden (wird nun ausgewertet); if (!ok) fprintf(stderr, ...) Fehlerausgabe; return (bool)ok
training/train_large.m 411 bool step_ok = true; vor der Akkumulations-for-Schleife eingefuegt (HIGH-05 Kommentar)
training/train_large.m 437, 450, 513, 553, 556, 580 Alle 6 ane_eval(...) Call-Sites → step_ok &= ane_eval(...)
training/train_large.m 636639 if (!step_ok) Guard nach dem Akkumulations-Loop: fprintf(stderr, ...) + continue (springt zur naechsten while-Iteration, ueberspringt Adam-Update)

Design-Entscheidungen

  • &= Operator: Propagiert false korrekt durch alle Iterationen — wenn auch nur ein einziges ane_eval() ueber alle Schichten und Akkumulationsschritte scheitert, wird step_ok dauerhaft false.
  • continue zielt auf while (step < total_steps): Die if (!step_ok) Pruefung liegt ausserhalb der inneren for (a=0..ACCUM_STEPS) Schleife, aber innerhalb der aeusseren while. Ein continue springt daher korrekt zum naechsten while-Durchlauf (naechste Kompilierungsrunde), nicht zum naechsten Akkumulationsschritt.
  • NSError *e = nil war bereits vorhanden: Der e-Parameter war schon in der alten Implementierung als nil initialisiert und an objc_msgSend uebergeben — der einzige fehlende Teil war das Auswerten des Rueckgabewerts und der NSError-Beschreibung.
  • Kein abort() bei Fehler: Im Gegensatz zu OOM-Fehlern (HIGH-04) ist ein transienter ANE-Fehler potenziell behebbar. Das Training ueberspringt den Schritt und faehrt mit dem naechsten fort — degradiert den Fortschritt, stoppt ihn aber nicht.
  • step_ok ausserhalb der Layer-Schleife: Eine einzelne bool-Variable reicht — die &=-Verkettung ueber alle Schichten und alle Akkumulationsschritte akkumuliert korrekt.

Build-Verifikation

  • make train_large kompiliert sauber ohne Fehler oder Warnungen (Compiler-Aufruf: xcrun clang -O2 -Wall -Wno-deprecated-declarations -fobjc-arc ...).
  • Commit: f78b943 auf Branch fix/high-security-findings

Status HIGH-05

Alle Teilprobleme vollstaendig behoben:

  1. stories_io.h ane_eval() von void zu bool geaendert — Commit f78b943
  2. train_large.m step_ok Deklaration vor Akkumulationsschleife — Commit f78b943
  3. train_large.m 6 Call-Sites mit step_ok &= — Commit f78b943
  4. train_large.m Adam-Update-Skip bei !step_ok — Commit f78b943

Abschlusstatus: Alle HIGH-Findings behoben (2026-03-02)

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

Alle 19 Sicherheitsbefunde vollstaendig behoben. Branch: fix/high-security-findings auf manni07/ANE.