Por que o mount não respeita a opção somente leitura para montagens de ligação?

30

No meu sistema Arch Linux (Linux Kernel 3.14.2) as montagens de ligação não respeitam a opção somente leitura

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

cria o arquivo /mnt/foo . A entrada relevante em /proc/mounts é

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

As opções de montagem não correspondem às minhas opções solicitadas, mas correspondem ao comportamento de leitura / gravação da montagem de ligação e às opções usadas para montar originalmente /dev/sda2 on /

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

Se, no entanto, eu remontar a montagem, ela respeitará a opção somente leitura

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

e a entrada relevante em /proc/mounts/

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

parece com o que eu poderia esperar (embora, na verdade, eu esperaria ver o caminho completo do diretório test ). A entrada em /proc/mounts/ para a montagem original de /dev/sda2/ on / também é inalterada e permanece como leitura / gravação

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

Esse comportamento e o trabalho em torno são conhecidos desde pelo menos 2008 e estão documentados na página do manual de mount

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

Nem todas as distribuições se comportam da mesma forma. Arch parece silenciosamente não respeitar as opções, enquanto o Debian gera um aviso quando a montagem de bind não é montada como somente leitura

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

Existem relatos de que esse comportamento foi "corrigido" no Lenny e Squeeze do Debian, embora não pareça ser uma correção universal nem ainda funciona no Debian Wheezy. Qual é o dificilmente associado a fazer a montagem de bind respeitando a opção somente leitura na montagem inicial?

    
por StrongBad 07.05.2014 / 17:47

2 respostas

16

A montagem de ligação é apenas ... bem ... uma montagem de ligação. Ou seja não é um novo monte. Apenas "links" / "expõe" / "considera" um subdiretório como um novo ponto de montagem. Como tal, não pode alterar os parâmetros de montagem. É por isso que você está recebendo reclamações:

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

Mas, como você disse, uma montagem normal de bind funciona:

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

E então uma remontagem ro também funciona:

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

No entanto, o que acontece é que você está mudando toda a montagem e não apenas essa montagem de ligação. Se você der uma olhada em / proc / mounts, verá que ambos bind mount e o mount original mudam para somente leitura:

/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

Então, o que você está fazendo é como mudar a montagem inicial para uma montagem somente leitura e então fazendo uma montagem de ligação que, naturalmente, será somente leitura.

ATUALIZAÇÃO 2016-07-20:

Os itens a seguir são verdadeiros para os kernels 4.5, mas não para os kernels 4.3 (Isso está errado. Veja a atualização 2 abaixo):

O kernel tem dois sinalizadores que controlam somente leitura:

  • O MS_READONLY : indicando se a montagem é somente leitura
  • O MNT_READONLY : indicando se o "usuário" quer que ele seja somente leitura

Em um kernel 4.5, fazer um mount -o bind,ro realmente fará o truque. Por exemplo, isso:

# 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

criará uma montagem de vinculação somente leitura de /tmp/test/a/d a /tmp/test/b , que será visível em /proc/mounts como:

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

Uma visão mais detalhada é visível em /proc/self/mountinfo , que leva em consideração a visão do usuário (namespace). As linhas relevantes serão 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

Onde na segunda linha, você pode ver que ele diz tanto ro ( MNT_READONLY ) quanto rw ( !MS_READONLY ).

O resultado final é este:

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

ATUALIZAÇÃO 2016-07-20 # 2:

Um pouco mais sobre isso mostra que o comportamento de fato depende da versão do libmount que faz parte do util-linux. O suporte para isso foi adicionado com este commit e foi lançado com a versão 2.27:

commit 9ac77b8a78452eab0612523d27fee52159f5016a
Author: Karel Zak 
Date:   Mon Aug 17 11:54:26 2015 +0200

    libmount: add support for "bind,ro"

    Now it's necessary t use two mount(8) calls to create a read-only
    mount:

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

    This patch allows to specify "bind,ro" and the remount is done
    automatically by libmount by additional mount(2) syscall. It's not
    atomic of course.

    Signed-off-by: Karel Zak 

que também fornece a solução alternativa. O comportamento pode ser visto usando strace em uma montagem mais antiga e mais recente:

Antigo:

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

Novo:

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>

Conclusão:

Para alcançar o resultado desejado, é necessário executar dois comandos (como @Thomas já disse):

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

Novas versões do mount (util-linux > = 2.27) fazem isso automaticamente quando se executa

mount SRC DST -o bind,ro
    
por 08.05.2014 / 00:25
9

A solução adequada é realmente montá-lo duas vezes. Na linha de comando:

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

Em /etc/fstab :

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

O manual ( man mount ) indica dessa forma:

   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
    
por 19.06.2015 / 20:41