Warum respektiert mount die schreibgeschützte Option für Bindungsbereitstellungen nicht?

35

Auf meinem Arch Linux-System (Linux Kernel 3.14.2) beachten Bindungs-Mounts nicht die Option "Nur Lesen"

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

Erstellt die Datei /mnt/foo. Der relevante Eintrag in /proc/mountsist

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

Die Mount - Optionen meine gewünschten Optionen nicht übereinstimmen, aber sowohl das Verhalten Lese- / Schreib tun entsprechen des bind montieren und die Optionen verwendet , um ursprünglich zu montieren /dev/sda2auf/

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

Wenn ich den Mount jedoch erneut einbinde, wird die schreibgeschützte Option beachtet

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

und den entsprechenden Eintrag in /proc/mounts/

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

sieht aus wie das, was ich erwarten könnte (obwohl ich in Wahrheit erwarten würde, den vollständigen Pfad des testVerzeichnisses zu sehen). Der Eintrag in /proc/mounts/für das orignal mount von /dev/sda2/on /bleibt ebenfalls unverändert und schreibgeschützt

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

Dieses Verhalten und die Abhilfe sind seit mindestens 2008 bekannt und in der Manpage von dokumentiertmount

Beachten Sie, dass die Mount-Optionen für das Dateisystem dieselben bleiben wie für den ursprünglichen Mount-Punkt und nicht geändert werden können, indem Sie die Option -o zusammen mit --bind / - rbind übergeben. Die Mount-Optionen können durch einen separaten Remount-Befehl geändert werden

Nicht alle Distributionen verhalten sich gleich. Arch scheint stillschweigend die Optionen nicht zu respektieren, während Debian eine Warnung generiert, wenn der Bind-Mount nicht schreibgeschützt wird

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

Es gibt Berichte, dass dieses Verhalten in Debian Lenny und Squeeze "behoben" wurde, obwohl es anscheinend kein universeller Fix ist und auch in Debian Wheezy nicht funktioniert. Was ist das Schwierige, das damit verbunden ist, dass Bindungs-Mount die Nur-Lese-Option beim anfänglichen Mount respektiert?

StrongBad
quelle
Haben Sie eine / etc / mtab?
eyoung100
Siehe auch thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 und eine Problemumgehung mithilfe mount -t bindeines Hilfsskripts
Stéphane Chazelas
@ECarterYoung ja ich habe eine /etc/mtab. Nach dem ersten Mount lautet der Eintrag "rw" und nach dem erneuten Mount "ro", sodass der Status des Mount korrekt gemeldet wird. Es ist nur der Befehl mount, der fehlschlägt.
StrongBad
3
Ich habe auf zwei Debian-Test- / Unstable-Maschinen getestet, eine mit einem Debian-Kernel und eine mit einem kernel.org-Kernel, beide funktionieren nicht mount --bind -o ro, beide spucken eine Nachricht aus. mount: warning: «mountpoint» seems to be mounted read-write.Es scheint also, als wäre Debian irgendwann gefallen oder hätte den Patch verloren ... Remount funktioniert aber.
Derobert
2
@StrongBad Getestet, wie angefordert, und es funktioniert auch nicht.
Derobert

Antworten:

21

Bindemount ist nur ... na ja ... ein Bindemount. Dh es ist kein neues Reittier. Es wird lediglich "links" / "exposes" / "betrachtet" ein Unterverzeichnis als neuen Einhängepunkt. Daher können die Mount-Parameter nicht geändert werden. Deshalb bekommen Sie Beschwerden:

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

Aber wie Sie sagten, funktioniert ein normaler Bind Mount:

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

Und dann funktioniert auch ein Ro-Remount:

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

Was jedoch passiert, ist, dass Sie das gesamte Mount ändern und nicht nur dieses Bind-Mount. Wenn Sie sich / proc / mounts ansehen, werden Sie feststellen, dass sowohl das Bindungs-Mount als auch das Original-Mount schreibgeschützt sind:

/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

