Zum Inhalt

Linux Kernel-Sandboxing: Capabilities, Seccomp & Systemd-Isolation

Erstellt: 10.11.2026 Aktualisiert: 10.11.2026

Management Summary: Traditionell operierte UNIX nach dem Alles-oder-Nichts-Prinzip: Ein Prozess lief entweder als unprivilegierter Standardbenutzer oder besaß als Superuser root unumschränkte Kontrolle über Hardware, Speicher und Kernel. POSIX Capabilities zerlegen diese monolithische Root-Macht in knapp 40 atomare Privilegien und machen gefährliche SUID-Binaries überflüssig. Gepaart mit Seccomp (Secure Computing Mode), das über BPF-Filter unerwünschte Systemaufrufe (Syscalls) noch vor dem Erreichen des Kernels blockiert, und deklarativen systemd-Sicherheitsdirektiven lassen sich moderne Linux-Dienste so isolieren, dass selbst ein erfolgreicher Remote-Code-Execution-Exploit wirkungslos im Sandkasten verpufft. Dieser Leitfaden führt durch die Capability-Architektur (Permitted, Effective, Ambient), Seccomp-Filterung, schlüsselfertige systemd-Sandboxing-Templates sowie die automatisierte Sicherheitsbewertung mit systemd-analyze security.

  • POSIX Capabilities Architektur


    Dekonstruktion des monolithischen Root: Die 5 Capability-Sets (Permitted, Inheritable, Effective, Bounding, Ambient) und Vererbungsregeln.

  • Rechtevergabe mit setcap & getcap


    Granulare Rechte für Daemons ohne Root: Binden an privilegierte Ports (CAP_NET_BIND_SERVICE) und Gefahren von SUID-Bit-Altlasten.

  • Seccomp BPF-Syscall-Filterung


    Drastische Reduktion der Kernel-Angriffsfläche durch Whitelisting erlaubter Systemaufrufe (prctl, BPF-Filter und SECCOMP_RET_KILL).

  • Deklarative Systemd-Härtung


    Service-Units atomar abriegeln mit ProtectSystem=strict, ProtectHome=yes, NoNewPrivileges=yes und MemoryDenyWriteExecute=yes.

  • Audits mit systemd-analyze security


    Automatisierte Sicherheitsbewertung aller Systemd-Services, Schwachstellen-Scoring (0.0 bis 10.0) und Härtungs-Workflows.

  • Denial-Forensik & Troubleshooting


    Blockierte Systemaufrufe lokalisieren mit journalctl -u, Dekodierung von audit: type=1326 via ausyscall und Debugging von SIGSYS.


1. POSIX Capabilities Architektur & Das Ende des Allmächtigen Root

Unter klassischem UNIX existierte eine strikte binäre Trennung: Prozesse mit UID 0 durften alles, Prozesse mit UID > 0 durften fast nichts. Um einem Webserver das Binden an Port 80 oder 443 zu erlauben, musste er historisch als root gestartet werden – mit der Folge, dass ein Pufferüberlauf im Webserver zur vollständigen Übernahme des Wirtsrechners führte.

POSIX Capabilities zerlegen die Superuser-Rechte in distinkte Einheiten:

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    Root_Monolith["Monolithischer root (UID 0)<br/>(Vollzugriff auf gesamte Hardware)"] ==> Split["POSIX Capabilities Subsystem"]
    Split --> Cap_Net["CAP_NET_BIND_SERVICE<br/>(Ports < 1024 binden)"]
    Split --> Cap_Raw["CAP_NET_RAW<br/>(ICMP / Raw Sockets senden)"]
    Split --> Cap_Admin["CAP_SYS_ADMIN<br/>(Mount / BPF / Namespaces)"]
    Split --> Cap_Trace["CAP_SYS_PTRACE<br/>(Prozess-Debugging / Tracing)"]

Die 5 Capability-Sets eines Prozesses

