Linux · 8 min read · Feb 03, 2026

Entrando a un espejo seguro al iniciar sesión con Unionfs y Chroot

Entrando a un espejo seguro al iniciar sesión con Unionfs y Chroot

1. Introducción

Al leer un ‘hint’ en el sitio web de LinuxFromScratch, descubrí las capacidades especiales de unionfs, especialmente en combinación con chroot. Más tarde leí un HowTo en un wiki de Gentoo, sobre cómo entrar en un directorio personal chrooted al usar un script especial como shell. Combinar estos dos me lleva a usar un entorno chrooted, que se ingresa al iniciar sesión como un usuario especial. Este entorno es una copia exacta (espejo) del sistema en el que estás trabajando. Debido a que estás en una copia segura del sistema real, puedes hacer lo que quieras, nunca cambiará el sistema, todo permanece dentro de la caché (la rama de lectura y escritura).

Enlaces:
TRIP, un empaquetador TRIvial para LFS (y otros sistemas linux) - Hint original en el sitio web de LFS
Home_directory_jail - Guía para configurar una cárcel chroot en Gentoo

2. Técnica básica

Haz lo que quieras, instala, cambia y elimina archivos del sistema, y no habrá ningún daño. Tu sistema real permanece intacto. Esto puede sonar como magia, pero en realidad es posible solo combinando algunas técnicas de todas las disponibles para Linux.
Al usar el sistema de archivos Unionfs, un chroot y algunos directorios remonteados bien elegidos, puedes configurar este sistema virtual.

2.1 Unionfs

La parte más importante es el uso de unionfs. Unionfs te da la posibilidad de crear un sistema de archivos, que es la unión de al menos otros dos. Consulta www.unionfs.org para más información. Ahora, al dejar que el nuevo sistema de archivos sea la unión de nuestro sistema de archivos original (la raíz) en modo solo lectura, y de un sistema de archivos temporal (la caché) en modo de lectura y escritura, tendrás un sistema de archivos que se ve exactamente como tu sistema de archivos original, pero en el que puedes modificar, eliminar y/o agregar archivos sin hacer nada a tu sistema original. Esto no es posible, porque la raíz está montada como solo lectura. Cada modificación es almacenada por unionfs en la caché.
La única diferencia entre el sistema original y el recién creado es la ruta: en el nuevo sistema siempre comienza con la ruta del punto de montaje de la unión. Por eso el siguiente paso es necesario.

Una nota especial: hoy [junio de 2007] parece que unionfs será incluido en el kernel. Unionfs está en un desarrollo intenso en este momento. Consulta el sitio web para más información.

En el sitio web encontrarás información sobre cómo habilitar unionfs. Para los últimos kernels (posteriores a 2.6.19) hay un parche para el código fuente del kernel, para kernels no tan recientes hay un módulo externo.

2.2 (Re)Montaje

Una cosa extra que tendrás que hacer es (re)montar varios directorios cruciales como /dev, /proc y /sys. Esto se debe a que el sistema de archivos de unión no preserva los puntos de montaje existentes.
También se recomienda volver a montar algunos directorios especiales como /tmp y el directorio en el que estás construyendo el software.

2.3 Chroot

Al chrootear a este punto de montaje, entras en un entorno que es absolutamente una copia de tu sistema. Puedes hacer lo que quieras, incluso eliminar directorios y archivos cruciales. ¡Pruébalo! Mira hasta dónde puedes llegar antes de que tu sistema se quede atascado.

2.4 Iniciar sesión en este entorno

Como el concepto explicado en Home_directory_jail, es posible crear un shell de inicio de sesión especial para entrar en el entorno creado con unionfs y chroot.
La idea explicada aquí es crear un usuario especial, con un shell especial. Este shell, antes de entrar en un shell interactivo, primero realizará los pasos necesarios como montar el sistema de archivos de unión, volver a montar algunos directorios importantes y hacer el chroot.

3. Preparación

3.1 La partición de caché

Para comenzar, una partición con suficiente espacio para funcionar como caché. Esto no tiene que ser una partición física, puede ser una unidad virtual.

Crea esta unidad con:

dd if=/dev/zero of=/mnt/cache.img bs=1M count=500  
mkfs.ext2 /mnt/cache.img  
mkdir /mnt/cache  
mount /mnt/cache.img /mnt/cache -o loop
chmod 777 /mnt/cache
mkdir /mnt/union

Esto crea una partición virtual (o unidad) de 500M.

