====== std.security_ext — Linux Capabilities & prctl ====== ''import std.security_ext;'' Zwei Subsysteme: * **prctl**: Prozessbezogene Kernel-Parameter steuern (Name, Dumpability, No-New-Privs, seccomp) * **Capabilities**: POSIX-Capabilities lesen und setzen (''capget''/''capset'', Kernel-Version 3) Syscalls: ''prctl(157)'', ''arch_prctl(158)'', ''capget(125)'', ''capset(126)''. → [[lyx_-_programmiersprache:units:ns|std.ns]] · [[lyx_-_programmiersprache:units:sysadmin|std.sysadmin]] · [[lyx_-_programmiersprache:units:debug|std.debug]] ---- ===== prctl-Konstanten ===== ^ Konstante ^ Wert ^ Beschreibung ^ | ''PR_SET_PDEATHSIG'' | 1 | Signal bei Elterntod setzen | | ''PR_SET_DUMPABLE'' | 4 | Core-Dump erlauben (1) oder sperren (0) | | ''PR_GET_DUMPABLE'' | 3 | Core-Dump-Status lesen | | ''PR_SET_NAME'' | 15 | Prozessname setzen (max. 15 Zeichen + NUL) | | ''PR_GET_NAME'' | 16 | Prozessname lesen (16-Byte-Puffer) | | ''PR_SET_NO_NEW_PRIVS'' | 38 | Keine neuen Rechte via setuid/caps (Einweg!) | | ''PR_GET_NO_NEW_PRIVS'' | 39 | no_new_privs-Status lesen | | ''PR_SET_SECCOMP'' | 22 | seccomp-Filter setzen | ===== arch_prctl-Konstanten (x86-64) ===== ^ Konstante ^ Wert ^ Beschreibung ^ | ''ARCH_SET_GS'' | 4097 | GS-Basisregister setzen (TLS) | | ''ARCH_SET_FS'' | 4098 | FS-Basisregister setzen (Thread-Local) | | ''ARCH_GET_FS'' | 4099 | FS-Basisregister lesen | | ''ARCH_GET_GS'' | 4100 | GS-Basisregister lesen | ---- ===== Capability-Konstanten ===== ''CAP_BUF_SIZE'': 32 Bytes (8 Bytes Header + 2 × 12 Bytes Data). ==== Puffer-Offsets ==== ^ Konstante ^ Offset ^ Inhalt ^ | ''CAP_EFF_0'' | 8 | Effektive Capabilities 0..31 | | ''CAP_PRM_0'' | 12 | Erlaubte Capabilities 0..31 | | ''CAP_INH_0'' | 16 | Vererbbare Capabilities 0..31 | | ''CAP_EFF_1'' | 20 | Effektive Capabilities 32..63 | | ''CAP_PRM_1'' | 24 | Erlaubte Capabilities 32..63 | | ''CAP_INH_1'' | 28 | Vererbbare Capabilities 32..63 | ==== Capability-Nummern ==== ^ Konstante ^ Nr ^ Beschreibung ^ | ''CAP_CHOWN'' | 0 | chown auf beliebige Dateien | | ''CAP_DAC_OVERRIDE'' | 1 | Dateizugriffsrechte ignorieren | | ''CAP_DAC_READ_SEARCH'' | 2 | Lesezugriff ohne Rechteprüfung | | ''CAP_FOWNER'' | 3 | Dateieigentümer-Checks überspringen | | ''CAP_KILL'' | 5 | Signale an beliebige Prozesse senden | | ''CAP_SETUID'' | 7 | setuid() auf beliebige UID | | ''CAP_SETGID'' | 6 | setgid() auf beliebige GID | | ''CAP_SETPCAP'' | 8 | Capabilities weitergeben | | ''CAP_NET_BIND_SERVICE'' | 10 | Ports < 1024 binden | | ''CAP_NET_RAW'' | 13 | Raw-Sockets | | ''CAP_SYS_RAWIO'' | 17 | I/O-Port-Zugriff | | ''CAP_SYS_PTRACE'' | 19 | ptrace beliebiger Prozesse | | ''CAP_SYS_ADMIN'' | 21 | Viele Admin-Operationen | ---- ===== prctl-Funktionen ===== ^ Funktion ^ Signatur ^ Beschreibung ^ | ''ProcessSetName'' | ''(name: pchar): int64'' | Setzt Prozessname (max. 15 Zeichen, sichtbar in ps/top) | | ''ProcessGetName'' | ''(outBuf: int64): int64'' | Liest Prozessname in Puffer (≥ 16 Bytes) | | ''ProcessSetDumpable'' | ''(val: int64): int64'' | Core-Dumps erlauben (1) oder sperren (0) | | ''ProcessGetDumpable'' | ''(): int64'' | 1 wenn Core-Dumps erlaubt | | ''ProcessSetNoNewPrivs'' | ''(): int64'' | Setzt no_new_privs-Flag (Einweg — nicht rückgängig machbar!) | | ''ProcessGetNoNewPrivs'' | ''(): int64'' | 1 wenn no_new_privs gesetzt | ===== arch_prctl-Funktionen ===== ^ Funktion ^ Signatur ^ Beschreibung ^ | ''ArchGetFs'' | ''(): int64'' | Liest FS-Basisregister (TLS-Zeiger des aktuellen Threads) | | ''ArchGetGs'' | ''(): int64'' | Liest GS-Basisregister | ===== Capability-Funktionen ===== ^ Funktion ^ Signatur ^ Beschreibung ^ | ''CapGet'' | ''(buf: int64): int64'' | Liest Capabilities in ''CAP_BUF_SIZE''-Puffer | | ''CapSet'' | ''(buf: int64): int64'' | Setzt Capabilities aus Puffer | | ''CapDrop'' | ''(capNum: int64): int64'' | Entfernt Capability aus effective und permitted | | ''CapIsSet'' | ''(capNum: int64): int64'' | Prüft ob Capability in effective gesetzt ist | ---- ===== Verwendung ===== ==== Prozessname setzen ==== import std.security_ext; fn main(): int64 { ProcessSetName("myworker"); // Sichtbar in: ps aux, /proc/self/comm, top return 0; } ==== no_new_privs für Sandboxing ==== import std.security_ext; fn Sandbox(): int64 { // Verhindert setuid-Eskalation nach diesem Punkt — EINWEG! var r: int64 := ProcessSetNoNewPrivs(); if (r < 0) { return r; } // Ab hier: keine neuen Privileges via execve(setuid), Capabilities o.ä. return 0; } ==== Capabilities prüfen ==== import std.security_ext; import std.alloc; fn CheckCap(): int64 { var r: int64 := CapIsSet(CAP_NET_BIND_SERVICE); if (r = 1) { // Port < 1024 binden erlaubt return 0; } return -1; // Keine Berechtigung } ==== Einzelne Capability entfernen ==== import std.security_ext; fn DropRawSockets(): int64 { // CAP_NET_RAW entfernen nach der Initialisierung return CapDrop(CAP_NET_RAW); } ==== Alle Capabilities lesen ==== import std.security_ext; import std.alloc; fn PrintCaps(): void { var buf: int64 := alloc(CAP_BUF_SIZE); var r: int64 := CapGet(buf); if (r < 0) { free(buf, CAP_BUF_SIZE); return; } var eff0: int64 := peek32(buf + CAP_EFF_0); // Capabilities 0..31 als Bitfeld var eff1: int64 := peek32(buf + CAP_EFF_1); // Capabilities 32..63 als Bitfeld free(buf, CAP_BUF_SIZE); } ---- ===== Hinweise ===== * **no_new_privs ist irreversibel**: ''ProcessSetNoNewPrivs'' kann nicht zurückgenommen werden — nur vor dem Sandbox-Eintritt setzen. * **CapDrop vs. CapSet**: ''CapDrop'' ist atomisch für eine einzelne Capability. Für mehrere: ''CapGet'' → Bits löschen → ''CapSet''. * **Capability-Vererbung**: ''inheritable''-Capabilities werden nur dann an execve()-Kinder vererbt wenn auch das neue Programm sie in seinem erlaubten Set hat (Dateicapability). * **Core-Dump-Sicherheit**: ''ProcessSetDumpable(0)'' verhindert dass ein Core-Dump Schlüsselmaterial aus dem Speicher preisgibt. Für Security-sensitive Prozesse empfohlen. * **ArchGetFs**: TLS-Implementierungen in Lyx können den FS-Zeiger des aktuellen Threads damit auslesen — für low-level Thread-Local-Storage ohne libc. ---- Letzte Aktualisierung: 2026-06-06