Jeder Linux-Thread verwaltet intern fünf Bitmap-Masken für Capabilities:

  1. Permitted (CapPrm): Die Obergrenze der Capabilities, die der Thread anfordern oder aktivieren darf.
  2. Effective (CapEff): Die Capabilities, die der Thread im aktuellen Moment tatsächlich aktiv ausübt (wird bei Berechtigungsprüfungen im Kernel abgefragt).
  3. Inheritable (CapInh): Capabilities, die über einen execve()-Aufruf hinweg an Kindprozesse vererbt werden können (erfordert entsprechende Datei-Capabilities).
  4. Bounding Set (CapBnd): Die systemweite Obergrenze. Capabilities, die nicht im Bounding Set liegen, können niemals (auch nicht durch Root) erlangt werden.
  5. Ambient Set (CapAmb): Moderne Erweiterung (ab Kernel 4.3): Capabilities, die unprivilegierte Prozesse ohne Datei-Capabilities direkt an unprivilegierte Kindprozesse vererben können.

Die gefährlichsten Capabilities (Vermeiden auf Produktions-Daemons!)

Vermeide Pseudo-Root Capabilities

Bestimmte Capabilities verleihen Angreifern de facto die Kontrolle über das Gesamtsystem:

  • CAP_SYS_ADMIN: Die gefährlichste Capability überhaupt. Erlaubt Mount-Operationen, BPF-Injektionen und das Verlassen von Containern.
  • CAP_SYS_PTRACE: Erlaubt das Auslesen und Manipulieren des Speichers beliebiger anderer Prozesse (Passwortdiebstahl).
  • CAP_DAC_OVERRIDE: Hebelt die gesamten Dateiberechtigungen (chmod/chown) im System aus.

2. Capabilities in der Praxis: Granulare Rechtevergabe mit setcap & getcap

Anstatt Binärdateien das brandgefährliche SUID-Bit (chmod u+s) zu verleihen, weisen wir ihnen über erweiterte Dateiattribute (security.capability) gezielt nur die benötigten Privilegien zu.

1. Bestehende Capabilities inspizieren mit getcap

# Zeige bestehende Capabilities von System-Binaries an
getcap /usr/bin/ping
# Ausgabe: /usr/bin/ping cap_net_raw+ep

Das Flag +ep bedeutet: Die Capability wird in das Effective- und das Permitted-Set geladen.

2. Privilegierte Ports ohne Root binden mit setcap

Muss eine eigene Go-, Node.js- oder C-Anwendung an Port 80 oder 443 lauschen, benötigt sie ausschließlich CAP_NET_BIND_SERVICE:

# Erteile der Binärdatei das Recht, privilegierte Ports unterhalb 1024 zu binden
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/web-daemon

# Verifiziere die Zuweisung
getcap /usr/local/bin/web-daemon

# Zuweisung bei Bedarf rückstandslos entfernen (-r)
sudo setcap -r /usr/local/bin/web-daemon

Nun kann /usr/local/bin/web-daemon als unprivilegierter Benutzer www-data gestartet werden und sich trotzdem an Port 443 binden!

Niemals Capabilities auf Skript-Interpretern setzen

Führe niemals setcap auf Skript-Interpretern wie /usr/bin/python3, /usr/bin/perl oder /usr/bin/node aus! Jeder Benutzer auf dem System könnte sonst ein Python-Skript schreiben und die vergebenen Capabilities unkontrolliert für eigene Zwecke missbrauchen.


3. Seccomp (Secure Computing Mode) & BPF-Syscall-Filterung

Der Linux-Kernel stellt über 450 Systemaufrufe (Syscalls) bereit – von einfachen Operationen wie read() und write() bis hin zu komplexen Kernel-Schnittstellen wie bpf(), ptrace(), reboot() oder mount(). Nahezu alle Kernel-Sicherheitslücken (Kernel-Exploits zur lokalen Rechteausweitung) verbergen sich in selten genutzten, hochkomplexen Syscalls.

