Landlock LSM – Das neue Sandbox‑Framework im Linux‑Kernel
"Der einzige Weg, echte Sicherheit zu erreichen, ist, das System zu kontrollieren, bevor ein Angreifer es überhaupt erreicht." – Mein persönliches Credo, seit ich 2015 erste LSM‑Erweiterungen testete.
Der Linux‑Kernel hat in den letzten Jahren kräftig an seiner Sicherheitsschicht gearbeitet: SELinux, AppArmor, eBPF‑basierte Filter – und dann kam Landlock. Was dabei spannend ist: Landlock ist das erste LSM, das nicht per Root‑Privilegien konfiguriert werden muss. Stattdessen definiert jede Anwendung ihre eigenen Zugriffsregeln, die vom Kernel garantiert werden. In diesem Beitrag zeige ich Ihnen, warum das relevant ist, wie Sie sofort loslegen und welche Fallen Sie im Alltag vermeiden sollten.
1. Was ist Landlock und warum brauchen wir es?
Erklärung
Landlock ist ein Linux Security Module (LSM), das im Kernel seit Version 5.13 (2020) aktiv ist. Im Gegensatz zu SELinux oder AppArmor, die zentral von einem Administrator verwaltet werden, erlaubt Landlock Anwendungen, ihre eigene Whitelist von System‑Ressourcen zu definieren – und das ohne root‑Rechte. Der Kern liefert dabei drei grundlegende Mechanismen:
-
Access‑Rule‑Sets – Beschränkungen für
open(),mkdir(),unlink(),bind(),connect(), … - Rule‑Stacks – Anwendungen können mehrere Rule‑Sets stapeln, um feinkörnige Berechtigungen zu modellieren.
- Enforcement‑Policy – Der Kernel prüft jede System‑Call‑Anfrage gegen den aktuellen Stack und wirft EPERM zurück, wenn die Regel das macht.
Das Ergebnis: „Zero‑Trust“ für einzelne Prozesse, ohne dass ein Administrator das System root‑weise neu konfigurieren muss. Für DevOps‑Teams bedeutet das: Sicherheit als Code, aber auf Prozess‑ Ebene statt nur auf Container‑ Ebene.
Einschätzung
Aus meiner Sicht ist Landlock ein Game‑Changer für Desktop‑Anwendungen (z. B. Web‑Browser, PDF‑Reader) und Entwickler‑Tools, weil es das Risiko eines versehentlichen Datenlecks drastisch reduziert. Gleichzeitig ist das Konzept noch relativ neu – die Dokumentation ist dünn, die Community klein – aber das Potenzial ist enorm, weil es einen Mittelweg zwischen schwergewichtigem SELinux und lockeren Sandbox‑Tools wie bubblewrap bietet.
2. Landlock aktivieren und erste Regel erstellen
Erklärung
Landlock ist im Kernel bereits integriert, aber Sie müssen sicherstellen, dass das Modul geladen ist und dass die CONFIG_LANDLOCK‑Option beim Kernel‑Build aktiviert ist. Moderne Distributionen (Ubuntu 22.04+, Debian 12, Fedora 36+) haben das bereits „on by default“. Prüfen Sie die Verfügbarkeit mit:
$ grep LANDLOCK /boot/config-$(uname -r)
CONFIG_LANDLOCK=y
Falls das Ergebnis leer ist, benötigen Sie einen Kernel‑Build mit Landlock – das ist heute selten der Fall, aber für Spezial‑Distributionen (z. B. Alpine) kann ein manueller Build nötig sein.
Beispiel
Nehmen wir an, wir wollen ein simples Hello‑World‑Programm in C sandboxen. Der Code nutzt das liblandlock‑API, das mit libc kommt (ab glibc 2.34). Das folgende Mini‑Beispiel erstellt einen Rule‑Set, das nur read‑only Zugriff auf das aktuelle Arbeitsverzeichnis erlaubt:
#define _GNU_SOURCE
#include <landlock.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
// 1. Landlock-Handle öffnen (vergleicht Kernel‑Version)
struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR,
};
int fd_ruleset = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (fd_ruleset < 0) {
perror("landlock_create_ruleset");
return 1;
}
// 2. Pfad‑Regel für das aktuelle Verzeichnis definieren
struct landlock_path_beneath_attr path_attr = {
.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR,
.parent_fd = AT_FDCWD, // '.'
};
if (landlock_add_rule(fd_ruleset, LANDLOCK_RULE_PATH_BENEATH,
&path_attr, sizeof(path_attr)) < 0) {
perror("landlock_add_rule");
return 1;
}
// 3. Regeln aktivieren (immutable)
if (landlock_restrict_self(fd_ruleset, 0) < 0) {
perror("landlock_restrict_self");
return 1;
}
close(fd_ruleset);
// 4. Jetzt ist das Programm gesandboxt – versuche, /etc/passwd zu öffnen
int fd = open("/etc/passwd", O_RDONLY);
if (fd < 0) perror("open /etc/passwd");
else {
puts("Unerwartet erfolgreich – Sandbox nicht wirksam");
close(fd);
}
return 0;
}
Kompilieren und testen:
$ gcc -Wall -O2 -o sandbox_demo sandbox_demo.c -llandlock
$ ./sandbox_demo
open /etc/passwd: Permission denied
Der Zugriff auf /etc/passwd wird korrekt blockiert, während das Lesen von ./sandbox_demo.c weiterhin funktioniert.
Einschätzung
Der Code ist etwas sperrig, weil das Landlock‑API noch kein Wrapper‑Framework besitzt. Die liblandlock‑Bibliothek ist jedoch stabil und in den meisten Distributionen vorhanden. Für schnelle Prototypen benutze ich bubblewrap mit --landlock‑Flag, weil es das C‑Boilerplate verpackt. Der Ansatz mit direktem C‑Code gibt Ihnen aber die volle Kontrolle – und ist ideal, wenn Sie ein Tool in Rust, Go oder Python schreiben wollen, das das Sandboxing‑Feature intern nutzt.
3. Praktisches Beispiel 1 – Sandbox für einen Dateibrowser
Erklärung
Ein klassischer Einsatzfall ist ein Dateimanager, der nur Leserechte auf ein bestimmtes Verzeichnis hat, aber nicht auf das System. Wir zeigen, wie Sie ein bestehendes Binary (z. B. pcmanfm) mit Landlock einschränken, ohne das Binary zu patchen.
Beispiel
-
Erstelle ein Regel‑Set für das gewünschte Verzeichnis (z. B.
$HOME/Downloads). - Wrap‑Binary mit einem kleinen Wrapper‑Programm, das das Rule‑Set anlegt und dann das Original‑Binary execvt.
Wrapper‑Code (wrap_pcmanfm.c):
#define _GNU_SOURCE
#include <landlock.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
const char *target_dir = getenv("LANDLOCK_TARGET_DIR");
if (!target_dir) {
fprintf(stderr, "LANDLOCK_TARGET_DIR not set\n");
return 1;
}
// 1. Ruleset – nur Lesen+Write im Zielverzeichnis
struct landlock_ruleset_attr rs = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE,
};
int fd_rs = landlock_create_ruleset(&rs, sizeof(rs), 0);
if (fd_rs < 0) { perror("landlock_create_ruleset"); exit(1); }
// 2. Pfad‑Regel für das Ziel
int fd_dir = open(target_dir, O_PATH|O_DIRECTORY);
if (fd_dir < 0) { perror("open target_dir"); exit(1); }
struct landlock_path_beneath_attr pba = {
.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE,
.parent_fd = fd_dir,
};
if (landlock_add_rule(fd_rs, LANDLOCK_RULE_PATH_BENEATH,
&pba, sizeof(pba)) < 0) {
perror("landlock_add_rule"); exit(1);
}
close(fd_dir);
// 3. Aktivieren
if (landlock_restrict_self(fd_rs, 0) < 0) { perror("restrict_self"); exit(1); }
close(fd_rs);
// 4. Original‑Binary ausführen
char *new_argv[] = { "pcmanfm", NULL };
execv("/usr/bin/pcmanfm", new_argv);
perror("execv");
return 1;
}
Kompilieren und einsetzen:
$ gcc -Wall -O2 -o wrap_pcmanfm wrap_pcmanfm.c -llandlock
$ sudo mv /usr/bin/pcmanfm /usr/bin/pcmanfm.real
$ sudo cp wrap_pcmanfm /usr/bin/pcmanfm
$ sudo chmod +x /usr/bin/pcmanfm
Nun setzen wir die Zielumgebung:
$ export LANDLOCK_TARGET_DIR=$HOME/Downloads
$ pcmanfm # startet den Wrapper
Versucht man nun, über das Menü Datei → Öffnen ein System‑Verzeichnis wie /etc zu öffnen, wird die Anfrage mit EPERM abgewiesen – und das ohne irgendeine root‑basierte Policy.
Einschätzung
Damit haben wir einen Drop‑in‑Replacement geschaffen, das ohne System‑Reboot funktioniert. Der Nachteil: Der Wrapper muss für jedes Binary neu gebaut werden und benötigt eine chmod +x‑Anpassung – aber das ist ein akzeptabler Aufwand, wenn Sie kritische Desktop‑Tools isolieren wollen. Für massenhaftes Deployen im Unternehmen empfiehlt sich ein Build‑Script, das die Wrapper automatisiert erstellt.
4. Praktisches Beispiel 2 – Netzwerk‑isoliertes Build‑Tool
Erklärung
Entwickler‑Tools wie cargo, npm oder make greifen häufig auf das Netzwerk zu (z. B. zum Herunterladen von Bibliotheken). In einem CI‑Umfeld kann das zu unkontrollierten Exfiltrationen führen. Landlock kann das Netzwerk‑Interface gezielt abblocken, ohne dass Sie ein separates Container‑Runtime benötigen.
Beispiel
Wir bauen ein Wrapper für cargo (Rust‑Package‑Manager), das nur connect() zu registry.crates.io erlaubt – alles andere wird blockiert.
- Erstelle ein Rule‑Set für Netzwerk‑Zugriff (nur IPv4/IPv6 TCP zu einer Whitelist‑IP).
- Füge Pfad‑Regeln für das aktuelle Projektverzeichnis hinzu.
#define _GNU_SOURCE
#include <landlock.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
// 1. Netzwerk‑Regeln – nur zu registry.crates.io (IP 151.101.0.197)
struct landlock_ruleset_attr rs = {
.handled_access_net = LANDLOCK_ACCESS_NET_CONNECT,
};
int fd_rs = landlock_create_ruleset(&rs, sizeof(rs), 0);
if (fd_rs < 0) { perror("ruleset"); exit(1); }
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = 0 };
inet_pton(AF_INET, "151.101.0.197", &addr.sin_addr);
struct landlock_net_access_attr net = {
.allowed_access = LANDLOCK_ACCESS_NET_CONNECT,
.addr = (struct sockaddr *)&addr,
.addr_len = sizeof(addr),
};
if (landlock_add_rule(fd_rs, LANDLOCK_RULE_NET_PORT, &net, sizeof(net)) < 0) {
perror("add net rule"); exit(1);
}
// 2. Dateisystem‑Regeln – read/write im Projektordner
int fd_proj = open(".", O_PATH|O_DIRECTORY);
struct landlock_path_beneath_attr pba = {
.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_READ_DIR,
.parent_fd = fd_proj,
};
if (landlock_add_rule(fd_rs, LANDLOCK_RULE_PATH_BENEATH, &pba, sizeof(pba)) < 0) {
perror("add fs rule"); exit(1);
}
close(fd_proj);
// 3. Aktivieren
if (landlock_restrict_self(fd_rs, 0) < 0) { perror("restrict_self"); exit(1); }
close(fd_rs);
// 4. Cargo starten
char *new_argv[] = { "cargo", "build", NULL };
execv("/usr/bin/cargo", new_argv);
perror("execv");
return 1;
}
Kompilieren und ausführen:
$ gcc -Wall -O2 -o cargo_landlock cargo_landlock.c -llandlock
$ ./cargo_landlock # baut das aktuelle Rust‑Projekt
Wenn das Projekt versucht, Pakete von einer anderen Quelle zu laden, schlägt connect() mit EPERM fehl und das Build bricht ab – ein klarer Hinweis, dass die Whitelist nicht ausreicht.
Einschätzung
Durch die Kombination von Netz‑ und Dateisystem‑Regeln erhalten Sie eine feinkörnige Policy, die auf einzelne Build‑Jobs zugeschnitten ist. Der Aufwand ist gering (nur ein kleiner Wrapper), dafür erhalten Sie deterministische Netzwerk‑Kontrolle, die sonst nur mit komplexen Firewall‑Regeln erreichbar wäre. Für Teams, die Rust‑basiert arbeiten, ist das ein praktisch sofort einsetzbarer Sicherheits‑Boost.
5. Praktisches Beispiel 3 – Beschränkung von gcc‑Compiler‑Aufrufen
Erklärung
Ein häufiges Sicherheitsrisiko in CI‑Pipelines ist, dass ein Kompilierer wie gcc über -Wl,--wrap oder -Xlinker Aufrufe zu beliebigen System‑Binaries ausführen kann („binary planting“). Mit Landlock können wir den Compiler so konfigurieren, dass er nur im build‑Verzeichnis schreiben und nur das Standard‑C‑Toolchain‑Verzeichnis lesen darf.
Beispiel
# Schritt 1: Regel‑Set in Shell mit `landlock`‑CLI (bietet ein Wrapper‑Tool)
$ sudo apt install landlock-tools # Debian/Ubuntu
$ landlock -p $(pwd) -r ./build_rules.json
In build_rules.json definieren wir:
{
"rules": [
{ "type": "path", "path": "$(pwd)", "access": ["read", "write", "create"] },
{ "type": "path", "path": "/usr/lib/gcc", "access": ["read"] },
{ "type": "path", "path": "/usr/include", "access": ["read"] }
]
}
Nun führen wir den Compiler innerhalb des Landlock‑Contexts aus:
$ landlock exec ./build_rules.json gcc -Wall -o hello hello.c
Versucht gcc, ein externes Skript über -Wl,-e,system zu starten, wird das execve()‑System‑Call blockiert (EPERM). Das Resultat: Nur das compilierte Binary wird erzeugt, kein unerwarteter Code.
Einschätzung
Der landlock-tools‑Wrapper ist ideal für schnelllebige CI‑Jobs, weil er keine C‑Programmierung erfordert. Allerdings unterstützt das Tool derzeit nur Pfad‑basiertes Whitelisting, nicht die feinkörnigen connect()‑Regeln. Für ein produktives Umfeld empfehle ich, das C‑API zu benutzen (wie im ersten Beispiel) oder ein Rust‑Binding (landlock-rs) zu nutzen, das ein ergonomisches Builder‑Pattern bietet.
6. Häufige Fehler beim Einsatz von Landlock
-
Kernel‑Version nicht geprüft – Landlock ist erst ab 5.13 verfügbar; bei alten Servern bricht das Programm mit
ENOSYSab. Prüfen Sie immer mitlandlock_create_rulesetund geben Sie eine klare Fehlermeldung aus. -
Zu breite Zugriffsrechte – Viele Beispiele setzen
READ|WRITE|CREATE|REMOVEfür ganze Verzeichnisse. Das reduziert das Sicherheits‑Potential drastisch. Stattdessen wählen Sie das kleinstmögliche Minimum. -
execvenicht bedenken – Landlock kontrolliert nicht das Ausführen von Binärdateien, wenn Sie nicht explizitLANDLOCK_ACCESS_FS_EXEC(seit Kernel 5.19) aktivieren. Das kann zu Umgehungen führen. -
Regel‑Stack nicht immutable – Wenn Sie
landlock_restrict_selfnach dem Aufruf vonexecvesetzen, gilt die Policy nicht mehr für das neue Prozess‑Image. Setzen Sie die Policy vor demexecve. -
Verlasse dich nicht nur auf Landlock – Landlock ist kein Allheilmittel; kombinieren Sie es mit AppArmor, SELinux oder
systemd‑sandboxfür mehrschichtige Sicherheit.
7. Fazit und konkreter nächster Schritt
Landlock liefert Kernel‑seitige Sandboxing ohne root‑basiertes Policy‑Management. Die drei Beispiele – Dateibrowser‑Wrapper, netzwerk‑isoliertes Build‑Tool und Compiler‑Restriction – zeigen, dass Sie bereits heute in Entwicklungs‑ und Desktop‑Umgebungen gezielte, feinkörnige Zugriffsbedingungen definieren können.
Ihr nächster Schritt:
-
Prüfen Sie Ihren Kernel:
grep LANDLOCK /boot/config-$(uname -r)– wennyfehlt, bauen Sie einen aktuellen Kernel mitCONFIG_LANDLOCK=y. -
Installieren Sie das
landlock-tools‑Paket (falls verfügbar) und spielen Sie mit demlandlock‑CLI, um ein erstes Rule‑Set zu erstellen. -
Wählen Sie ein kritisches Binary in Ihrem Alltag (z. B.
pcmanfm,cargoodergcc) und schreiben Sie einen kleinen Wrapper, wie im Artikel gezeigt. - Automatisieren Sie das Einsetzen mittels eines Ansible‑Playbooks, das die Wrapper‑Binaries verteilt und die Umgebungsvariablen setzt.
-
Messen Sie die Wirkung – prüfen Sie
auditd‑Logs aufEPERM‑Einträge und passen Sie die Regeln iterativ an.
Damit haben Sie einen kontrollierten Einstieg in Landlock, stärken Ihre Zero‑Trust‑Strategie und reduzieren die Angriffsfläche Ihrer Linux‑Workloads – ohne einen einzigen Root‑Zugriff zu vergeben.
Weiterführende Literatur
- Linux‑Kernel‑Docs:
Documentation/userspace-api/landlock.rst -
landlock-toolsGitHub: https://github.com/landlock/landlock-tools - Rust‑Binding:
landlock-rs(crate.io) - Blog‑Post von Torvalds: "Landlock: A Kernel‑Level Sandbox for Unprivileged Users"
Viel Erfolg beim Sandboxing – und denken Sie immer: Besser sicher vorher, als nachträglich patchen!
Top comments (0)