c linux linux-namespaces

''Unshare'' no funciona como se espera en C api



linux linux-namespaces (4)

Esta secuencia de comandos funciona:

unshare --fork --pid --mount umount /proc mount -t proc proc /proc umount /dev/pts mount -t devpts devpts /dev/pts

Sin embargo, el programa C correspondiente no funciona como se esperaba (parece que no desmonta el proc / anterior, y también proporciona EBUSY al intentar desmontar los devpts):

unshare(CLONE_NEWPID | CLONE_NEWNS ); int pid = fork(); if (pid != 0) { int status; waitpid(-1, &status, 0); return status; } printf("My pid: %i/n", getpid()); // It prints 1 as expected umount("/proc"); // Returns 0 system("mount"); // Should print error on mtab, but it prints the previous mounted filesystems mount("proc", "/proc", "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)); // Returns 0 umount("/dev/pts"); // Returns -1 errno = 0 (??) mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL) ); // Returns -1 errno = EBUSY

He omitido aquí la comprobación de errores para la legibilidad

Creo que no compartir o desmontar no funciona como se esperaba: incluso si devuelve cero, parece que no se desmonta / proc (si intento ejecutar un system("mount") después de eso, imprime los sistemas de archivos montados).


A pesar de tu comentario que

"a veces" umount devuelve 0 "a veces" -1, pero al final no desmonta /proc en absoluto

, en 10000 intentos del código de tu pastebin, umount() siempre falló para mí, devolviendo -1 y no desmontando /proc . No estoy dispuesto a creer que umount() siempre devuelve 0 pesar de no haber realizado el desmontaje solicitado, pero si alguna vez lo hace, eso constituiría un error en umount() . Si de hecho puede justificar un error, la respuesta de la comunidad sería presentar un informe de error contra glibc.

La pregunta entonces se convierte en por qué y cómo su script de bash comporta de manera diferente. De hecho, sin embargo, no parece hacerlo.

En primer lugar, tiene la expectativa errónea del comando unshare(1) . A diferencia de la función unshare(2) , el comando unshare no afecta al shell en el que se ejecuta. En su lugar, lanza un proceso separado que tiene sus propias copias privadas de los espacios de nombres especificados. Normalmente, debe especificar el comando para iniciar ese proceso en la línea de comandos de no unshare y, de hecho, la página del manual del programa indica que hacerlo es obligatorio.

Empíricamente, encuentro que si no especifico un comando de este tipo, como lo hace usted, entonces unshare lanza un nuevo shell como proceso objetivo. En particular, cuando ejecuto su secuencia de comandos (con el privilegio suficiente para usar unshare ), inmediatamente recibo un nuevo indicador, pero es el indicador del nuevo shell, que se ejecuta en primer plano. Esto es inmediatamente evidente para mí porque la solicitud es diferente (sin embargo, su solicitud podría no ser diferente en esas circunstancias). No hay mensaje de error, etc. de umount en ese punto porque aún no se ha ejecutado . Si umount de umount manualmente proc en la subshell ( unshare d), falla con "el dispositivo está ocupado": este es el análogo de lo que su programa C intenta hacer.

Cuando salgo de la subshell, el resto de la secuencia de comandos se ejecuta, con umount sy ambos mount s fallando. Eso es de esperar, porque el script principal comparte su espacio de nombres de montaje.

Es completamente plausible que /proc realmente esté ocupado y, por lo tanto, no se pueda desmontar, incluso para un proceso que tiene una copia privada del espacio de nombres de montaje. Es probable que ese proceso esté utilizando su copia privada del montaje de /proc . En contraste, encuentro que puedo desmontar /dev/pts exitosamente en un proceso con un espacio de nombres de montaje no compartido, pero no en un proceso que comparta la copia del sistema de ese espacio de nombres.


Creo que el problema está en el sistema ("mount"), que genera un shell y no se transfiere a umount. Intente abrir un archivo en / proc / after umount y vea que funciona como se esperaba.

Mira esto -