Ein typischer Microservice oder Webserver benötigt in seinem gesamten Lebenszyklus weniger als 40 bis 50 dieser Syscalls. Seccomp schrumpft die Kernel-Angriffsfläche radikal zusammen:

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    App["Anwendung / Microservice"] ==> SysCall["System Call Abfrage<br/>(z. B. reboot, ptrace, bpf)"]
    SysCall --> BPF_Filter{"Seccomp cBPF-Filter<br/>(Prüft Syscall-Nummer)"}
    BPF_Filter -->|"In Whitelist enthalten"| Kernel_Exec["Syscall wird im Kernel ausgeführt"]
    BPF_Filter -->|"Nicht in Whitelist"| Action{"Definierte Filter-Aktion"}
    Action -->|"SECCOMP_RET_KILL"| Kill["Prozess wird sofort terminiert<br/>(SIGSYS / Exit Code 159)"]
    Action -->|"SECCOMP_RET_ERRNO"| Errno["Aufruf wird abgewiesen<br/>(Return: EPERM)"]

Die Return-Aktionen von Seccomp

  • SECCOMP_RET_ALLOW: Der Syscall ist legitim und wird normal ausgeführt.
  • SECCOMP_RET_ERRNO: Der Syscall wird blockiert. Die Anwendung erhält einen Fehlercode (typischerweise EPERM), läuft aber weiter.
  • SECCOMP_RET_LOG: Der Syscall wird ausgeführt, aber im Audit-Log dokumentiert (ideal zum Erstellen von Whitelists).
  • SECCOMP_RET_KILL_PROCESS: Der gesamte Prozess wird vom Kernel sofort und unaufhaltbar per SIGSYS terminiert.

4. Deklaratives Systemd Service Sandboxing

In der modernen Enterprise-Praxis müssen Administratoren Seccomp und Capabilities nicht mühsam in C programmieren. systemd bietet mächtige, deklarative Direktiven, die beim Prozess-Start atomar über den Linux-Kernel erzwungen werden.

Erstelle ein Drop-In für deinen Dienst (z. B. /etc/systemd/system/api-service.service.d/override.conf):

# /etc/systemd/system/api-service.service.d/override.conf
[Service]
# ==============================================================================
# Enterprise Systemd Service Hardening & Sandboxing
# ==============================================================================

# 1. PRIVILEGIEN-ESKALATION VERHINDERN
# Verhindert, dass der Dienst oder seine Kindprozesse über SUID-Bits neue Rechte erlangen
NoNewPrivileges=yes

# 2. DATEISYSTEM-ISOLATION
# /usr, /boot und /etc auf striktes Read-Only setzen
ProtectSystem=strict
# Privates Verzeichnis für /tmp und /var/tmp erzwingen (kein Zugriff auf System-/tmp)
PrivateTmp=yes
# Benutzerverzeichnisse (/home, /root) unsichtbar machen
ProtectHome=yes
# Zugriff auf physische Hardwaregeräte (/dev/sda etc.) verbieten
PrivateDevices=yes
# Explizite Lese-/Schreibpfade für den Dienst definieren
ReadWritePaths=/var/lib/api-service /var/log/api-service

# 3. KERNEL- & HARDWARE-SCHUTZ
# Kernel-Variablen (/proc/sys, /sys) auf Read-Only setzen
ProtectKernelTunables=yes
# Verhindert das Nachladen von Kernel-Modulen
ProtectKernelModules=yes
# Verbietet Manipulationen an Control Groups
ProtectControlGroups=yes
# W^X Memory Protection: Verbietet das Erzeugen beschreibbarer und ausführbarer Speicherseiten
# Neutralisiert Pufferüberläufe und Shellcodes im RAM!
MemoryDenyWriteExecute=yes
# Verhindert das Ändern des Hostnamens oder der Systemuhrzeit
ProtectHostname=yes
ProtectClock=yes

# 4. CAPABILITIES BESCHRÄNKEN
# Entzieht alle Capabilities bis auf das Binden an Port 443
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

# 5. SECCOMP SYSCALL-FILTER
# Erlaube die Standard-Gruppe für Hintergrunddienste
SystemCallFilter=@system-service
# Blockiere explizit privilegierte Aufrufe und Kernel-Modul-Management
SystemCallFilter=~@privileged @resources @module @obsolete
# Setze die Architektur auf nativen 64-Bit-Modus (verhindert 32-Bit-Syscall-Bypasses)
SystemCallArchitectures=native

