EPERM beim Formatieren eines Blockgeräts auf einem FUSE-Dateisystem

EPERM beim Formatieren eines Blockgeräts auf einem FUSE-Dateisystem

Kurz zusammengefasst

Der Versuch, ein Blockgerät auf meinem FUSE-Dateisystem zu formatieren, schlägt EPERMbeim openSystemaufruf fehl. Die Berechtigungen sind auf777und die notwendigen ioctls werden gestubbt, aber es werden keine Protokolle aus dem FUSE-Handler gedruckt.

Hintergrund

Ich schreibe ein Programm zum Erstellen virtueller Disk-Images. Eines meiner Kriterien ist, dass es ohne Superuser-Zugriff ausgeführt werden kann, d. h. ich kann keine Loopback-Geräte mounten, keine Besitzer von Dateien ändern oder sogar bearbeiten./etc/fuse.conf. Aus diesem Grund ist mein Ansatz am Ende ziemlich umständlich. Insbesondere möchte ich zum Formatieren der verschiedenen Partitionen auf der Festplatte Systemtools verwenden können, da mir dies eine viel größere Auswahl an möglichen Dateisystemen bietet. Dies beinhaltet das Offenlegen der verschiedenen Partitionen auf der VDisk als Blockgeräte für das System. Alle möglichen Methoden, die ich gefunden habe, erforderten jedoch entweder nbdS- oder Loopback-Geräte. Für beide ist Superuser-Zugriff erforderlich.

FUSE selbst implementieren

Die Implementierung von Blockgeräten in FUSE ist jedoch nicht nur möglich, sondern wird auch unterstützt. Leider konnte ich nicht viel Dokumentation zu diesem Thema finden und da ich das alles in Rust mache, ist die Dokumentation dazu noch spärlicher.

Ich habe die folgenden FUSE-Methoden implementiert:

  • init
  • lookup
  • getattr
  • open
  • read
  • write
  • readdir
  • ioctl
    • BLKGETSIZE
    • BLKFLSBUF
    • BLKSSZGET

Ich kann den Inhalt des Dateisystems auflisten und Verzeichnis-/Dateiinformationen abrufen. Ich ignoriere bewusst Methoden, die Ressourcen erstellen oder ändern, da dies über den Build-Prozess erfolgt.

Der Fehler

Wie gesagt, ich bekommeZugriff verweigert( EPERM) Fehler. straceDie Ausführung des mkfsAufrufs zeigt, dass der openAufruf des Blockgeräts auf der Kernelseite fehlschlägt.Vollständiges straceErgebnis.

execve("/usr/sbin/mkfs.fat", ["mkfs.fat", "out/partitions/EFI"], 0x7ffd42f64ab8 /* 76 vars */) = 0

    --- snip ---

openat(AT_FDCWD, "out/partitions/EFI", O_RDWR|O_EXCL) = -1 EACCES (Permission denied)
write(2, "mkfs.fat: unable to open out/par"..., 63mkfs.fat: unable to open out/partitions/EFI: Permission denied
) = 63
exit_group(1)                           = ?

Der Übersichtlichkeit halber sieht meine Verzeichnisstruktur folgendermaßen aus:

out
├── minimal.qcow2 [raw disk image] (shadows minimal.qcow2 [qcow2 file] with qemu-storage-daemon)
├── partitions
│   ├── EFI [Block device]
│   └── System [Block device]
└── qemu-monitor.sock [UNIX domain socket]

Natürlich gibt es Protokollierungsfunktionen, die jede Methode verfolgen. Ich sehe Protokolle, wenn ich die Partitionen aufliste, aber nicht beim Formatieren.

Wie bereits erwähnt, habe ich nur sehr wenig Dokumentation darüber gefunden, was diesen Fehler tatsächlich verursachen könnte.

Weitere Einblicke

Dank der Erkenntnisse von @orenkishon habe ich noch weitere Details herausgefunden, die mich einfach verblüffen.

  1. Ich habe einige fuserinteressante Optionen gefunden:

    • MountOption::Dev Aktivieren Sie Sonderzeichen und blockieren Sie Geräte
    • MountOption::DefaultPermission Aktivieren Sie die Berechtigungsprüfung im Kernel
    • MountOption::RW Lese-/Schreibdateisystem(offenbar keine Standardoption)

    Leider konnte mein Problem durch keine dieser Kombinationen gelöst werden.

  2. Protokollfunktionen werden nicht sofort aufgerufen. Sie scheinen an eine Art Leerungsvorgang gebunden zu sein. Ich kann den mkfs.fatBefehl ausführen, ein oder zwei Protokolle sehen, zu meiner IDE zurückkehren und eine Seite mit Protokollen sehen.

    Dies kann daran liegen, dass sich das Verzeichnis, in dem ich die Dateien erstelle, im Verzeichnis des Projekts befindet und daher für die IDE sichtbar ist, aber mir kommt es sehr ungewöhnlich vor.

  3. Das Protokoll accessist in der Funktion nie sichtbar, in der statfsFunktion jedoch schon, allerdings nur, wenn es von außerhalb des Verzeichnisses mkfsaufgerufen wirdoutUndist der erste aller mkfsAnrufe.

    project > cd ./out
    project/out > mkfs.fat partitions/EFI
    mkfs.fat 4.2 (2021-01-31)
    mkfs.fat: unable to open partitions/EFI: Permission denied
    
    # No logs
    
    project > mkfs.fat out/partitions/EFI
    mkfs.fat 4.2 (2021-01-31)
    mkfs.fat: unable to open out/partitions/EFI: Permission denied
    
    # No logs
    project > cargo run ...
    project > mkfs.fat out/partitions
    mkfs.fat 4.2 (2021-01-31)
    mkfs.fat: unable to open out/partitions/EFI: Permission denied
    
    # Logs appear after switching to IDE
    
  1. Diese Protokollnachricht sehe ich heute zum ersten Mal:
