長い話を短く
FUSEファイルシステムでブロックデバイスをフォーマットしようとすると、システムコールがEPERM
失敗しました。open
権限は次のように設定されます。777話必要なioctl
sはスタブされますが、FUSEハンドラ内にログは印刷されません。
背景
仮想ディスクイメージを作成するプログラムを作成しています。私の基準の1つは、スーパーユーザーアクセスがまったくない状態で実行できる必要があることでした。つまり、ループバックデバイスをインストールできず、ファイル所有者を変更できず、編集することもできませんでした。/etc/fuse.conf。このため、私のアプローチは結局非常に冗長になりました。特に、ディスクの個々のパーティションをフォーマットするには、システムツールを使用したいと思います。これは、可能なファイルシステムの範囲がより広くなるためです。これには、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に戻り、表示されたログページを表示できます。ファイルを生成するディレクトリがプロジェクトディレクトリ内にあり、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
ブロックおよび文字デバイスのサポートを追加すると推定される特定のデバイスが1つあります。しかし、なぜ拒否されたのかを説明することはできません。パッチ版が使えばいいのにlibfuse3
そうではないようです。
便利な追加情報
システム仕様
KDEのシステム情報から直接コピー
- オペレーティングシステム:Kubuntu 23.10
- KDEプラズマバージョン:5.27.8
- KDEフレームワークバージョン:5.110.0
- Qtバージョン:5.15.10
- カーネルバージョン:6.5.0-28-typ(64ビット)
- グラフィックプラットフォーム: Wayland
- プロセッサー: 32 13世代 Intel® Core™ i9-13900
- メモリ:31.1GiB RAM
- グラフィックプロセッサ:AMD Radeon RX 7900 XT
- メーカー: ASUS
通常の書き込み操作も失敗します。
1つの提案は、ブロックデバイスがサポートされていないと失敗することを確認することです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
実際には通常のファイルである偽のデバイスからいくつかのパーティションを偽にすることができます。これが役に立つかどうかはわかりませんが、覚えておくことをお勧めします。