Comment effectuer un chroot avec des espaces de noms Linux?

14

Après avoir lu sur les espaces de noms Linux, j'avais l'impression qu'ils sont, parmi beaucoup d'autres fonctionnalités, une alternative au chroot. Par exemple, dans cet article :

D'autres utilisations [des espaces de noms] incluent [...] l'isolement de style chroot () d'un processus à une partie de la hiérarchie de répertoire unique.

Cependant, lorsque je clone l'espace de noms de montage, par exemple avec la commande suivante, je vois toujours la totalité de l'arborescence racine d'origine.

unshare --mount -- /bin/bash

Je comprends que je suis maintenant en mesure d'effectuer des montages supplémentaires dans le nouvel espace de noms qui ne sont pas partagés avec l'espace de noms d'origine et donc cela fournit l'isolement, mais c'est toujours la même racine, par exemple /etcest toujours le même pour les deux espaces de noms. Dois-je encore chrootchanger la racine ou existe-t-il une alternative?

Je m'attendais à ce que cette question fournisse une réponse, mais la réponse utilise seulement chroot, encore une fois.

EDIT # 1

Un commentaire maintenant supprimé a été mentionné pivot_root. Puisque cela fait en fait partie de linux/fs/namespace.c, il fait en fait partie de l'implémentation des espaces de noms. Cela suggère que la modification du répertoire racine uniquement avec unshareet mountn'est pas possible, mais les espaces de noms fournissent une version propre - plus intelligente - de chroot. Je n'ai toujours pas l'idée principale de cette approche qui la rend fondamentalement différente de chroot, même après avoir lu le code source (dans le sens par exemple de la sécurité ou d'une meilleure isolation).

EDIT # 2

Ce n'est pas un double de cette question . Après avoir exécuté toutes les commandes de la réponse, j'ai séparé /tmp/tmp.vyM9IwnKuY (ou similaire), mais le répertoire racine est toujours le même!

Koalo
la source
En ce qui concerne la différence entre pivot_rootet chroot: j'ai jeté un coup d'œil aux sources Docker et j'ai constaté que s'il échoue à l'exécution pivot_root, il revient à chroot, c'est- à -dire que ces mécanismes sont considérés comme au moins similaires en termes de fonctionnalités à des fins de conteneurisation.
Danila Kiver

Réponses:

13

La saisie d'un espace de noms de montage avant de configurer un chrootpermet d'éviter d'encombrer l'espace de noms de l'hôte avec des montages supplémentaires, par exemple pour /proc. Vous pouvez utiliser à l' chrootintérieur d'un espace de noms de montage comme un hack agréable et simple.

Je pense qu'il y a des avantages à comprendre pivot_root, mais cela a un peu de courbe d'apprentissage. La documentation n'explique pas tout ... bien qu'il y ait un exemple d'utilisation dans man 8 pivot_root(pour la commande shell). man 2 pivot_root(pour l'appel système) pourrait être plus clair s'il faisait de même, et incluait un exemple de programme C.

Comment utiliser pivot_root

Immédiatement après l'entrée dans l'espace de noms de montage, vous avez également besoin d' mount --make-rslave /un équivalent. Sinon, toutes vos modifications de montage se propagent aux montures de l'espace de noms d'origine, y compris le pivot_root. Vous ne voulez pas ça :).

Si vous avez utilisé la unshare --mountcommande, notez qu'elle est documentée pour s'appliquer mount --make-rprivatepar défaut. AFAICS c'est un mauvais défaut et vous ne voulez pas cela dans le code de production. Par exemple, à ce stade, il ne ejectfonctionnerait plus sur un DVD ou USB monté dans l'espace de noms de l'hôte. Le DVD ou l'USB resterait monté dans l'arborescence de montage privée et le noyau ne vous laisserait pas éjecter le DVD.

Une fois que vous avez fait cela, vous pouvez monter par exemple le /procrépertoire que vous utiliserez. De la même manière que vous le feriez chroot.

Contrairement à ce que vous utilisez chroot, pivot_rootnécessite que votre nouveau système de fichiers racine soit un point de montage. S'il est pas déjà, vous pouvez satisfaire en appliquant simplement une monture bind: mount --rbind new_root new_root.

