
Niedrigstufiges, unprivilegiertes Sandboxing-Werkzeug, das von Flatpak und ähnlichen Projekten verwendet wird.
Viele Container-Runtime-Tools wie systemd-nspawn, docker,
usw. konzentrieren sich darauf, Systemadministratoren und
Orchestrierungswerkzeugen (z. B. Kubernetes) eine Infrastruktur zum Ausführen von Containern bereitzustellen.
Diese Tools sind nicht dafür geeignet, unprivilegierten Benutzern überlassen zu werden, da es trivial ist, einen solchen Zugriff in eine voll privilegierte Root-Shell auf dem Host zu verwandeln.
Es gibt ein Feature im Linux-Kernel namens User-Namespaces, das es unprivilegierten Benutzern ermöglicht, Container-Features zu nutzen. Bubblewrap verwendet diese, um die Sandbox zu bauen, sodass jeder Benutzer das Tool verwenden kann.
Historisch gesehen unterstützte bubblewrap außerdem einen Setuid-Modus für Systeme, auf denen unprivilegierte User-Namespaces nicht unterstützt wurden. Dieser wurde jedoch entfernt.
Der ursprüngliche bubblewrap-Code entstand vor den User-Namespaces – er erbt Code von xdg-app helper, welcher wiederum entfernt von linux-user-chroot abstammt.
Die Maintainer dieses Tools glauben, dass es – selbst wenn es in Kombination mit typischer, auf dieser Distribution installierter Software verwendet wird – keine Privilegienerweiterung (Privilege Escalation) ermöglicht. Es könnte jedoch die Fähigkeit eines angemeldeten Benutzers erhöhen, Denial-of-Service-Angriffe durchzuführen.
Insbesondere verwendet bubblewrap PR_SET_NO_NEW_PRIVS, um
Setuid-Binaries abzuschalten, was der traditionelle Weg ist, aus Dingen wie
Chroots herauszukommen.
bubblewrap ist ein Werkzeug zum Erstellen von Sandbox-Umgebungen. bubblewrap ist keine vollständige, fertige Sandbox mit einer bestimmten Sicherheitsrichtlinie.
Einige Anwendungsfälle von bubblewrap wünschen eine Sicherheitsgrenze zwischen der Sandbox und dem echten System; andere Anwendungsfälle möchten die Möglichkeit, das Layout des Dateisystems für Prozesse innerhalb der Sandbox zu ändern, zielen jedoch nicht darauf ab, eine Sicherheitsgrenze zu sein. Daher wird das Schutzniveau zwischen den sandboxierten Prozessen und dem Hostsystem vollständig durch die Argumente bestimmt, die an bubblewrap übergeben werden.
Welches Programm auch immer die Befehlszeilenargumente für bubblewrap erstellt (oft ein größeres Framework wie Flatpak, libgnome-desktop, sandwine oder ein Ad-hoc-Skript), ist dafür verantwortlich, sein eigenes Sicherheitsmodell zu definieren und geeignete bubblewrap-Befehlszeilenargumente zu wählen, um dieses Sicherheitsmodell umzusetzen.
Einige Aspekte der Sandbox-Sicherheit, die besondere Sorgfalt erfordern, werden im Abschnitt Einschränkungen unten beschrieben.
Dieses Programm kann von allen Container-Tools gemeinsam genutzt werden, die einen Betrieb ohne Root-Rechte durchführen, wie zum Beispiel:
Wir würden außerdem gerne sehen, dass dies in Kubernetes/OpenShift-Clustern verfügbar ist. Die Möglichkeit für unprivilegierte Benutzer, Container-Features zu nutzen, würde es erheblich erleichtern, interaktive Debugging-Szenarien und Ähnliches durchzuführen.
bubblewrap ist in den Paketquellen der meisten Linux-Distributionen verfügbar und kann von dort installiert werden.
Falls du bubblewrap aus dem Quellcode erstellen musst, kannst du dies mit meson tun:
meson _builddir
meson compile -C _builddir
meson test -C _builddir
meson install -C _builddir
bubblewrap funktioniert, indem es einen neuen, vollständig leeren Mount-Namespace erstellt, in dem das Root-Verzeichnis auf einem tmpfs liegt, das vom Host aus unsichtbar ist und automatisch bereinigt wird, wenn der letzte Prozess endet. Du kannst dann über Befehlszeilenoptionen das Root-Dateisystem sowie die Prozessumgebung und den Befehl konstruieren, der im Namespace ausgeführt werden soll.
Im Quellcode gibt es ein größeres Demo-Skript,
aber hier ist eine abgespeckte Version, die eine neue Shell
unter Wiederverwendung des Host-/usr ausführt.
bwrap \
--ro-bind /usr /usr \
--symlink usr/lib64 /lib64 \
--proc /proc \
--dev /dev \
--unshare-pid \
--new-session \
bash
Dies ist ein unvollständiges Beispiel, aber zur Veranschaulichung
nützlich. Häufiger möchtest du, anstatt einen Container mit dem Dateisystembaum des Hosts
zu erstellen, eine Chroot anvisieren. Dort hast du den Symlink
lib64 -> usr/lib64 möglicherweise bereits im Ziel-Rootfs erstellt, anstatt
ihn im tmpfs anzulegen.
Das Ziel von bubblewrap ist es, eine Anwendung in einer Sandbox auszuführen, in der sie eingeschränkten Zugriff auf Teile des Betriebssystems oder auf Benutzerdaten wie das Home-Verzeichnis hat.
bubblewrap erstellt immer einen neuen Mount-Namespace, und der Benutzer kann genau festlegen,
welche Teile des Dateisystems in der Sandbox sichtbar sein sollen.
Alle solche Verzeichnisse, die du angibst, werden standardmäßig nodev gemountet und können schreibgeschützt gemacht werden.
Zusätzlich kannst du diese Kernel-Features verwenden:
User-Namespaces (CLONE_NEWUSER): Dies verbirgt vor der Sandbox alles außer der aktuellen uid und gid. Du kannst auch ändern, welchen Wert uid/gid in der Sandbox haben sollen.
IPC-Namespaces (CLONE_NEWIPC): Die Sandbox erhält eine eigene Kopie aller verschiedenen Formen von IPCs, wie SysV Shared Memory und Semaphore.
PID-Namespaces (CLONE_NEWPID): Die Sandbox sieht keine Prozesse außerhalb der Sandbox. Zusätzlich wird bubblewrap einen trivialen pid1 innerhalb deines Containers ausführen, um die Anforderungen des Einsammelns von Kindprozessen (Reaping) in der Sandbox zu erfüllen. Dies vermeidet das, was heute als Docker-Pid-1-Problem bekannt ist.
Netzwerk-Namespaces (CLONE_NEWNET): Die Sandbox sieht das Netzwerk nicht. Stattdessen hat sie einen eigenen Netzwerk-Namespace mit nur einem Loopback-Gerät.
UTS-Namespace (CLONE_NEWUTS): Die Sandbox hat einen eigenen Hostnamen.
Seccomp-Filter: Du kannst Seccomp-Filter übergeben, die einschränken, welche Syscalls in der Sandbox ausgeführt werden können. Weitere Informationen findest du unter Seccomp.
Wie im Abschnitt Sandbox-Sicherheit oben erwähnt, wird das Schutzniveau zwischen den sandboxierten Prozessen und dem Hostsystem vollständig durch die an bubblewrap übergebenen Argumente bestimmt. Einige Aspekte, die besondere Sorgfalt erfordern, werden hier genannt.
Wenn du TIOCSTI-Befehle nicht mithilfe von Seccomp-Filtern herausfilterst,
wird das Argument --new-session benötigt, um sich vor der Ausführung von Befehlen
außerhalb der Sandbox zu schützen
(siehe CVE-2017-5226).
Alles, was in die Sandbox gemountet wird, kann potenziell zur Erweiterung von Rechten verwendet werden. Wenn du beispielsweise einen D-Bus-Socket in die Sandbox bindest, kann er verwendet werden, um Befehle über systemd auszuführen. Du kannst xdg-dbus-proxy verwenden, um die D-Bus-Kommunikation zu filtern.
Einige Anwendungen setzen eigene Sandbox-Mechanismen ein, und diese können durch die von bubblewraps Sandboxing auferlegten Einschränkungen begrenzt werden. Zum Beispiel einige Webbrowser, die ihre Kindprozesse über Seccomp so konfigurieren, dass sie keinen Zugriff auf das Dateisystem haben. Wenn du die Syscalls einschränkst und den Seccomp-Syscall nicht erlaubst, kann ein Browser diese Einschränkungen nicht anwenden. Wenn diese Regeln außerdem in eine Datei kompiliert wurden, die in der Sandbox nicht verfügbar ist, kann der Browser diese Regeln nicht aus dieser Datei laden und diese Einschränkungen nicht anwenden.
Firejail ähnelt Flatpak, bevor bubblewrap ausgegliedert wurde, da es ein Setuid-Werkzeug mit vielen desktop-spezifischen Sandbox-Funktionen kombiniert. Zum Beispiel kennt Firejail Pulseaudio, während bubblewrap das nicht tut.
Die bubblewrap-Autoren glauben, dass es viel einfacher ist, ein kleines Setuid-Programm zu prüfen und Funktionen wie die Pulseaudio-Filterung als unprivilegierten Prozess zu behalten, wie es jetzt in Flatpak geschieht.
Außerdem hält @cgwalters den Versuch,
Dateipfade auf eine Whitelist zu setzen,
für eine schlechte Idee angesichts der unzähligen Möglichkeiten, wie Benutzer Pfade manipulieren können,
und der unzähligen Arten, wie Systemadministratoren ein System konfigurieren
können. Der bubblewrap-Ansatz besteht darin, nur einige wenige spezifische
Linux-Capabilities wie CAP_SYS_ADMIN zu behalten, aber immer auf das
Dateisystem als aufrufende uid zuzugreifen. Dies schließt
TOCTTOU-Angriffe und Ähnliches
vollständig aus.
Sandstorm.io benötigt unprivilegierte User-Namespaces, um seine Sandbox einzurichten, obwohl es leicht angepasst werden könnte, um auch im Setuid-Modus zu arbeiten. @cgwalters glaubt, dass ihr Code ziemlich gut ist, aber es könnte dennoch sinnvoll sein, sich auf bubblewrap zu vereinheitlichen. @kentonv (von Sandstorm) hingegen findet, dass dies zwar im Prinzip sinnvoll ist, die Umstellungskosten jedoch die praktischen Vorteile derzeit überwiegen. Diese Entscheidung könnte in Zukunft überdacht werden, wird aber heute nicht aktiv verfolgt.
runC arbeitet derzeit an der
Unterstützung von rootless containers,
ohne dass während der Installation von
runC (mithilfe unprivilegierter User-Namespaces anstelle von setuid),
der Erstellung und Verwaltung von Containern setuid oder andere Privilegien benötigt werden. Der Standardmodus der
Verwendung von runC ähnelt jedoch systemd nspawn
insofern, als es sich um ein Werkzeug handelt, das von root aufgerufen werden soll.
Die bubblewrap-Autoren glauben, dass runc und systemd-nspawn nicht dafür entworfen wurden, setuid-fähig gemacht zu werden, und weit davon entfernt sind, einen solchen Modus zu unterstützen. Mit rootless containers wird runC jedoch in der Lage sein, bestimmte Anwendungsfälle zu erfüllen, die bubblewrap unterstützt (mit dem zusätzlichen Vorteil, eine standardisierte und vollständige OCI-Runtime zu sein).
binctr ist nur ein Wrapper für runC und erbt daher alle seine Design-Abwägungen.
Der Name bubblewrap wurde gewählt, um auszudrücken, dass dieses Tool als Elternprozess der Anwendung läuft (es umhüllt sie also gewissermaßen) und eine schützende Schicht (die Sandbox) um sie herum erstellt.

(Bubblewrap-Katze von dancing_stupidity)