Pourquoi mount ne respecte-t-il pas l'option de lecture seule pour les montages liés?

35

Sur mon système Linux Arch (Linux Kernel 3.14.2), les montages de liaison ne respectent pas l'option de lecture seule.

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

crée le fichier /mnt/foo. L'entrée pertinente dans /proc/mountsest

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

Les options de montage ne correspondent pas à mes options demandées, mais ne correspondent à la fois la lecture / comportement d'écriture de la liaison monter et les options utilisées pour monter à l' origine /dev/sda2sur/

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

Si, toutefois, je remonte la monture, elle respecte l'option de lecture seule.

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

et l'entrée correspondante dans /proc/mounts/

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

ressemble à ce à quoi je pourrais m'attendre (bien qu'en vérité je m'attende à voir le chemin complet du testrépertoire). L'entrée dans /proc/mounts/pour le montage d'origine de /dev/sda2/sur /est également inchangée et reste en lecture / écriture.

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

Ce comportement et le contournement sont connus depuis au moins 2008 et sont documentés dans la page de manuel demount

Notez que les options de montage du système de fichiers resteront les mêmes que celles du point de montage d'origine et ne peuvent pas être modifiées en passant l'option -o avec --bind / - rbind. Les options de montage peuvent être modifiées par une commande séparée de remontage

Toutes les distributions ne se comportent pas de la même manière. Arch semble ne pas respecter les options en silence tandis que Debian génère un avertissement lorsque le montage de la liaison ne reçoit pas le montage en lecture seule.

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

Il a été signalé que ce problème avait été "résolu" dans Debian Lenny and Squeeze, bien qu'il ne semble pas être un correctif universel ni qu'il fonctionne toujours dans Debian Wheezy. Qu'est-ce qui est difficile à faire pour que bind mount respecte l'option en lecture seule du montage initial?

StrongBad
la source
Avez-vous un / etc / mtab?
eyoung100
Voir aussi thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 et une solution de contournement en utilisant mount -t bindet un script d'assistance à l' adresse bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Stéphane Chazelas
@ECarterYoung oui j'ai un /etc/mtab. Après le montage initial, l'entrée indique que le montage est rw et après le remontage, elle indique ro, afin de signaler correctement l'état du montage. C'est juste la commande de montage qui échoue.
StrongBad
3
J'ai testé sur deux machines Debian testant / instables, l'une fonctionnant sous un noyau Debian et l'autre sous un noyau kernel.org, aucun des deux ne fonctionnant mount --bind -o ro, ils ont tous deux craché un message. mount: warning: «mountpoint» seems to be mounted read-write.Il semble donc que Debian ait oublié ou perdu le correctif à un moment donné ... Remount fonctionne, cependant.
derobert
2
@ StrongBad a testé cela comme demandé, et cela ne fonctionnait pas non plus.
derobert

Réponses:

21

La monture Bind est simplement… bien… une monture Bind. C'est pas une nouvelle monture. Il suffit de "liens" / "expose" / "considère" un sous-répertoire comme un nouveau point de montage. En tant que tel, il ne peut pas modifier les paramètres de montage. C'est pourquoi vous recevez des plaintes:

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

Mais comme vous l'avez dit, un montage normal fonctionne:

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

Et puis a ro remount fonctionne aussi:

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

Cependant, ce qui se passe, c’est que vous modifiez l’ensemble du montage et pas seulement ce montage lié. Si vous jetez un coup d'œil à / proc / mounts, vous verrez que le montage lié et le montage d'origine passent en lecture seule:

/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

Donc, ce que vous faites est comme changer le montage initial en un montage en lecture seule puis faire un montage lié qui sera bien sûr en lecture seule.

MISE À JOUR 2016-07-20:

Ce qui suit est vrai pour les noyaux 4.5, mais pas pour les noyaux 4.3 (cela est faux. Voir la mise à jour n ° 2 ci-dessous):

Le noyau a deux drapeaux contrôlant en lecture seule:

  • Le MS_READONLY: Indique si le montage est en lecture seule
  • Le MNT_READONLY: Indique si "l'utilisateur" veut qu'il soit en lecture seule

Sur un noyau 4.5, faire un mount -o bind,rotestament fait vraiment l'affaire. Par exemple, ceci:

# 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

créera un assemblage en lecture seule de /tmp/test/a/dto /tmp/test/b, qui sera visible /proc/mountssous:

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

Une vue plus détaillée est visible dans /proc/self/mountinfo, qui prend en compte la vue de l'utilisateur (espace de nom). Les lignes pertinentes seront les suivantes:

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

Où sur la deuxième ligne, vous pouvez voir qu'il est dit à la fois ro( MNT_READONLY) et rw( !MS_READONLY).

Le résultat final est ceci:

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

MISE À JOUR 2016-07-20 N ° 2:

Un peu plus loin, cela montre que le comportement dépend en fait de la version de libmount qui fait partie de util-linux. La prise en charge de ceci a été ajoutée avec ce commit et a été publiée avec la version 2.27:

commettre 9ac77b8a78452eab0612523d27fee52159f5016a
Auteur: Karel Zak 
Date: lun 17 août 11:54:26 2015 +0200

    libmount: ajoute le support pour "bind, ro"

    Maintenant, il est nécessaire d’utiliser deux appels à mount (8) pour créer un script en lecture seule.
    monter:

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

    Ce patch permet de spécifier "bind, ro" et le remontage est fait
    automatiquement par libmount par un appel système supplémentaire à mount (2). Ce n'est pas
    atomique bien sûr.

    Signé par: Karel Zak 

