¿Por qué el montaje no respeta la opción de solo lectura para los montajes de enlace?

35

En mi sistema Arch Linux (Linux Kernel 3.14.2), los montajes de enlace no respetan la opción de solo lectura

# mkdir test
# mount --bind -o ro test/ /mnt
# touch /mnt/foo

crea el archivo /mnt/foo. La entrada relevante en /proc/mountses

/dev/sda2 /mnt ext4 rw,noatime,data=ordered 0 0

Las opciones de montaje no coinciden con mis opciones solicitadas, pero coinciden con el comportamiento de lectura / escritura del montaje de enlace y las opciones utilizadas para montar originalmente /dev/sda2en/

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

Sin embargo, si vuelvo a montar el soporte, respeta la opción de solo lectura

# mount --bind -o remount,ro test/ /mnt
# touch /mnt/bar
touch: cannot touch ‘/mnt/bar’: Read-only file system

y la entrada relevante en /proc/mounts/

/dev/sda2 /mnt ext4 ro,relatime,data=ordered 0 0

se parece a lo que podría esperar (aunque en verdad esperaría ver la ruta completa del testdirectorio). La entrada /proc/mounts/para el montaje original de /dev/sda2/on /tampoco cambia y permanece en lectura / escritura

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

Este comportamiento y la solución se conocen desde al menos 2008 y están documentados en la página de manual demount

Tenga en cuenta que las opciones de montaje del sistema de archivos seguirán siendo las mismas que en el punto de montaje original, y no se pueden cambiar pasando la opción -o junto con --bind / - rbind. Las opciones de montaje se pueden cambiar mediante un comando de montaje por separado

No todas las distribuciones se comportan igual. Arch parece no respetar silenciosamente las opciones, mientras que Debian genera una advertencia cuando el montaje de enlace no obtiene montaje de solo lectura

mount: warning: /mnt seems to be mounted read-write.

Hay informes de que este comportamiento fue "arreglado" en Debian Lenny y Squeeze, aunque no parece ser una solución universal ni funciona en Debian Wheezy. ¿Cuál es la dificultad de hacer que el montaje de enlace respete la opción de solo lectura en el montaje inicial?

Fuerte
fuente
¿Tienes un / etc / mtab?
eyoung100
Vea también thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 y una solución usando mount -t bindun script de ayuda en bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Stéphane Chazelas
@ECarterYoung sí, tengo un /etc/mtab. Después del montaje inicial, la entrada dice que el montaje es rw y después del montaje dice ro, por lo que informa el estado del montaje correctamente. Es solo el comando de montaje el que falla.
StrongBad
3
Probé en dos máquinas de prueba / inestables de Debian, una con un núcleo de Debian y otra con un núcleo kernel.org, ninguno de los cuales funciona mount --bind -o ro, ambos escupen un mensaje mount: warning: «mountpoint» seems to be mounted read-write.. Parece que Debian cayó o perdió el parche en algún momento ... funciona, sin embargo.
derobert
2
@StrongBad Probó eso según lo solicitado, y tampoco funciona.
derobert

Respuestas:

21

Bind Mount es solo ... bueno ... Bind Mount. Es decir, no es una nueva montura. Simplemente "vincula" / "expone" / "considera" un subdirectorio como un nuevo punto de montaje. Como tal, no puede alterar los parámetros de montaje. Es por eso que recibes quejas:

# mount /mnt/1/lala /mnt/2 -o bind,ro
mount: warning: /mnt/2 seems to be mounted read-write.

Pero como dijiste, un montaje de unión normal funciona:

# mount /mnt/1/lala /mnt/2 -o bind

Y luego un montaje de ro también funciona:

# mount /mnt/1/lala /mnt/2 -o bind,remount,ro 

Sin embargo, lo que sucede es que está cambiando todo el montaje y no solo este montaje de enlace. Si echas un vistazo a / proc / monturas, verás que tanto el montaje de enlace como el montaje original cambian a solo lectura:

/dev/loop0 /mnt/1 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0
/dev/loop0 /mnt/2 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0

Entonces, lo que está haciendo es como cambiar el montaje inicial a un montaje de solo lectura y luego hacer un montaje de enlace que, por supuesto, será de solo lectura.

ACTUALIZACIÓN 2016-07-20:

