Comment savoir que je cours dans un chroot?


47

J'ai une installation Unix qui est supposée être utilisable à la fois en tant que chroot et en tant que système autonome. Si cela fonctionne en tant que chroot, je ne veux exécuter aucun service (cron, inetd, etc.), car ils seraient en conflit avec le système hôte ou seraient redondants.

Comment puis-je écrire un script shell qui se comporte différemment selon qu'il est exécuté dans un chroot? Mon besoin immédiat est un système Linux moderne, /procmonté dans le chroot, et le script s'exécutant en tant que root, mais des réponses plus portables sont également les bienvenues. (Voir Comment savoir si je suis en train de courir dans un chroot si / proc n'est pas monté? Dans le cas de Linux sans /proc.)

Plus généralement, des suggestions qui fonctionnent pour d'autres méthodes de confinement seraient intéressantes. La question pratique est de savoir si ce système est censé exécuter des services. (La réponse étant non dans un chroot et oui dans une machine virtuelle à part entière; je ne connais pas les cas intermédiaires tels que les prisons ou les conteneurs.)

Réponses:


46

Ce que j'ai fait ici est de vérifier si la racine du initprocessus (PID 1) est identique à la racine du processus actuel. Bien que ce /proc/1/rootsoit toujours un lien vers /(à moins que initlui-même ne soit chrooté, mais ce n’est pas un cas qui m’intéresse), cela conduit au répertoire racine «maître». Cette technique est utilisée dans quelques scripts de maintenance dans Debian, par exemple pour sauter le démarrage de udev après l’installation dans un chroot.

if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then
  echo "We are chrooted!"
else
  echo "Business as usual"
fi

(À propos, ceci est un autre exemple de la raison chrootpour laquelle la sécurité est inutile si le processus chrooté a un accès root. Les processus non root ne peuvent pas lire /proc/1/root, mais ils peuvent suivre /proc/1234/rootsi un processus en cours d'exécution avec le PID 1234 s'exécute de la même manière. utilisateur.)

Si vous ne disposez pas des autorisations root, vous pouvez consulter /proc/1/mountinfoet /proc/$$/mountinfo(brièvement documenté dans la documentation filesystems/proc.txtdu noyau Linux ). Ce fichier est lisible par tout le monde et contient de nombreuses informations sur chaque point de montage dans la vue du processus du système de fichiers par le processus. Les chemins dans ce fichier sont limités par le chroot affectant le processus de lecture, le cas échéant. Si la lecture du processus /proc/1/mountinfoest chrootée dans un système de fichiers différent de la racine globale (en supposant que la racine de pid 1 est la racine globale), aucune entrée pour /s'affiche dans /proc/1/mountinfo. Si la lecture du processus /proc/1/mountinfoest chrootée dans un répertoire du système de fichiers racine global, une entrée pour, /apparaît dans /proc/1/mountinfo, mais avec un ID de montage différent. Incidemment, le champ racine ($4) indique où se trouve le chroot dans son système de fichiers maître.

[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]

Ceci est une solution purement Linux. Il peut être généralisable à d’autres variantes Unix avec une valeur suffisamment similaire /proc(Solaris a une valeur similaire /proc/1/root, je pense, mais pas mountinfo).


1
Cela ne fonctionnera pas dans OpenBSD car il a des PID aléatoires ; le processus racine est fondamentalement jamais jamais PID 1. Maintenant vous savez pourquoi!
Adam Katz

@AdamKatz "... avec quelques exceptions évidentes, par exemple init (8)." Alors c'est quoi?
Muru

@muru: aw, merde. Tu m'as abattu. Je ne suis pas sûr de savoir pourquoi il init(8)faudrait absolument avoir le créneau n ° 1 à moins que cela ne soit imposé par une nature codée en dur (dans laquelle je ne suis toujours pas sûr de savoir pourquoi ). Bien sûr, les BSD ont des prisons bien plus avancées que le simple chroot, je ne suis même pas sûr de la gravité de la situation.
Adam Katz

4
@AdamKatz C'est l'inverse: pid 1 a un rôle spécial (il doit récolter des zombies et il est immunisé contre SIGKILL). Le programme init est une implémentation de ce rôle. La raison pour laquelle ma réponse ne fonctionne pas sous OpenBSD n’a rien à voir avec cela: c’est parce qu’OpenBSD n’a rien de comparable à celui de Solaris / Linux /proc. Ma réponse ne visait de toute façon pas Linux.
Gilles, arrête de faire le mal

@ Gilles j'ai pensé qu'OpenBSD aurait vaincu cela d'une manière ou d'une autre. Néanmoins, je suis surpris que tous ces éléments de rôle spéciaux ne puissent pas être appliqués à un PID arbitraire (sans conséquences), ce que je voulais dire dans mon précédent "pourquoi" en italique.
Adam Katz

22

Comme indiqué dans la section Méthode portable pour trouver le numéro d'inode et Détecter une prison chroot de l'intérieur , vous pouvez vérifier si le numéro d'inode /est 2:

$ ls -di /
2 /

Un numéro d'inode différent de 2 indique que la racine apparente n'est pas la racine réelle d'un système de fichiers. Cela ne détectera pas les chroots qui sont enracinés sur un point de montage ou sur des systèmes d'exploitation avec des numéros d'inode racine aléatoires .


Sur quels systèmes de fichiers cette heuristique fonctionne-t-elle?
Gilles, arrête de faire le mal

Testé sur ext3 et hfs.
l0b0

Je me suis donc moqué de moi et je pense avoir trouvé une méthode plus fiable ne nécessitant pas d'autorisations root (Linux uniquement). Je suis toujours ouvert aux contre-exemples ou aux méthodes plus portables.
Gilles, arrête de faire le mal le

6
Ceci est vrai pour ext [234], mais pas pour tous les systèmes de fichiers. Il vérifie également que votre racine est la racine du système de fichiers, qui ne peut pas être monté en tant que racine réelle. En d'autres termes, si vous montez une autre partition dans / jail chroot /jail, elle ressemblera à la véritable racine de ce test.
Psusi

1
@AdamKatz Apparemment pas. Testé dans openbsd 6.0-stable, le numéro d'inode est toujours 2 pour le chemin racine réel alors qu'il s'agit d'un nombre aléatoire pour le chroot.
Dmitri DB

5

Bien que ce ne soit clairement pas aussi portable que de nombreuses autres options répertoriées ici, essayez un système basé sur Debian ischroot.

Voir: https://manpages.debian.org/jessie/debianutils/ischroot.1.fr.html

Pour obtenir le statut directement dans la console, utilisez ischroot:

ischroot;echo $?

Codes de sortie:

0 if currently running in a chroot
1 if currently not running in a chroot
2 if the detection is not possible (On GNU/Linux this happens if the script is not run as root).
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.