(Nota: el dispositivo de bucle debe ser compatible con tu kernel. Los kernels de la mayoría de las distribuciones lo son.)

3.2 Shell de inicio de sesión especial

Crea un script de shell chroot-union que realizará todos los pasos necesarios:

El script chroot-union en /bin:

#!/bin/bash
function mount_unionfs {
# montar sistemas de archivos temporales
if [ -z "$(mount -t unionfs | grep -w /mnt/union )" ]; then
    sudo /bin/mount -t unionfs -o dirs=/mnt/cache:/=ro unionfs /mnt/union
    
fi
if [ -n "$(mount -t unionfs | grep -w /mnt/union )" ]; then
    # montajes del sistema básico
    if [ -z "$(mount | grep -w /mnt/union/dev)" ]; then
    sudo /bin/mount --bind /dev /mnt/union/dev 2> /dev/null
    fi
    
    if [ -z "$(mount -t devpts | grep -w /mnt/union/dev/pts)" ]; then
    sudo /bin/mount -t devpts devpts /mnt/union/dev/pts 2> /dev/null
    fi
    if [ -z "$(mount -t tmpfs | grep -w /mnt/union/dev/shm)" ]; then
    sudo /bin/mount -t tmpfs shm /mnt/union/dev/shm 2> /dev/null
    fi
    
    if [ -z "$(mount -t sysfs | grep -w /mnt/union/sys)" ]; then
    sudo /bin/mount -t sysfs sysfs /mnt/union/sys 2> /dev/null
    fi
    
    if [ -z "$(mount -t proc | grep -w /mnt/union/proc)" ]; then
    sudo /bin/mount -t proc proc /mnt/union/proc 2> /dev/null
    fi
    if [ -z "$(mount | grep -w /mnt/union/tmp)" ]; then
    sudo /bin/mount --bind /tmp /mnt/union/tmp 2> /dev/null
    fi
    
    
else
    echo "El montaje de /mnt/union falló."
    
    exit 2
fi
    
}
function umount_unionfs {
#
# desmontar /tmp
#
if [ -n "$(mount | grep -w /mnt/union/tmp)" ]; then
    sudo /bin/umount /mnt/union/tmp 2> /dev/null
fi
#
# desmontar /proc
#
if [ -n "$(mount -t proc | grep -w /mnt/union/proc)" ]; then
    sudo /bin/umount /mnt/union/proc 2> /dev/null
fi
#
# desmontar /sys
#
if [ -n "$(mount -t sysfs | grep -w /mnt/union/sys)" ]; then
    sudo /bin/umount /mnt/union/sys 2> /dev/null
fi
#
# desmontar /dev/shm
#
if [ -n "$(mount -t tmpfs | grep -w /mnt/union/dev/shm)" ]; then
    sudo /bin/umount /mnt/union/dev/shm 2> /dev/null
fi
#
# desmontar /dev/pts
#
if [ -n "$(mount -t devpts | grep -w /mnt/union/dev/pts)" ]; then
    sudo /bin/umount /mnt/union/dev/pts 2> /dev/null
fi
#
# desmontar /dev
#
if [ -n "$(mount | grep -w /mnt/union/dev)" ]; then    
sudo /bin/umount /mnt/union/dev 2> /dev/null
fi
if [ -n "$(mount | grep -w /mnt/union )" ]; then  
sudo /bin/umount /mnt/union 2> /dev/null
fi
}
mount_unionfs
# entrar en el chroot
sudo /usr/sbin/chroot /mnt/union /bin/su --shell /bin/bash --login $USER
# desmontar sistemas de archivos temporales
umount_unionfs
EOF

Agrega el nuevo shell de inicio de sesión al archivo /etc/shells. Tendrás que hacer esto cuando PAM verifique el shell.

3.3 Crear usuario y grupo.

Crea un nuevo grupo y usuario con este script como shell:

groupadd -g 27 uniongroup  
useradd -c "Usuario de prueba para chrooted union." -d /home/unionuser \  
-m -s /bin/chroot-union -g uniongroup -u 27 unionuser  
passwd unionuser

3.4 Dar al usuario suficientes derechos

Dale al nuevo usuario más derechos con sudo. Agrega la siguiente línea al archivo de configuración de sudo, /etc/sudoers:


unionuser ALL=(ALL) ALL

Nota: hay otras formas de dar permisos a este usuario. Estoy revisándolas en este momento.

