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).

std.ns · std.sysadmin · 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