Después de leer sobre los espacios de nombres de Linux, tuve la impresión de que son, entre muchas otras características, una alternativa a chroot. Por ejemplo, en este artículo:
Otros usos [de los espacios de nombres] incluyen […] el aislamiento al estilo chroot() de un proceso en una parte de la jerarquía de un solo directorio.
Sin embargo, cuando clono el espacio de nombres de montaje, por ejemplo con el siguiente comando, sigo viendo todo el árbol raíz original.
unshare --mount -- /bin/bash
Entiendo que ahora puedo realizar montajes adicionales en el nuevo espacio de nombres que no se comparten con el espacio de nombres original y, por lo tanto, esto proporciona aislamiento, pero sigue siendo la misma raíz, p. /etc
sigue siendo el mismo para ambos espacios de nombres. ¿Todavía necesito chroot
? cambiar la raíz o hay alguna alternativa?
Esperaba que esta pregunta proporcionara una respuesta, pero la respuesta solo usa chroot
, de nuevo.
EDITAR #1
Había un comentario ahora eliminado que mencionaba pivot_root
. Dado que esto es en realidad parte de linux/fs/namespace.c
, de hecho es parte de la implementación de los espacios de nombres. Esto sugiere que cambiar el directorio raíz solo con unshare
y mount
no es posible, pero los espacios de nombres proporcionan una versión propia, más inteligente, de chroot
. Todavía no entiendo la idea principal de este enfoque que lo hace fundamentalmente diferente de chroot
, incluso después de leer el código fuente (en el sentido de, por ejemplo, seguridad o mejor aislamiento).
EDITAR #2
Esto no es un duplicado de esta pregunta. Después de ejecutar todos los comandos de la respuesta, he separado /tmp/tmp.vyM9IwnKuY (o similar), ¡pero el directorio raíz sigue siendo el mismo!
Respuesta aceptada:
Ingresar un espacio de nombres de montaje antes de configurar un chroot
, le permite evitar saturar el espacio de nombres del host con montajes adicionales, p. para /proc
. Puedes usar chroot
dentro de un espacio de nombres de montaje como un truco agradable y simple.
Creo que hay ventajas en comprender pivot_root
, pero tiene un poco de una curva de aprendizaje. La documentación no explica todo del todo... aunque hay un ejemplo de uso en man 8 pivot_root
(para el comando de shell). man 2 pivot_root
(para la llamada al sistema) podría ser más claro si hiciera lo mismo e incluyera un programa C de ejemplo.
Cómo usar pivot_root
Inmediatamente después de ingresar el espacio de nombres de montaje, también necesita mount --make-rslave /
o equivalente. De lo contrario, todos los cambios de montaje se propagan a los montajes en el espacio de nombres original, incluido el pivot_root
. No quieres eso :).
Si usó unshare --mount
comando, tenga en cuenta que está documentado para aplicar mount --make-rprivate
por defecto. AFAICS, este es un valor predeterminado incorrecto y no desea esto en el código de producción. P.ej. en este punto, detendría eject
de trabajar en un DVD o USB montado en el espacio de nombres del host. El DVD o USB permanecería montado dentro del árbol de montaje privado y el núcleo no le permitiría expulsar el DVD.
Una vez que haya hecho eso, puede montar, p. el /proc
directorio que usará. De la misma manera que lo haría para chroot
.
A diferencia de cuando usas chroot
, pivot_root
requiere que su nuevo sistema de archivos raíz sea un punto de montaje. Si aún no lo es, puede satisfacer esto simplemente aplicando un montaje de vinculación:mount --rbind new_root new_root
.
Usar pivot_root
– y luego umount
el antiguo sistema de archivos raíz, con -l
/ MNT_DETACH
opción. (No necesita umount -R
, lo que puede llevar más tiempo).
Técnicamente, usando pivot_root
generalmente necesita involucrar el uso de chroot
así como; no es "o esto o lo otro".
Según man 2 pivot_root
, solo se define como el intercambio de la raíz del espacio de nombres de montaje. No está definido para cambiar a qué directorio físico apunta la raíz del proceso. O el directorio de trabajo actual (/proc/self/cwd
). Sucede que sí hágalo, pero esto es un truco para manejar los hilos del núcleo. La página de manual dice que eso podría cambiar en el futuro.
Por lo general, desea esta secuencia:
chdir(new_root); // cd new_root
pivot_root(".", put_old); // pivot_root . put_old
chroot("."); // chroot .
La posición del chroot
en esta secuencia hay otro detalle sutil. Aunque el punto de pivot_root
es reorganizar el espacio de nombres de montaje, el código del kernel parece encontrar el sistema de archivos raíz para mover al mirar la raíz por proceso, que es lo que chroot
conjuntos.
Por qué usar pivot_root
En principio, tiene sentido usar pivot_root
por seguridad y aislamiento. Me gusta pensar en la teoría de la seguridad basada en capacidades. Pasa una lista de los recursos específicos necesarios y el proceso no puede acceder a ningún otro recurso. En este caso, estamos hablando de los sistemas de archivos pasados a un espacio de nombres de montaje. Esta idea se aplica generalmente a la función de "espacios de nombres" de Linux, aunque probablemente no lo esté expresando muy bien.
chroot
solo establece la raíz del proceso, pero el proceso aún se refiere al espacio de nombres de montaje completo. Si un proceso conserva el privilegio de realizar chroot
, luego puede atravesar una copia de seguridad del espacio de nombres del sistema de archivos. Como se detalla en man 2 chroot
, "el superusuario puede escapar de una 'cárcel chroot' por...".
Otra manera sugerente de deshacer chroot
es nsenter --mount=/proc/self/ns/mnt
. Este es quizás un argumento más fuerte para el principio. nsenter
/ setns()
necesariamente vuelve a cargar la raíz del proceso, desde la raíz del espacio de nombres de montaje... aunque el hecho de que esto funcione cuando los dos se refieren a directorios físicos diferentes, podría considerarse un error del kernel. (Nota técnica:podría haber varios sistemas de archivos montados uno encima del otro en la raíz; setns()
usa la parte superior, la montada más recientemente).
Esto ilustra una ventaja de combinar un espacio de nombres de montaje con un "espacio de nombres PID". Estar dentro de un espacio de nombres PID le impediría ingresar el espacio de nombres de montaje de un proceso no confinado. También le impide ingresar a la raíz de un proceso no confinado (/proc/$PID/root
). Y, por supuesto, un espacio de nombres PID también evita que elimine cualquier proceso que esté fuera de él :-).