Wie führe ich Chroot mit Linux-Namespaces durch?

14

Nachdem ich über Linux-Namespaces gelesen hatte, hatte ich den Eindruck, dass sie neben vielen anderen Funktionen eine Alternative zu chroot darstellen. Zum Beispiel in diesem Artikel :

Andere Verwendungen [von Namespaces] umfassen [...] die Isolierung eines Prozesses in der Art von chroot () für einen Teil der einzelnen Verzeichnishierarchie.

Wenn ich jedoch den Mount-Namespace klone, z. B. mit dem folgenden Befehl, wird immer noch der gesamte ursprüngliche Stammbaum angezeigt.

unshare --mount -- /bin/bash

Ich verstehe, dass ich jetzt in der Lage bin, zusätzliche Ladevorgänge in dem neuen Namespace durchzuführen, die nicht mit dem ursprünglichen Namespace geteilt werden, und dies stellt eine Isolierung dar, aber es ist immer noch derselbe Stamm, z. B. /etcist immer noch derselbe für beide Namespaces. Muss ich noch chrootdie Wurzel wechseln oder gibt es eine Alternative?

Ich hatte erwartet, dass diese Frage eine Antwort liefern würde, aber die Antwort verwendet nur chrootwieder.

EDIT # 1

Es gab einen jetzt gelöschten Kommentar, der dies erwähnte pivot_root. Da dies tatsächlich Teil von ist linux/fs/namespace.c, ist es tatsächlich Teil der Namespaces-Implementierung. Dies deutet darauf hin, dass das Ändern des Stammverzeichnisses nur mit unshareund mountnicht möglich ist, Namespaces jedoch eine eigene, cleverere Version von chroot. Trotzdem verstehe ich diesen Ansatz nicht als grundlegend anders chroot, auch nicht nach dem Lesen des Quellcodes (im Sinne von z. B. Sicherheit oder besserer Isolation).

EDIT # 2

Dies ist kein Duplikat dieser Frage . Nach der Ausführung aller Befehle aus der Antwort habe ich separate /tmp/tmp.vyM9IwnKuY (oder ähnlich), aber das Stammverzeichnis ist immer noch das gleiche!

Koalo
quelle
In Bezug auf den Unterschied zwischen pivot_rootund chroot: Ich habe mir die Docker-Quellen angesehen und festgestellt, dass diese Mechanismen , wenn sie nicht ausgeführt werden können pivot_root, chrootauf mindestens ähnliche Funktionen für Containerisierungszwecke zurückgreifen.
Danila Kiver

Antworten:

13

Wenn Sie einen Mount-Namespace eingeben, bevor chrootSie einen einrichten, können Sie vermeiden, dass der Host-Namespace mit zusätzlichen Mounts überladen wird, z /proc. Sie können chrootin einem Mount-Namespace einen netten und einfachen Hack verwenden.

Ich denke, es gibt Vorteile beim Verstehen pivot_root, aber es hat eine gewisse Lernkurve. Die Dokumentation erklärt nicht alles ... obwohl es in man 8 pivot_root(für den Shell-Befehl) ein Anwendungsbeispiel gibt . man 2 pivot_root(für den Systemaufruf) könnte klarer sein, wenn es dasselbe tut und ein Beispiel-C-Programm enthält.

So verwenden Sie pivot_root

Unmittelbar nach der Eingabe des Mount-Namespace benötigen Sie ebenfalls mount --make-rslave /oder ein gleichwertiges Element. Andernfalls werden alle Mount-Änderungen auf die Mounts im ursprünglichen Namespace übertragen, einschließlich der pivot_root. Das willst du nicht :).

Wenn Sie den unshare --mountBefehl verwendet haben, beachten Sie, dass die Anwendung mount --make-rprivatestandardmäßig dokumentiert ist . AFAICS Dies ist eine schlechte Standardeinstellung, und Sie möchten dies nicht im Produktionscode. ejectZum Beispiel würde es an diesem Punkt aufhören , an einer eingebundenen DVD oder USB im Host-Namespace zu arbeiten. Die DVD oder der USB-Stick verbleiben im privaten Bereitstellungsbaum und der Kernel lässt Sie die DVD nicht auswerfen.

Danach können Sie zB das von /procIhnen verwendete Verzeichnis einhängen . So wie du es für tun würdest chroot.

Anders als bei der Verwendung chrootist es pivot_rooterforderlich, dass Ihr neues Root-Dateisystem ein Mount-Punkt ist. Wenn es nicht ein bereits ist, können Sie diese erfüllen , indem einfach eine bind montieren: mount --rbind new_root new_root.

Verwenden Sie pivot_root- und dann umountdas alte Root-Dateisystem mit der Option -l/ MNT_DETACH. ( Du brauchst nicht umount -R, was länger dauern kann. )

