====== 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