
Kurz zusammengefasst
Der Versuch, ein Blockgerät auf meinem FUSE-Dateisystem zu formatieren, schlägt EPERM
beim open
Systemaufruf fehl. Die Berechtigungen sind auf777und die notwendigen ioctl
s 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 nbd
S- 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. strace
Die Ausführung des mkfs
Aufrufs zeigt, dass der open
Aufruf des Blockgeräts auf der Kernelseite fehlschlägt.Vollständiges strace
Ergebnis.
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.
Ich habe einige
fuser
interessante Optionen gefunden:MountOption::Dev
Aktivieren Sie Sonderzeichen und blockieren Sie GeräteMountOption::DefaultPermission
Aktivieren Sie die Berechtigungsprüfung im KernelMountOption::RW
Lese-/Schreibdateisystem(offenbar keine Standardoption)
Leider konnte mein Problem durch keine dieser Kombinationen gelöst werden.
Protokollfunktionen werden nicht sofort aufgerufen. Sie scheinen an eine Art Leerungsvorgang gebunden zu sein. Ich kann den
mkfs.fat
Befehl 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.
Das Protokoll
access
ist in der Funktion nie sichtbar, in derstatfs
Funktion jedoch schon, allerdings nur, wenn es von außerhalb des Verzeichnissesmkfs
aufgerufen wirdout
Undist der erste allermkfs
Anrufe.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
- 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::Dev
spepcified, 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, libfuse3
aber 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 mkfs
ein Fehler auftritt, wenn fat32
das 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 mkfs
als Testplattform, da mir derzeit keine anderen leicht verfügbaren Systemdienstprogramme bekannt sind, die direkt auf Blockgeräte schreiben, und mkfs
es 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 fakeroot
macht. Es hakt sich in jede libc
Funktion ein, die von dem Programm verwendet wird, das Sie darunter ausführen. Immer wenn ein Vorgang root
ausgeführt wird, der Zugriff erfordert (z. B. das Erstellen eines Geräts), wird der Vorgang aufgezeichnet. Später fakeroot
wird 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 ioctl
Dateien 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.