Sie ändern also das ursprüngliche Mount in ein schreibgeschütztes Mount und führen dann ein Bind-Mount durch, das natürlich schreibgeschützt ist.

UPDATE 20.07.2016:

Folgendes gilt für 4.5-Kernel, aber nicht für 4.3-Kernel (Dies ist falsch. Siehe Update 2 unten):

Der Kernel verfügt über zwei Flags, die schreibgeschützt sind:

  • The MS_READONLY: Gibt an, ob der Mount schreibgeschützt ist
  • Das MNT_READONLY: Gibt an, ob der "Benutzer" es schreibgeschützt haben möchte

Bei einem 4.5er-Kernel reicht ein mount -o bind,roWille aus. Zum Beispiel das:

# 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

erstellt ein schreibgeschütztes Bindungs-Mount von /tmp/test/a/dto /tmp/test/b, das wie folgt angezeigt wird /proc/mounts:

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

In wird eine detailliertere Ansicht angezeigt /proc/self/mountinfo, die die Benutzeransicht (Namespace) berücksichtigt. Die relevanten Zeilen sind diese:

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

Wo in der zweiten Zeile steht ro( MNT_READONLY) und rw( !MS_READONLY)?

Das Endergebnis ist folgendes:

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

UPDATE 20.07.2016 # 2:

Ein bisschen genaueres Hinsehen zeigt, dass das Verhalten tatsächlich von der Version von libmount abhängt, die Teil von util-linux ist. Die Unterstützung hierfür wurde mit diesem Commit hinzugefügt und mit Version 2.27 veröffentlicht:

Commit 9ac77b8a78452eab0612523d27fee52159f5016a
Urheber: Karel Zak 
Datum: Montag, 17. August, 11:54:26 Uhr 2015 +0200

    libmount: Unterstützung für "bind, ro" hinzufügen

    Jetzt müssen Sie nicht zwei mount (8) -Aufrufe verwenden, um einen Nur-Lese-Befehl zu erstellen
    montieren:

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

    Mit diesem Patch können Sie "bind, ro" angeben und die erneute Bereitstellung wird durchgeführt
    automatisch von libmount durch zusätzlichen mount (2) syscall. Es ist nicht
    natürlich atomar.

    Unterzeichnet von: Karel Zak 

das bietet auch die Problemumgehung. Das Verhalten kann mit strace auf einem älteren und einem neueren Mount beobachtet werden:

Alt:

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

Neu:

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>

Fazit:

Um das gewünschte Ergebnis zu erzielen, muss man zwei Befehle ausführen (wie @Thomas bereits sagte):

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

Neuere Versionen von mount (util-linux> = 2.27) machen dies automatisch, wenn man läuft

mount SRC DST -o bind,ro
V13
quelle
3
Ja aber nein. Im Kernel gibt es eine gewisse Unterstützung für verschiedene Einhängepunkte (nicht Dateisysteme), um verschiedene Optionen zu haben. Debian hatte früher einen Patch, mit dem mount -o bind,roeine Nur-Lese-Ansicht eines Lese-Schreib-Dateisystems erstellt wurde (aber es scheint nicht mehr in Wheezy zu sein).
Gilles 'SO- hör auf böse zu sein'
Ich verstehe nicht, inwiefern dies dem oben Gesagten widerspricht. Hacks können alle möglichen Dinge zulassen, auch Dinge, die wenig Sinn ergeben. Derzeit wird die schreibgeschützte erneute Bereitstellung auf dem 3.14-Kernel möglicherweise von diesem Aufruf behandelt: mnt_make_readonly (real_mount (mnt)). Wie Sie sehen können, wird real_mount () verwendet, wodurch die tatsächliche Bereitstellung praktisch beeinträchtigt wird und Bindungsbereitstellungen die neue widerspiegeln (schreibgeschütztes) Mount-Flag. Zumindest ist das mein Verständnis.
V13
Dies wäre eine Konsequenz des Patches "spread struct mount" (speziell dieses Commit ), der erstmals in Kernel 3.3 erscheint. Wissen Sie, ob die Konsequenzen dieses Patches auf lkml oder lwn diskutiert wurden?
Gilles 'SO- hör auf böse zu sein'
7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... dann touch /tmp/aist es OK, aber es touch /mnt/tmp/bgibt touch: cannot touch ‘/mnt/tmp/b’: Read-only file system. Das funktioniert sowohl unter Debian 3.13 als auch unter kernel.org 3.14.2. Es ändert also nicht nur die gesamte Montierung. Zumindest nicht mit neueren Kerneln.
Derobert
1
Vermutlich die Aussage, dass ein "Bind Mount nur ... na ja ... ein Bind Mount" ist. ist wirklich wichtig, bedeutet mir aber nichts. Ich verstehe auch nicht warum es dann das zweite mal mit der remount Option klappt.
StrongBad
9

