
要約
FUSEファイルシステムでブロックデバイスをフォーマットしようとすると、システムコールで失敗しますEPERM
。open
権限は次のように設定されています。777必要なioctl
はスタブ化されますが、FUSE ハンドラー内からログは出力されません。
背景
私は仮想ディスクイメージを作成するプログラムを書いています。私の基準の1つは、スーパーユーザーアクセスなしで実行できることです。つまり、ループバックデバイスをマウントしたり、ファイルの所有者を変更したり、編集したりすることはできません。設定ファイルこのため、私のアプローチはかなり長ったらしいものになっています。具体的には、ディスク上のさまざまなパーティションをフォーマットするために、システム ツールを使用できるようにしたいのです。そうすることで、はるかに幅広いファイル システムが可能になるからです。これには、VDisk 上のさまざまなパーティションをブロック デバイスとしてシステムに公開することが含まれます。ただし、私が見つけたすべての可能な方法では、nbd
s またはループバック デバイスのいずれかが必要でした。どちらもスーパー ユーザー アクセスが必要です。
FUSEを自分で実装する
ただし、FUSE でブロック デバイスを実装することは可能であるだけでなく、サポートされています。残念ながら、この件に関するドキュメントはあまり見つかりませんでした。また、私はこれをすべて Rust で行っているため、この件に関するドキュメントはさらに不足しています。
以下の FUSE メソッドを実装しました。
init
lookup
getattr
open
read
write
readdir
ioctl
BLKGETSIZE
BLKFLSBUF
BLKSSZGET
ファイルシステムの内容を一覧表示し、ディレクトリ/ファイル情報を取得できます。リソースを作成または変更するメソッドはビルドプロセスを通じて実行されるため、意図的に無視しています。
エラー
前述したように、私は許可が拒否されました( EPERM
) エラー。呼び出しstrace
を実行すると、カーネル側でブロック デバイスへの呼び出しが失敗しているmkfs
ことがわかります。open
完全なstrace
結果。
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) = ?
わかりやすくするために、ディレクトリ構造は次のようになります。
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]
もちろん、すべてのメソッドをトレースするログ機能があります。パーティションをリストするときにはログが表示されますが、フォーマットするときにはログは表示されません。
前述したように、このエラーの実際の原因に関するドキュメントはほとんど見つかりませんでした。
さらなる洞察
@orenkishon の洞察のおかげで、私を困惑させる詳細をさらにいくつか見つけました。
fuser
興味深いオプションがいくつか見つかりました:MountOption::Dev
特殊文字とブロックデバイスを有効にするMountOption::DefaultPermission
カーネルでの権限チェックを有効にするMountOption::RW
読み書き可能なファイルシステム(どうやらデフォルトのオプションではないようです)
残念ながら、その組み合わせでは問題は解決しませんでした。
ログ関数はすぐには呼び出されません。何らかのフラッシュ操作に関連付けられているようです。コマンドを実行して
mkfs.fat
1 つまたは 2 つのログを確認し、IDE に戻ると 1 ページ分のログが表示されます。これは、ファイルを生成しているディレクトリがプロジェクトのディレクトリ内にあるため、IDE から見えるためである可能性がありますが、非常に異常なことのように思えます。
関数内のログ
access
は表示されませんが、関数内のログは表示されます。ただし、ディレクトリ外から呼び出されたstatfs
場合のみです。mkfs
out
そしてあらゆる通話の最初のものですmkfs
。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
- 今日は初めてこのログメッセージを見ました:
[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
ブロック デバイスと文字デバイスのサポートを追加すると思われる が指定されていますMountOption::Dev
。ただし、拒否される理由を説明できないようです。 のパッチ バージョンを使用できることを期待していましたlibfuse3
が、どうやらそうではないようです。
役に立つかもしれない追加情報
システム仕様
KDE のシステム情報から直接コピー
- オペレーティング システム: Kubuntu 23.10
- KDE プラズマ バージョン: 5.27.8
- KDE フレームワーク バージョン: 5.110.0
- バージョン: 5.15.10
- カーネル バージョン: 6.5.0-28-generic (64 ビット)
- グラフィックプラットフォーム: Wayland
- プロセッサー: 32 × 第 13 世代 Intel® Core™ i9-13900
- メモリ: 31.1 GiB の RAM
- グラフィックプロセッサ: AMD Radeon RX 7900 XT
- メーカー: ASUS
一般的な書き込み操作も失敗する
mkfs
ブロック デバイスをサポートしていない場合に失敗するかどうかを確認することが提案されましたfat32
。ただし、他のファイル システムでフォーマットしても同じ結果になるため、これは当てはまらないようです。
mkfs
また、ブロック デバイスに直接書き込む他のすぐに利用できるシステム ユーティリティを現在知らないため、テスト プラットフォームとしても使用していますmkfs
。いずれにしても、これを使用するつもりです。
悪いニュース :(
マンページを読んでいるときに、この段落それは私の心を沈ませました。
mount で説明されている一般的なマウント オプションのほとんどがサポートされています (ro、rw、suid、nosuid、dev、nodev、exec、noexec、atime、noatime、sync、async、dirsync)。ファイル システムは、デフォルトで nodev、nosuid を使用してマウントされますが、これは特権ユーザーによってのみ上書きできます。
したがって、これは不可能のようです。それでも、ここでの洞察、ほんのわずかな希望でも、大いに感謝いたします。
答え1
私の理解が正しければ、FUSE ファイルシステムを介してブロックデバイスを公開しますが、これはセキュリティ上の理由から機能しません。
Unix ライクなシステムでは、ファイルは単なるファイル以上のものです。権限のないユーザーに任意のブロック デバイスの作成を許可すると、rootfs デバイスに対応するブロック デバイスを作成することでシステムが危険にさらされる可能性があるため、問題があります。
プログラムが何をするか確認してみるといいでしょうfakeroot
。プログラムを実行するプログラムが使用するすべての関数をフックしますlibc
。アクセスを必要とする操作root
(デバイスの作成など) が行われるたびに、その操作が記録されます。後でfakeroot
禁止ファイルの存在を偽装します。
パーティションを公開したいだけなので、同様のアプローチを取り、ioctl
偽のデバイス上の一部の を偽装することができますが、実際にはそれは単なる通常のファイルです。これが役立つかどうかはわかりませんが、これを念頭に置いておくのは良いことです。