¿Cómo puedo decir que estoy corriendo en un chroot?

47

Tengo una instalación de Unix que se supone que se puede utilizar como chroot y como sistema independiente. Si se ejecuta como chroot, no quiero ejecutar ningún servicio (cron, inetd, etc.), ya que entrarían en conflicto con el sistema host o serían redundantes.

¿Cómo escribo un script de shell que se comporta de manera diferente dependiendo de si se ejecuta en un chroot? Mi necesidad inmediata es un sistema Linux moderno, /procmontado en el chroot, y el script se ejecuta como root, pero también se aceptan respuestas más portátiles. (Consulte ¿Cómo puedo saber si estoy ejecutando un chroot si / proc no está montado? Para el caso de Linux sin /proc).

En términos más generales, las sugerencias que funcionan para otros métodos de contención serían interesantes. La pregunta práctica es, ¿se supone que este sistema ejecuta algún servicio? (La respuesta es no en un chroot, y sí en máquinas virtuales completas; no sé sobre casos intermedios como cárceles o contenedores).

Gilles 'SO- deja de ser malvado'
fuente

Respuestas:

46

Lo que he hecho aquí es probar si la raíz del initproceso (PID 1) es la misma que la raíz del proceso actual. Aunque /proc/1/rootsiempre es un enlace a /(a menos que esté en initsí, pero ese no es un caso que me interese), seguirlo lleva al directorio raíz "maestro". Esta técnica se utiliza en algunos scripts de mantenimiento en Debian, por ejemplo, para omitir el inicio de udev después de la instalación en 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

(Por cierto, este es otro ejemplo de por qué chrootes inútil para la seguridad si el proceso chrooteado tiene acceso a la raíz. Los procesos no root no pueden leer /proc/1/root, pero pueden seguir /proc/1234/rootsi hay un proceso en ejecución con PID 1234 ejecutándose igual) usuario.)

Si no tiene permisos de root, puede ver /proc/1/mountinfoy /proc/$$/mountinfo(brevemente documentado filesystems/proc.txten la documentación del kernel de Linux ). Este archivo es legible en todo el mundo y contiene mucha información sobre cada punto de montaje en la vista del proceso del sistema de archivos. Las rutas en ese archivo están restringidas por el chroot que afecta el proceso del lector, si lo hay. Si la lectura del proceso /proc/1/mountinfose procesa en un sistema de archivos que es diferente de la raíz global (suponiendo que la raíz de pid 1 sea la raíz global), no /aparece ninguna entrada para /proc/1/mountinfo. Si la lectura del proceso /proc/1/mountinfose cambia a un directorio en el sistema de archivos raíz global, entonces /aparece una entrada para /proc/1/mountinfo, pero con un ID de montaje diferente. Por cierto, el campo raíz ($4) indica dónde está el chroot en su sistema de archivos maestro.

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

Esta es una solución pura de Linux. Puede ser generalizable a otras variantes de Unix con una suficientemente similar /proc(Solaris tiene una similar /proc/1/root, creo, pero no mountinfo).

Gilles 'SO- deja de ser malvado'
fuente
1
Esto no funcionará en OpenBSD porque tiene PID aleatorios ; el proceso raíz es básicamente nunca PID 1. ¡Ahora sabes por qué!
Adam Katz
@AdamKatz "... con un par de excepciones obvias, por ejemplo, init (8)". Entonces, ¿cuál es?
muru
@muru: aw, demonios. Me has derribado. No estoy seguro de por init(8)qué necesitaría tener el espacio n. ° 1 a menos que haya algún tipo de naturaleza codificada que lo requiera (en el que todavía no estoy seguro de por qué ). Por supuesto, los BSD tienen cárceles mucho más avanzadas que solo chroot, por lo que ni siquiera estoy seguro de lo problemático que es esto.
Adam Katz
44
@AdamKatz Es todo lo contrario: pid 1 tiene un papel especial (debe cosechar zombies y es inmune a SIGKILL). El programa init es una implementación de ese rol. La razón por la que mi respuesta no funciona en OpenBSD no tiene nada que ver con esto: es porque OpenBSD no tiene nada como Solaris / Linux /proc. Mi respuesta no estaba destinada a abordar nada más que Linux de todos modos.
Gilles 'SO- deja de ser malvado'
@Gilles pensé que OpenBSD habría derrotado esto de una manera u otra. Aún así, me sorprende que todos esos elementos de roles especiales no puedan aplicarse a un PID arbitrario (sin consecuencias), que es lo que quise decir en mi "por qué" en cursiva anteriormente.
Adam Katz
22

Como se mencionó en la forma portátil para encontrar el número de inodo y detectar una cárcel chroot desde adentro , puede verificar si el número de inodo /es 2:

$ ls -di /
2 /

Un número de inodo diferente de 2 indica que la raíz aparente no es la raíz real de un sistema de archivos. Esto no detectará los chroots que están enraizados en un punto de montaje o en sistemas operativos con números de inodo de raíz aleatorios .

l0b0
fuente
¿En qué sistemas de archivos funciona esta heurística?
Gilles 'SO- deja de ser malvado'
Probado en ext3 y hfs.
l0b0
Así que estaba bromeando, y creo que he encontrado un método más confiable que no requiere permisos de root (solo Linux). Todavía estoy abierto a contraejemplos o métodos más portátiles.
Gilles 'SO- deja de ser malvado'
66
Esto es cierto para ext [234], pero no para todos los sistemas de archivos. También solo prueba que su raíz es la raíz del sistema de archivos, que puede no estar montada como la raíz real. En otras palabras, si monta otra partición en / jail y chroot /jail, entonces se verá como la raíz real de esta prueba.
psusi
1
@AdamKatz Aparentemente no. Probado en openbsd 6.0 estable, el número de inodo sigue siendo 2 para la ruta raíz real, mientras que es un número aleatorio para el chroot.
Dmitri DB
5

Aunque claramente no es tan portátil como muchas otras opciones enumeradas aquí, si está en un sistema basado en Debian, intente ischroot.

Ver: https://manpages.debian.org/jessie/debianutils/ischroot.1.en.html

Para obtener el estado en la consola directamente, usando ischroot:

ischroot;echo $?

Códigos de salida

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).
thom_nic
fuente