Ausliefern

Ein Lyx-Programm ist eine einzelne, statisch gelinkte Datei ohne Laufzeitumgebung. Das macht das Ausliefern einfach — und verschiebt die Fragen: nicht „welche Bibliotheken müssen mit?„, sondern „für welches Ziel, mit welchen Rechten, und wie beweise ich, dass es dasselbe Binary ist?“.

Cross-Compilation · Capabilities · lpm


Was herauskommt

lyxc app.lyx -o app
file app

ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked

Kein Interpreter, keine libc-Pflicht, kein Garbage Collector — die Datei läuft auf jedem Linux mit passender Architektur. Ein Hello-World liegt bei rund 100 KB, ein Programm mit Dateizugriff und Capabilities im Beispiel unten bei 206 KB.

Ausnahme: Wer extern fn … link „lib…so“ benutzt, verlangt diese Bibliothek auf dem Zielsystem. Das ist die einzige Abhängigkeit, die entstehen kann — und sie steht im Quelltext.


Für welches Ziel

lyxc app.lyx -o app                                        # Linux x86-64
lyxc app.lyx --target=win64 --format=pe -o app.exe          # Windows
lyxc app.lyx --target=arm64 -o app_arm64
lyxc app.lyx --target=riscv -o app_riscv
lyxc app.lyx --target=macosx64 --format=macho -o app_mac

Alle Ziele entstehen aus derselben Quelle, ohne Cross-Toolchain. Die vollständige Liste samt Einschränkungen steht im Cross-Compilation-Guide; für Oberflächen kommt die Backendwahl über den Include-Pfad dazu (Vega: portabel bauen).


Rechte festlegen: @capabilities

@capabilities([system.exit, system.memory.heap, fs.read])
import std.io;
import std.fs;
import std.alloc;

fn main(): int64 {
  var buf: int64 := alloc(256);
  var n: int64 := ReadFile("/etc/hostname", buf as pchar, 255);
  if (n > 0) { PrintLn("gelesen"); } else { PrintLn("nicht lesbar"); }
  free(buf, 256);
  return 0;
}

Aus der Deklaration entsteht ein seccomp-Filter. Das Audit im Build zeigt, was daraus wurde:

Explizite Capabilities:
  + W^X (RX-Code / RW-Daten getrennt — zwei PT_LOAD)
  + RELRO (kein GOT/PLT-Angriffsziel — statisches ELF)
  + seccomp (SECCOMP_RET_KILL_PROCESS, 121 Regeln)
Sicherheits-Score: 35/35

Und der Filter greift wirklich. Dasselbe Programm ohne fs.read in der Liste:

vor dem Lesen
Ungültiger Betriebssystemaufruf (Speicherabzug geschrieben), rc=159

Der Prozess stirbt beim nicht deklarierten Syscall. Für die Fehlersuche macht –seccomp-trap daraus ein SIGSYS mit Syscall-Nummer, statt stumm zu töten.

Ohne @capabilities gibt es keinen Filter — das Audit sagt dann Capability-Modell: NONE. Für ein ausgeliefertes Programm ist die Liste deshalb Pflichtprogramm, nicht Kür.


Reproduzierbar bauen

  • lyx.lock einchecken und mit lpm install –offline bauen — ein Bau, der aus dem Netz nachlädt, ist nicht wiederholbar.
  • Compilerversion festhalten (lyxc –version) — sie gehört ins Build-Protokoll wie die Quellversion.
  • Prüfsumme des Binaries bilden und mitliefern; bei gleicher Quelle und gleicher Compilerversion entsteht dasselbe Ergebnis.
  • Keine Zeitstempel oder Pfade ins Programm einbetten, wenn die Prüfsumme stabil bleiben soll.

Was mit ausgeliefert werden muss

Fall Mitliefern
Reines Rechenprogramm nur die Datei
extern fn … link „libfoo.so“ die Bibliothek muss auf dem Ziel vorhanden sein
Vega-Anwendung nichts zusätzlich — X11 bzw. Win32 stellt das System
Eigene Themes (.vtheme) oder Formulare (.lfm) die Dateien, relativ zum Arbeitsverzeichnis
Daten, die zur Laufzeit gelesen werden dieselbe Überlegung — und die passende Capability

Vor der Auslieferung

  1. lyxc –version notieren, lpm install –offline, Bau aus sauberem Stand.
  2. Testreihe laufen lassen (Testen).
  3. Audit ansehen: Steht seccomp dort? Ist der Score, was er sein soll?
  4. file auf das Ergebnis: richtiges Format, richtige Architektur, statically linked.
  5. Auf dem Zielsystem starten — nicht nur auf der Entwicklungsmaschine.
  6. Prüfsumme bilden und mit dem Build-Protokoll ablegen.

Fallstricke

  • Capabilities zu knapp. Der Fehler zeigt sich erst beim seltenen Pfad — Tests laufen unter demselben Filter wie die Auslieferung.
  • Capabilities zu weit. system.unsafe.* hebt den Sinn der Übung auf.
  • –target vergessen. Ein ELF auf einem Windows-Ziel fällt sofort auf, ein x86-64-Binary auf ARM erst beim Kunden.
  • Relative Pfade. Programme, die Dateien neben sich erwarten, brauchen eine feste Annahme über das Arbeitsverzeichnis.

Letzte Aktualisierung: 2026-08-19 — Beispiel, Audit-Ausgabe und die Wirkung des seccomp-Filters mit lyxc 1.1.3I nachgemessen.