[2024-04-21T16:58:24Z DEBUG fuser::mnt::fuse_pure] fusermount: 
[2024-04-21T16:58:24Z DEBUG fuser::mnt::fuse_pure] fusermount: fusermount3: unsafe option dev ignored

Es gibt ein MountOption::Devspepcified, das angeblich Unterstützung für Block- und Zeichengeräte bietet. Ich kann mir jedoch nicht erklären, warum es abgelehnt wird. Ich hatte gehofft, dass ich eine gepatchte Version verwenden könnte, libfuse3aber anscheinend ist das nicht der Fall.

Zusätzliche Informationen, die nützlich sein könnten

System-Spezifikationen

Direkt aus den KDE-Systeminformationen kopiert

  • Betriebssystem: Kubuntu 23.10
  • KDE Plasma Version: 5.27.8
  • KDE Frameworks Version: 5.110.0
  • Qt-Version: 5.15.10
  • Kernel-Version: 6.5.0-28-generic (64-Bit)
  • Grafikplattform: Wayland
  • Prozessoren: 32 × Intel® Core™ i9-13900 der 13. Generation
  • Speicher: 31,1 GiB RAM
  • Grafikprozessor: AMD Radeon RX 7900 XT
  • Hersteller: ASUS

Auch allgemeine Schreibvorgänge schlagen fehl

Ein Vorschlag war, zu prüfen, ob mkfsein Fehler auftritt, wenn fat32das Blockgerät nicht unterstützt wird. Dies scheint jedoch nicht der Fall zu sein, da die Formatierung mit jedem anderen Dateisystem dieselben Ergebnisse liefert.

Ich verwende es auch mkfsals Testplattform, da mir derzeit keine anderen leicht verfügbaren Systemdienstprogramme bekannt sind, die direkt auf Blockgeräte schreiben, und mkfses ist etwas, das ich ohnehin verwenden möchte.

Schlechte Nachrichten :(

Beim Lesen der Manpages stieß ich aufdieser Absatzwas mir das Herz schwer machte:

Die meisten der in mount beschriebenen allgemeinen Mount-Optionen werden unterstützt (ro, rw, suid, nosuid, dev, nodev, exec, noexec, atime, noatime, sync, async, dirsync). Dateisysteme werden standardmäßig mit nodev,nosuid gemountet, was nur von einem privilegierten Benutzer überschrieben werden kann.

Es sieht also so aus, als ob das nicht möglich ist. Trotzdem wäre ich für alle Erkenntnisse hier – jeden Hoffnungsschimmer – sehr dankbar.

Antwort1

Wenn ich das richtig verstehe, legen Sie über Ihr FUSE-Dateisystem eine Blocksicherung frei, die aus Sicherheitsgründen nicht funktioniert.

In Unix-ähnlichen Systemen sind Dateien viel mehr als nur Dateien. Es ist problematisch, einem nicht privilegierten Benutzer das Erstellen beliebiger Blockgeräte zu erlauben, da das System durch die Erstellung eines Blockgeräts, das dem Rootfs-Gerät entspricht, kompromittiert werden kann.

Sie sollten sich ansehen, was das Programm fakerootmacht. Es hakt sich in jede libcFunktion ein, die von dem Programm verwendet wird, das Sie darunter ausführen. Immer wenn ein Vorgang rootausgeführt wird, der Zugriff erfordert (z. B. das Erstellen eines Geräts), wird der Vorgang aufgezeichnet. Später fakerootwird die Existenz der verbotenen Datei vorgetäuscht.

Da Sie nur die Partitionen freigeben möchten, können Sie einen ähnlichen Ansatz wählen und einige der ioctlDateien auf Ihrem gefälschten Gerät fälschen, während es sich in Wirklichkeit nur um eine normale Datei handelt. Ich bin nicht sicher, ob das hilft, aber es ist gut, dies im Hinterkopf zu behalten.

verwandte Informationen