Nota: dar estos permisos completos es demasiado para un usuario normal. Pero para un usuario que instalará software y modificará tu sistema es necesario.

Lo que es posible

Entorno seguro y protegido para usuarios normales

Esta construcción es muy adecuada para usuarios invitados, a los que no puedes confiar. Lo primero que intenté fue iniciar una sesión gráfica. No tuve ningún problema.

Instalar software como este usuario

Otro uso posible es la instalación de software como este usuario. Esto se puede hacer de la siguiente manera:

  • como este usuario, instala tu software. Debido a la construcción especial, todos los cambios van a la caché.
  • después de cerrar sesión, compara el contenido de la caché con el sistema real.
  • el usuario controlador (root) tiene la opción de hacer la instalación real simplemente moviendo el contenido de la caché a la raíz.

Por ejemplo, la compilación e instalación de un pequeño paquete, audiofile-0.2.6. Supongamos que la fuente está en /tmp. Primero inicia sesión:

[root@hostname ]# login  
hostname login: unionuser  
Password:  
Last login: Wed Jun 20 19:58:32 CEST 2007 on pts/0  
[unionuser@hostname ]$

Ahora compila e instala el paquete:

[unionuser@hostname ]$ cd /tmp/audiofile-0.2.6
[unionuser@hostname ]$ ./configure –prefix=/usr
[unionuser@hostname ]$ make
[unionuser@hostname ]$ sudo make install

Ahora sal de la sesión y verifica el contenido de la caché:

[unionuser@hostname ]$exit
[root@hostname ]# cd /mnt/cache
[root@hostname ]# ls -Al
drwxr-xr-x 3 root root 1024 2007-06-05 17:32 home
drwxr-xr-x 6 root root 1024 2007-06-05 17:37 usr
drwxr-xr-x 3 root root 1024 2007-06-05 17:32 var
[root@hostname ]#

El directorio home aparece aquí porque el shell Bash cambia el archivo .bash_history; el directorio var aparece debido a cambios en el archivo /var/run/utmp y el directorio /var/run/sudo. Esto prueba que funciona como debería.

Ahora, al mirar los cambios en el directorio /usr donde he instalado el software, da:

[root@hostname ]# find usr -type f
usr/lib/pkgconfig/audiofile.pc
usr/lib/libaudiofile.la
usr/lib/libaudiofile.a
usr/lib/libaudiofile.so.0.0.2
usr/include/audiofile.h
usr/include/aupvlist.h
usr/include/af_vfs.h
usr/bin/audiofile-config
usr/bin/sfconvert
usr/bin/sfinfo
usr/share/aclocal/audiofile.m4
[root@hostname ]# find usr -type d
usr
usr/lib
usr/lib/pkgconfig
usr/include
usr/bin
usr/share
usr/share/aclocal

Como puedes ver, todo está en el directorio /mnt/cache/usr.

Puedes hacer una copia de seguridad de esto:

[root@hostname ]# find usr | sort -u > /tmp/filelist-audiofile-0.2.6  

[root@hostname ]# tar --create --files-from=/tmp/filelist-audiofile-0.2.6 \  
                  --file=/tmp/install-audiofile-0.2.6.tar --directory=/mnt/cache \  
                  --no-recursion --absolute-names --preserve-permissions

También es muy posible hacer una copia de seguridad de todos los archivos que serán sobrescritos:

[root@hostname ]# for installfile in $(cat /tmp/filelist-audiofile-0.2.6); do \  
                    if [ -e "/$installfile ]; then \  
                      echo "/$installfile" >> /tmp/backup-audiofile-0.2.6 \  
                    fi \  
                  done  
[root@hostname ]# tar --create --files-from=/tmp/backup-audiofile-0.2.6 \  
                  --file=/tmp/backup-audiofile-0.2.6.tar --directory=/mnt/cache \  
                  --no-recursion --absolute-names --preserve-permissions

Ahora haz la instalación real copiando todos los archivos a la raíz:

[root@hostname ]# for installfile in $(cat /tmp/filelist-audiofile-0.2.6); do \  
                    cp --verbose --force --recursive --parents --no-dereference \  
                      --preserve --target-directory=/ $installfile \  
                  done

Nota: los comandos anteriores son para ilustrar la idea. He creado scripts que realizan la copia de seguridad, la verificación y la instalación, y funciona muy bien.

Share: X/Twitter LinkedIn

Recibe nuevas publicaciones en tu bandeja de entrada.

No spam. Cancela la suscripción en cualquier momento.