"dejar de compartir --mount" dentro de un entorno chroot de jenkins

"dejar de compartir --mount" dentro de un entorno chroot de jenkins

En algunos de mis scripts de compilación, he estado usando espacios de nombres de montaje como mecanismo para montar de forma segura sin dejar estos montajes cuando finaliza el script. Los puntos de montaje no compartidos se desmontan implícitamente cuando sale el último proceso en ese espacio de nombres..

Mis guiones suelen incluir una stansa como esta:

#!/bin/bash
self_ns=$(ls -lh /proc/self/ns/mnt)
init_ns=$(ls -lh /proc/$PPID/ns/mnt)
if [ "${self_ns#*mnt:}" = "${init_ns#*mnt:}" ] ; then
    unshare --mount $0 "$@"
    exit $?
fi

Si bien esto me ha funcionado bien durante algún tiempo, recientemente me encontré con un problema en un servidor de compilación jenkins.

Creo que el problema es que el script de compilación en sí se ejecuta dentro de unentorno chroot de jenkins. Entonces, cuando se ejecuta el script unshare --mount ..., falla con el error:

unshare: cannot change root filesystem propagation: Invalid argument

Lamentablemente, realmente no entiendo esta restricción ni cómo sortearla. Cuando intento hacer un chroot en la línea de comando, no puedo replicar este error. No sé qué ha hecho el complemento jenkins para causar esto.

Lo más importante es que estos puntos de montaje se eliminen al salir.cada vez sin falta.

Respuesta1

Según el comentario de AB, encontré una solución alternativa:

AB escribió:

Recibo el mismo error si hago chroot en la instalación del directorio rootfs de un lxc y unshare --mount bash. Si primero vinculo el montaje (--private) de este directorio en otro lugar y luego hago el chroot allí, unshare --mountentonces funciona. No sé qué significa esto, pero espero que pueda ayudar a encontrar la causa o una solución (agregar un montaje de enlace en la tubería).

Basado en esto descubrí que esto no funciona:

unshare --mount bash -c 'echo hello'

Pero esto funciona:

mount --bind --make-private / /mnt 
chroot /mnt unshare --mount bash -c 'echo hello'
umount /mnt

Respuesta2

La causa del problema es que unshareintenta establecer los indicadores de propagación de montaje del directorio raíz, lo que sólo se puede hacer para los puntos de montaje. El directorio raíz del entorno chroot de Jenkins no es un punto de montaje.

Por ejemplo:

$ unshare -rm mount --make-rprivate /opt
mount: /opt: not mount point or bad option.

Una reproducción completa:

#!/bin/bash
try() {
  mount -t tmpfs t /mnt
  mkdir /mnt/t
  for i in /bin /lib* /sbin /usr /home /proc
  do
    mkdir "/mnt/t$i"
    mount --rbind "$i" "/mnt/t$i"
  done
  chroot /mnt/t unshare -m echo OK
}
export -f try
unshare -rm bash -c try

Una solución alternativa sencilla que no realiza montajes fuera del espacio de nombres de montaje. Escapa del chroot para configurar la propagación del montaje y asume que el comando de montaje está disponible fuera del chroot:

unshare --propagation unchanged -m sh -c \
'nsenter --mount=/proc/self/ns/mnt mount --make-rslave /; echo Do some mounts'

O convierta el chroot en un pivot_rootentorno:

#define _GNU_SOURCE
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

static int pivot_root(const char *new_root, const char *put_old){
    return syscall(SYS_pivot_root, new_root, put_old);
}

int main(int argc, char **argv) {

    if (unshare(CLONE_NEWNS))
        error(1, errno, "unshare");

    int root = open("/", O_DIRECTORY | O_PATH | O_CLOEXEC);
    if (root < 0) error(1, errno, "open /");

    int ns = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
    if (ns < 0) error(1, errno, "open mount namespace");

    if (setns(ns, CLONE_NEWNS))
        error(1, errno, "setns");

    if (fchdir(root))
        error(1, errno, "fchdir");

    if (mount("/", "/", 0, MS_REC|MS_SLAVE, 0))
        error(1, errno, "mount --make-rslave");

    if (mount(".", "proc", 0, MS_REC|MS_BIND, 0))
        error(1, errno, "mount --rbind");

    if (chdir("proc"))
        error(1, errno, "chdir");

    if (pivot_root(".", "proc"))
        error(1, errno, "pivot_root");

    if (umount2("proc", MNT_DETACH))
        error(1, errno, "umount");

    execvp(argv[1], argv + 1);
    error(1, errno, "exec");
}

información relacionada