Utilisez pivot_root- puis umountl'ancien système de fichiers racine, avec l' option -l/ MNT_DETACH. ( Vous n'avez pas besoin umount -R, ce qui peut prendre plus de temps. ).

Techniquement, l'utilisation pivot_rootdoit généralement impliquer l'utilisation chrootégalement; ce n'est pas "l'un ou l'autre".

Selon man 2 pivot_root, il est uniquement défini comme l'échange de la racine de l'espace de noms de montage. Il n'est pas défini pour changer le répertoire physique vers lequel pointe la racine du processus. Ou le répertoire de travail actuel ( /proc/self/cwd). Il arrive que ce ne le font, mais cela est un hack pour les threads du noyau de poignée. La page de manuel indique que cela pourrait changer à l'avenir.

Habituellement, vous voulez cette séquence:

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

La position de la chrootdans cette séquence est encore un autre détail subtil . Bien que l'objectif pivot_rootsoit de réorganiser l'espace de noms de montage, le code du noyau semble trouver le système de fichiers racine à déplacer en regardant la racine par processus, ce qui chrootdéfinit.

Pourquoi utiliser pivot_root

En principe, il est logique d'utiliser pivot_rootpour la sécurité et l'isolement. J'aime penser à la théorie de la sécurité basée sur les capacités . Vous passez une liste des ressources spécifiques nécessaires et le processus ne peut accéder à aucune autre ressource. Dans ce cas, nous parlons des systèmes de fichiers transmis à un espace de noms de montage. Cette idée s'applique généralement à la fonction "namespaces" de Linux, bien que je ne l'exprime probablement pas très bien.

chrootdéfinit uniquement la racine du processus, mais le processus fait toujours référence à l'espace de noms de montage complet. Si un processus conserve le privilège d'effectuer chroot, il peut parcourir en arrière l'espace de noms du système de fichiers. Comme détaillé dans man 2 chroot, "le superutilisateur peut s'échapper d'une" prison chroot "en ...".

Une autre façon de faire réfléchir chrootest de défaire nsenter --mount=/proc/self/ns/mnt. C'est peut-être un argument plus fort pour le principe. nsenter/ setns()recharge nécessairement la racine du processus, à partir de la racine de l'espace de noms de montage ... bien que le fait que cela fonctionne lorsque les deux font référence à des répertoires physiques différents, peut être considéré comme un bogue du noyau. (Note technique: il peut y avoir plusieurs systèmes de fichiers montés les uns sur les autres à la racine; setns()utilise le dernier, le plus récemment monté).

Cela illustre un avantage de combiner un espace de noms de montage avec un "espace de noms PID". Être à l'intérieur d'un espace de noms PID vous empêcherait d'entrer dans l'espace de noms de montage d'un processus non confiné. Cela vous empêche également d'entrer à la racine d'un processus non confiné ( /proc/$PID/root). Et bien sûr, un espace de noms PID vous empêche également de tuer tout processus en dehors de celui-ci :-).

sourcejedi
la source
Cela aide déjà beaucoup. Je ne sais toujours pas ce que vous entendez par "la monture en haut de l'espace de noms". Et existe-t-il un moyen de le changer?
koalo
1
@koalo édité :-). ps je ne sais pas pourquoi vous auriez besoin de fstab pour "make-rslave" / "make-rprivate". switch-root.c de systemd fait justemount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL)
sourcejedi
1
@koalo puis les développeurs du noyau linux ont utilisé "rootfs" lorsqu'ils ont nommé une quatrième chose :-P. unix.stackexchange.com/questions/152029/…
sourcejedi
1
Cette réponse et d'autres par @sourcejedi ont été exceptionnellement utiles, j'aurais demandé "pivot_root: impossible de monter um put_old comme occupé" mais la réponse était déjà là, soyez paresseux car la force ne fonctionnera pasumount -l ./oldroot
earcam
1
Récemment, il y a eu une mise à jour de la page de manuel pivot_root (2) avec plusieurs clarifications, et elle inclut maintenant un exemple de programme. Vous voudrez peut-être mettre à jour votre réponse pour refléter cela? La page de manuel explique maintenant également la bonne pivot_root(".", ".")astuce, qui est en fait la manière la plus simple à utiliser pivot_rootdans la plupart des circonstances (pas chrootnécessaire).
Philipp Wendler