Konfiguration aktivieren

# Systemd-Konfiguration neu einlesen
sudo systemctl daemon-reload

# Dienst neu starten
sudo systemctl restart api-service.service

5. Automatisierte Sicherheits-Audits mit systemd-analyze security

Systemd verfügt über ein integriertes Bewertungs-Framework, das jeden installierten Dienst anhand von über 60 Sicherheitsflags analysiert und eine Gesamtnote berechnet.

1. Sicherheits-Übersicht aller laufenden Daemons anzeigen

# Zeige den Sicherheits-Score aller Services (0.0 = extrem sicher, 10.0 = unsicher)
systemd-analyze security

2. Detaillierte Schwachstellen-Analyse für einen Dienst

# Zeigt jedes einzelne Flag, dessen Gewichtung und Einsparpotenzial
systemd-analyze security api-service.service

Vorher / Nachher Vergleich in der Produktion

Zustand Exposure Score Einstufung Analyse
Standard (Default) 9.6 UNSAFE Dienst läuft ungeschützt: Voller Zugriff auf /home, Ptrace erlaubt, keine Syscall-Filter.
Gehärtet (Drop-In) 1.4 OK Strikte Isolation: Read-Only-Dateisystem, Seccomp aktiv, Capabilities minimiert.

6. Denial-Forensik & Deep Troubleshooting Runbook

Wird ein Dienst zu strikt isoliert, kann er abstürzen oder Systemaufrufe verweigert bekommen. Dieses Runbook führt durch die zielgenaue Entstörung.

1. Blockierte Seccomp-Syscalls identifizieren

Stürzt ein Dienst mit SIGSYS oder der Meldung Bad system call ab, hat Seccomp zugeschlagen:

# 1. Suche nach Seccomp-Audit-Ereignissen im Journal
journalctl -u api-service.service -e --grep="audit"

# 2. Suche im Kernel-Ringpuffer nach Audit-Type 1326 (SECCOMP)
sudo dmesg -T | grep "audit: type=1326"

Ein typischer Kernel-Eintrag sieht wie folgt aus: type=1326 ... syscall=311 compat=0 ... comm="api-daemon"

2. Syscall-Nummer in Funktionsnamen übersetzen

Die Zahl hinter syscall= gibt die Kernel-ID des Systemaufrufs an:

# Installiere die Audit-Hilfswerkzeuge
sudo apt-get install auditd libseccomp-tools

# Übersetze die Syscall-Nummer (z. B. 311) in den Funktionsnamen
ausyscall 311
# Ausgabe: process_vm_readv

Nun kann die benötigte Funktion gezielt im SystemCallFilter des Service-Drop-Ins freigegeben werden: SystemCallFilter=process_vm_readv

Enterprise Troubleshooting-Tabelle

Fehlersymptom Ursache Lösung
Exit-Code 159 (SIGSYS) Seccomp hat einen verbotenen Syscall blockiert. Syscall-ID via dmesg ermitteln, mit ausyscall decodieren und in SystemCallFilter= aufnehmen.
Permission denied (Bind) Dienst darf Port < 1024 nicht öffnen. AmbientCapabilities=CAP_NET_BIND_SERVICE im Drop-In ergänzen.
Service kann Logs nicht schreiben ProtectSystem=strict sperrt Schreibrechte. ReadWritePaths=/var/log/mein-dienst im Drop-In definieren.
Fehler bei temporären Dateien PrivateTmp=yes trennt /tmp. Bei IPC über /tmp stattdessen Unix-Domain-Sockets unter /run/ nutzen.

Mit POSIX Capabilities und Seccomp-Sandboxing ist die Anwendungs- und Kernel-Schnittstelle vollständig versiegelt: Selbst bei gravierenden Sicherheitslücken in Daemons kann kein Angreifer aus dem zugewiesenen Korsett ausbrechen.