unshare(CLONE_NEWPID | CLONE_NEWNS ); int rc = 0; int pid = fork(); if (pid != 0) { int status; waitpid(-1, &status, 0); return status; } printf(">>> My pid: %d/n", getpid()); // It prints 1 as expected rc = umount2("/proc", MNT_FORCE); // Returns 0 printf(">>> umount returned %d. errno = %d, desc = (%s)/n", rc, errno, strerror(errno)); rc = open("/proc/cpuinfo", O_RDONLY); printf(">>> open returned %d. errno = %d, desc = (%s)/n", rc, errno, strerror(errno));


Encontré el problema al verificar el código fuente del comando Unshare . El /proc debe ser desmontado con MS_PRIVATE | MS_REC MS_PRIVATE | MS_REC y montado sin ellos, esto es esencialmente para garantizar que el montaje tenga efecto solo en el espacio de nombres actual (el nuevo). El segundo problema es que no es posible desmontar /dev/pts sin producir un efecto en el espacio de nombres global (esto es causado por la rutina interna del controlador de devpts). Para tener un / dev / pts privado, la única forma es montarlo con la opción -o newinstance dedicada. Finalmente, /dev/ptmx también debe ser remontado de manera vinculante.

Por lo tanto, este es el código de trabajo de C como se esperaba:

unshare(CLONE_NEWPID | CLONE_NEWNS ); int pid = fork(); if (pid != 0) { int status; waitpid(-1, &status, 0); return status; } printf("New PID after unshare is %i", getpid()); if (mount("none", "/proc", NULL, MS_PRIVATE|MS_REC, NULL)) { printf("Cannot umount proc! errno=%i", errno); exit(1); } if (mount("proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL)) { printf("Cannot mount proc! errno=%i", errno); exit(1); } if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC, "newinstance") ) { printf("Cannot mount pts! errno=%i", errno); exit(1); } if (mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_BIND, NULL) ) { printf("Cannot mount ptmx! errno=%i", errno); exit(1); }


unshare bash! = unshare c

unshare - ejecuta el programa con algunos espacios de nombres no compartidos desde el padre

Básicamente, con --fork estás bifurcando desde / bin / sh de / bin / bash (sea cual sea tu ejecución de script) con las opciones --pid y --mount. "fork" seguido de "unshare"

unshare - desasociar partes del contexto de ejecución del proceso (proceso actual) Está desconectando de init y luego bifurcando.

CLONE_NEWPID es un indicador de "clonación" y no "no compartido"

Entonces, dependiendo de lo que está tratando de lograr, asumo que está tratando de hacer "/ proc" y "/ dev / pts" exclusivos para el proceso de niños.

Aquí hay un pequeño ejemplo con las carpetas locales de mount --bind:

# mkdir mnt point # touch point/point.txt # mount --bind point mnt # ls mnt point.txt # ./unshare My pid: 28377 Child: point.txt Parent: # ls mnt

Código:

#define _GNU_SOURCE #include <sched.h> int main(int argc, char *argv[]) { /** umount global */ system("umount mnt/"); int pid = fork(); if (pid != 0) { int status; waitpid(-1, &status, 0); printf("Parent:/n"); /* and here we don''t */ system("ls mnt/"); return status; } /* unshare */ unshare(CLONE_FS | CLONE_NEWNS); printf("My pid: %i/n", getpid()); // It prints 1 as expected /* mount exclusively */ system("mount --bind point/ mnt/"); printf("Child:/n"); /* here we see it */ system("ls mnt/"); return 0; }

También hay un buen ejemplo con bash: http://karelzak.blogspot.ru/2009/12/unshare1.html

continuación:

el montaje depende de / etc / mtab, que no siempre es un enlace simbólico a / proc / mounts

así que compruebe / etc / mtab con ls -la.

También verifique el código para umount en / dev / pts con:

int ret = umount("/dev/pts"); int errsv = errno; if(ret == -1) { printf("Error on umount: %s/n", strerror(errsv)); }

Estoy bastante seguro de que está en uso - verifíquelo con fuser / dev / pts /

** EDITADO **

Finalmente, no estoy seguro de que pueda desmontar procfs solo en el espacio de nombres (creo que es imposible)

pero puedes montar tu propia copia de procfs en tu espacio de nombres:

# mount -t proc proc /proc/

Ahora solo tu proceso es visible a través de ps -e.