Technisch gesehen muss die Verwendung im pivot_rootAllgemeinen auch die Verwendung umfassen chroot. es ist nicht "entweder-oder".

Per man 2 pivot_root, wird es nur als Swapping die Wurzel des Mount - Namensraum definiert. Es ist nicht definiert, auf welches physische Verzeichnis der Prozessstamm verweist. Oder das aktuelle Arbeitsverzeichnis ( /proc/self/cwd). Es kommt vor, dass dies der Fall ist , aber dies ist ein Hack, um Kernel-Threads zu behandeln. Die Manpage sagt, dass sich dies in Zukunft ändern könnte.

Normalerweise möchten Sie diese Sequenz:

chdir(new_root);            // cd new_root
pivot_root(".", put_old);   // pivot_root . put_old
chroot(".");                // chroot .

Die Position der chrootin dieser Sequenz ist noch ein weiteres subtiles Detail . Obwohl pivot_rootes darum geht, den Mount-Namespace neu zu ordnen, scheint der Kernel-Code das zu verschiebende Root-Dateisystem zu finden, indem er sich das pro Prozess definierte Root-Verzeichnis ansieht chroot.

Warum soll ich pivot_root verwenden?

Grundsätzlich ist es sinnvoll, pivot_rootfür Sicherheit und Isolation zu verwenden. Ich denke gerne über die Theorie der leistungsbasierten Sicherheit nach . Sie übergeben eine Liste der benötigten Ressourcen, und der Prozess kann auf keine anderen Ressourcen zugreifen. In diesem Fall handelt es sich um die Dateisysteme, die an einen Mount-Namespace übergeben wurden. Diese Idee gilt allgemein für die Linux-Funktion "Namespaces", obwohl ich sie wahrscheinlich nicht sehr gut ausdrücken kann.

chrootLegt nur den Prozessstamm fest, der Prozess verweist jedoch weiterhin auf den vollständigen Mount-Namespace. Wenn ein Prozess die Berechtigung zum Ausführen behält chroot, kann er den Namespace des Dateisystems sichern. Wie in man 2 chroot"Der Superuser kann aus einem 'Chroot-Gefängnis' entkommen, bis ..." ausgeführt.

Ein anderer nachdenklicher Weg zum Rückgängigmachen chrootist nsenter --mount=/proc/self/ns/mnt. Dies ist vielleicht ein stärkeres Argument für das Prinzip. nsenter/ setns()lädt den Prozessstamm notwendigerweise vom Stamm des Mount-Namespace neu ... obwohl die Tatsache, dass dies funktioniert, wenn sich die beiden auf unterschiedliche physische Verzeichnisse beziehen, als Kernel-Fehler angesehen werden kann. (Technischer Hinweis: Es können mehrere Dateisysteme im Stammverzeichnis setns()übereinander montiert sein ; verwendet das oberste, zuletzt montierte Dateisystem ).

Dies zeigt einen Vorteil der Kombination eines Mount-Namespaces mit einem "PID-Namespace". Wenn Sie sich in einem PID-Namespace befinden, können Sie den Mount-Namespace eines unbeschränkten Prozesses nicht eingeben. Außerdem wird verhindert, dass Sie die Wurzel eines nicht abgeschlossenen Prozesses eingeben ( /proc/$PID/root). Und natürlich verhindert ein PID-Namespace auch, dass Sie einen Prozess beenden, der sich außerhalb befindet :-).

sourcejedi
quelle
Das hilft schon sehr. Trotzdem bin ich mir nicht sicher, was Sie mit "dem Mount oben im Namespace" meinen. Und gibt es eine Möglichkeit, dies zu ändern?
Koalo
1
@koalo bearbeitet :-). ps ich weiß nicht warum du fstab für "make-rslave" / "make-rprivate" brauchst. systemds switch-root.c macht genau dasmount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL)
sourcejedi
1
@koalo und dann die Linux-Kernel-Entwickler verwendeten "rootfs", als sie eine vierte Sache nannten :-P. unix.stackexchange.com/questions/152029/…
sourcejedi
1
Diese Antwort und andere durch @sourcejedi haben außerordentlich hilfreich gewesen, hätte ich gefragt „pivot_root: können sie nicht umount put_old so beschäftigt“ , aber die Antwort war schon hier, faul sein als Kraft wird nicht funktionierenumount -l ./oldroot
earcam
1
Vor kurzem gab es ein Update der Hilfeseite pivot_root (2) mit mehreren Erläuterungen , und es enthält jetzt ein Beispielprogramm. Vielleicht möchten Sie Ihre Antwort aktualisieren, um dies widerzuspiegeln? In der Manpage wird nun auch der nette pivot_root(".", ".")Trick erklärt , der pivot_rootin den meisten Fällen am einfachsten anzuwenden ist (nicht chrooterforderlich).
Philipp Wendler