qui fournit également la solution de contournement. Le comportement peut être vu en utilisant strace sur un montage plus ancien et plus récent:

Vieux:

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

Nouveau:

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>

Conclusion:

Pour obtenir le résultat souhaité, il faut exécuter deux commandes (comme @Thomas l’a déjà dit):

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

Les nouvelles versions de mount (util-linux> = 2.27) le font automatiquement quand on exécute

mount SRC DST -o bind,ro
V13
la source
3
Oui mais non. IIRC prend en charge dans le noyau des options différentes pour différents points de montage (pas des systèmes de fichiers). Debian possédait un patch qui permettait de mount -o bind,rocréer une vue en lecture seule d’un système de fichiers en lecture-écriture (mais cela ne semble plus être présent dans Wheezy).
Gilles 'SO- arrête d'être méchant'
Je ne vois pas comment cela contredit ce qui précède. Les hack peuvent permettre toutes sortes de choses, y compris des choses qui n'ont pas beaucoup de sens. Actuellement, le remontage en lecture seule sur le noyau 3.14 est finalement pris en charge par cet appel: mnt_make_readonly (real_mount (mnt)), qui, comme vous pouvez le voir, utilise real_mount (), ce qui a donc une incidence sur le montage réel et entraîne des montages de liaisons reflétant le nouveau (lecture seule) indicateur de montage. Au moins c'est ce que j'ai compris.
V13
Cela serait donc une conséquence du correctif «spread struct mount» (plus précisément de ce commit ), apparaissant pour la première fois dans le noyau 3.3. Savez-vous si les conséquences de ce patch ont été discutées sur lkml ou lwn?
Gilles 'SO- arrête d'être méchant'
7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... touch /tmp/aest OK, mais touch /mnt/tmp/bdonne touch: cannot touch ‘/mnt/tmp/b’: Read-only file system. Cela fonctionne à la fois sur Debian 3.13 et sur kernel.org 3.14.2. Donc, cela ne change pas simplement la monture entière. Du moins pas avec les noyaux récents.
derobert
1
Vraisemblablement, l'affirmation selon laquelle "un montage lié est simplement ... bien ... un montage lié". est vraiment important mais ne signifie rien pour moi. Je ne comprends pas non plus pourquoi cela fonctionne la deuxième fois avec l'option de remontage.
StrongBad
9

La bonne solution est vraiment de le monter deux fois. Sur la ligne de commande:

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

Dans /etc/fstab:

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

Le manuel ( man mount) le dit comme suit:

   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
la source
Cela semble fonctionner avec au moins Ubuntu 14.04 LTS et le noyau 3.19.0-51-lowlatency. Agréable!
Mikko Rantalainen
0

Vous demandez du point de vue de la mount(8)ligne de commande (ce qui est acceptable sur ce site). Cette commande a été discutée dans les autres réponses et, dans certains cas, fait abstraction du deuxième mount(2)appel système nécessaire .

Mais pourquoi le second appel système est-il nécessaire? Pourquoi un seul mount(2)appel ne peut-il pas créer le montage de liaison en lecture seule?

La mount(2)page de manuel explique qu'il existe, comme d'autres l'ont souligné, deux ensembles de drapeaux définis:

  • Les indicateurs du système de fichiers sous-jacent
  • Les drapeaux de point de montage VFS

Ça dit:

Depuis Linux 2.6.16, vous MS_RDONLYpouvez définir ou effacer chaque point de montage, ainsi que le système de fichiers sous-jacent. Le système de fichiers monté ne sera accessible en écriture que si ni le système de fichiers ni le point de montage ne sont marqués en lecture seule.

Et concernant MS_REMOUNT:

Depuis Linux 2.6.26, cet indicateur peut être utilisé avec MS_BINDpour modifier uniquement les indicateurs par point de montage. Ceci est particulièrement utile pour définir ou effacer l'indicateur "lecture seule" sur un point de montage sans modifier le système de fichiers sous-jacent. Spécification de mountflags comme:

      MS_REMOUNT | MS_BIND | MS_RDONLY

rendra l'accès via ce point de montage en lecture seule, sans affecter les autres points de montage.

Je pense que le problème est survenu lorsque les montages Bind ont été introduits pour la première fois:

Si mountflags inclut MS_BIND(disponible depuis Linux 2.4), effectuez un montage lié . ... Les bits restants dans l'argument mountflags sont également ignorés, à l'exception de MS_REC. (Le montage lié possède les mêmes options de montage que le point de montage sous-jacent.)

Il semble que, au lieu d'utiliser MS_BIND | MS_REMOUNTcomme signal pour définir uniquement les indicateurs VFS, ils auraient pu choisir d'exclure (et d'accepter) MS_RDONLYavec l'initiale MS_BINDet de l'appliquer au point de montage.

Donc, à cause de la sémantique quelque peu étrange de l' mount(2)appel système:

  • Le premier appel crée le montage de liaison et tous les autres indicateurs sont ignorés
  • Le deuxième appel (avec remount) définit les indicateurs de point de montage en lecture seule.
Jonathon Reinhart
la source