Die richtige Lösung ist es wirklich, es zweimal zu montieren. In der Befehlszeile:

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

In /etc/fstab:

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

In manual ( man mount) heißt es so:

   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
quelle
Dies scheint mit mindestens Ubuntu 14.04 LTS und Kernel 3.19.0-51-lowlatency zu funktionieren. Nett!
Mikko Rantalainen
0

Sie fragen aus der Perspektive der mount(8)Befehlszeile (was auf dieser Site akzeptabel ist). Dieser Befehl wurde in den anderen Antworten besprochen und abstrahiert in einigen Fällen den erforderlichen zweiten mount(2)Systemaufruf.

Aber warum wird der zweite Systemaufruf benötigt? Warum kann ein einzelner mount(2)Aufruf das schreibgeschützte Bindungs-Mount nicht erstellen?

In der mount(2)Manpage wird erklärt, dass, wie andere betont haben, zwei Sätze von Flags gesetzt werden:

  • Die zugrunde liegenden Dateisystemflags
  • Die VFS-Mount-Point-Flags

Es sagt:

Seit Linux 2.6.16 MS_RDONLYkann es sowohl für einzelne Mountpunkte als auch für das zugrunde liegende Dateisystem festgelegt oder gelöscht werden. Das bereitgestellte Dateisystem kann nur beschrieben werden, wenn weder das Dateisystem noch der Bereitstellungspunkt als schreibgeschützt gekennzeichnet sind.

Und in Bezug auf MS_REMOUNT:

Seit Linux 2.6.26 kann dieses Flag verwendet werden MS_BIND, um nur die Per-Mount-Point-Flags zu ändern. Dies ist besonders nützlich, um das "Nur Lesen" -Flag auf einem Mount-Punkt zu setzen oder zu löschen, ohne das zugrunde liegende Dateisystem zu ändern. Angeben von Mountflags als:

      MS_REMOUNT | MS_BIND | MS_RDONLY

Der Zugriff über diesen Einhängepunkt ist schreibgeschützt, ohne dass andere Einhängepunkte betroffen sind.

Ich glaube, das Problem ist aufgetreten, als Bind-Mounts zum ersten Mal eingeführt wurden:

Wenn mountflags include enthält MS_BIND(verfügbar seit Linux 2.4), führen Sie einen Bind-Mount durch. ... Die verbleibenden Bits im Argument mountflags werden mit Ausnahme von auch ignoriert MS_REC. (Die Bindungsbereitstellung verfügt über dieselben Bereitstellungsoptionen wie der zugrunde liegende Bereitstellungspunkt.)

Es scheint, dass sie, anstatt MS_BIND | MS_REMOUNTnur die VFS-Flags als Signal zu verwenden, die Option hätten wählen können, MS_RDONLYzusammen mit der Initiale die Ausnahme (und Annahme) vorzunehmen MS_BINDund sie auf den Einhängepunkt anzuwenden.

Also wegen der etwas seltsamen Semantik des mount(2)Systemaufrufs:

  • Beim ersten Aufruf wird der Bind-Mount erstellt und alle anderen Flags werden ignoriert
  • Der zweite Aufruf (mit remount) setzt die Mount-Point- Flags auf schreibgeschützt
Jonathon Reinhart
quelle