Lo siguiente es cierto para los núcleos 4.5, pero no es cierto para los núcleos 4.3 (Esto es incorrecto. Consulte la actualización # 2 a continuación):

El kernel tiene dos banderas que controlan solo lectura:

  • El MS_READONLY: Indica si el montaje es de solo lectura
  • El MNT_READONLY: Indica si el "usuario" lo quiere de solo lectura

En un kernel 4.5, hacer un mount -o bind,rotestamento realmente hará el truco. Por ejemplo, esto:

# mkdir /tmp/test
# mkdir /tmp/test/a /tmp/test/b
# mount -t tmpfs none /tmp/test/a
# mkdir /tmp/test/a/d
# mount -o bind,ro /tmp/test/a/d /tmp/test/b

creará un montaje de enlace de solo lectura de /tmp/test/a/dto /tmp/test/b, que será visible en /proc/mounts:

none /tmp/test/a tmpfs rw,relatime 0 0
none /tmp/test/b tmpfs ro,relatime 0 0

Se puede ver una vista más detallada /proc/self/mountinfo, que tiene en cuenta la vista del usuario (espacio de nombres). Las líneas relevantes serán estas:

363 74 0:49 / /tmp/test/a rw,relatime shared:273 - tmpfs none rw
368 74 0:49 /d /tmp/test/b ro,relatime shared:273 - tmpfs none rw

Donde en la segunda línea, puede ver que dice ambos ro( MNT_READONLY) y rw( !MS_READONLY).

El resultado final es este:

# echo a > /tmp/test/a/d/f
# echo a > /tmp/test/b/f
-su: /tmp/test/b/f: Read-only file system

ACTUALIZACIÓN 2016-07-20 # 2:

Un poco más de investigación muestra que el comportamiento depende de la versión de libmount que es parte de util-linux. El soporte para esto se agregó con este commit y se lanzó con la versión 2.27:

commit 9ac77b8a78452eab0612523d27fee52159f5016a
Autor: Karel Zak 
Fecha: lunes 17 de agosto 11:54:26 2015 +0200

    libmount: agregue soporte para "bind, ro"

    Ahora es necesario usar dos llamadas de montaje (8) para crear un solo lectura
    montar:

      mount / foo / bar -o bind
      mount / bar -o remontar, ro, bind

    Este parche permite especificar "bind, ro" y se realiza el montaje
    automáticamente por libmount por montaje adicional (2) syscall. No es
    atómica por supuesto.

    Firmado por: Karel Zak 

que también proporciona la solución alternativa. El comportamiento se puede ver usando strace en un montaje más antiguo y más nuevo:

Antiguo:

mount("/tmp/test/a/d", "/tmp/test/b", 0x222e240, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.000681>

Nuevo:

mount("/tmp/test/a/d", "/tmp/test/b", 0x1a8ee90, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.011492>
mount("none", "/tmp/test/b", NULL, MS_RDONLY|MS_REMOUNT|MS_BIND, NULL) = 0 <0.006281>

Conclusión:

Para lograr el resultado deseado, es necesario ejecutar dos comandos (como ya dijo @Thomas):

mount SRC DST -o bind
mount DST -o remount,ro,bind

Las versiones más recientes de mount (util-linux> = 2.27) hacen esto automáticamente cuando se ejecuta

mount SRC DST -o bind,ro
V13
fuente
3
Si pero no. IIRC hay algún soporte en el núcleo para que diferentes puntos de montaje (no sistemas de archivos) tengan diferentes opciones. Debian solía tener un parche que mount -o bind,rocreaba una vista de solo lectura de un sistema de archivos de lectura-escritura (pero ya no parece estar en jadeo).
Gilles 'SO- deja de ser malvado'
No veo cómo esto contradice lo anterior. Los piratas informáticos pueden permitir todo tipo de cosas, incluidas cosas que no tienen mucho sentido. Actualmente, el remontaje de solo lectura en el kernel 3.14 finalmente se maneja con esta llamada: mnt_make_readonly (real_mount (mnt)), que como puede ver usa real_mount (), por lo que prácticamente afecta el montaje real y eso hace que los montajes de enlace reflejen el nuevo (solo lectura) bandera de montaje. Al menos eso entiendo.
V13
Entonces, esto sería una consecuencia del parche "spread struct mount" (específicamente este commit ), que aparece primero en el kernel 3.3. ¿Sabes si las consecuencias de este parche se discutieron en lkml o lwn?
Gilles 'SO- deja de ser malvado'
77
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... entonces touch /tmp/aestá bien, pero touch /mnt/tmp/bda touch: cannot touch ‘/mnt/tmp/b’: Read-only file system. Eso funciona tanto en Debian 3.13 como en kernel.org 3.14.2. Por lo tanto, no solo cambia todo el montaje. Al menos no con los núcleos recientes.
derobert
1
Presumiblemente la afirmación de que un "montaje de unión es solo ... bueno ... un montaje de unión" Es realmente importante pero no significa nada para mí. Tampoco entiendo por qué funciona la segunda vez con la opción de montaje.
StrongBad
9

La solución adecuada es realmente montarlo dos veces. En la línea de comando:

mount -t none -o bind /source/dir /destination/dir
mount -t none -o bind,remount,ro /source/dir /destination/dir

En /etc/fstab:

/source/dir            /destination/dir    none  bind            0 0
/source/dir            /destination/dir    none  remount,bind,ro 0 0

El manual ( man mount) lo dice así:

   The bind mounts.
          Since Linux 2.4.0 it is possible to remount part of the file hierarchy somewhere else. The call is
                 mount --bind olddir newdir
   [...]
          Note that the filesystem mount options will remain the same as those on the original mount point, and cannot be changed  by  passing  the  -o  option
          along with --bind/--rbind. The mount options can be changed by a separate remount command, for example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro newdir
          .
          Note  that  behavior  of  the remount operation depends on the /etc/mtab file. The first command stores the 'bind' flag to the /etc/mtab file and the
          second command reads the flag from the file.  If you have a system without the /etc/mtab file or if you explicitly define source and target  for  the
          remount command (then mount(8) does not read /etc/mtab), then you have to use bind flag (or option) for the remount command too. For example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro,bind olddir newdir
Thomas
fuente
Esto parece funcionar con al menos Ubuntu 14.04 LTS y kernel 3.19.0-51-lowlatency. ¡Agradable!
Mikko Rantalainen
0

Está preguntando desde la perspectiva de la mount(8)línea de comando (que es aceptable en este sitio). Ese comando se ha discutido en las otras respuestas y, en algunos casos, extrae la segunda mount(2)llamada al sistema necesaria .

Pero, ¿por qué se necesita la segunda llamada al sistema? ¿Por qué una sola mount(2)llamada no puede crear el montaje de enlace de solo lectura?

La mount(2)página del manual explica que, como otros han señalado, se están configurando dos conjuntos de banderas:

  • Las banderas subyacentes del sistema de archivos
  • Las banderas de punto de montaje VFS

Dice:

Desde Linux 2.6.16, MS_RDONLYse puede establecer o borrar por punto de montaje, así como en el sistema de archivos subyacente. El sistema de archivos montado solo se podrá escribir si ni el sistema de archivos ni el punto de montaje se marcan como de solo lectura.

Y con respecto a MS_REMOUNT:

Desde Linux 2.6.26, este indicador se puede usar MS_BINDpara modificar solo los indicadores por punto de montaje. Esto es particularmente útil para configurar o borrar el indicador de "solo lectura" en un punto de montaje sin cambiar el sistema de archivos subyacente. Especificando banderas de montaje como:

      MS_REMOUNT | MS_BIND | MS_RDONLY

hará que el acceso a través de este punto de montaje sea de solo lectura, sin afectar a otros puntos de montaje.

Creo que el problema surgió cuando se introdujeron los montajes de unión:

Si mountflags incluye MS_BIND(disponible desde Linux 2.4), realice un montaje de enlace. ... Los bits restantes en el argumento mountflags también se ignoran, con la excepción de MS_REC. (El montaje de enlace tiene las mismas opciones de montaje que el punto de montaje subyacente).

Parece que, en lugar de usar MS_BIND | MS_REMOUNTcomo señal para establecer solo los indicadores VFS, podrían haber elegido exceptuar (y aceptar) MS_RDONLYjunto con la inicial MS_BINDy aplicarla al punto de montaje.

Entonces, debido a la semántica algo extraña de la mount(2)llamada al sistema:

  • La primera llamada crea el montaje de enlace y todos los demás indicadores se ignoran
  • La segunda llamada (con remontaje) establece los indicadores de punto de montaje en solo lectura
Jonathon Reinhart
fuente