$ mkdir mnt
$ bindfs /tmp mnt
fusermount: option allow_other only allowed if 'user_allow_other' is set in /etc/fuse.conf
$ bindfs --no-allow-other /tmp mnt
$ mkdir /tmp/mnt2
$ bindfs --no-allow-other /tmp mnt/mnt2
fusermount: bad mount point /home/alan/mnt/mnt2: Permission denied
fusermount
他のユーザーとして実行しているため失敗します。
$ sudo ls mnt/
ls: cannot open directory 'mnt/': Permission denied
fusermount
set-uidですroot
。これはmount()
、権限のないユーザーがシステムコールを使用できないために必要です。
$ ls -l $(which fusermount)
-rwsr-xr-x. 1 root root 32848 Feb 7 2018 /usr/bin/fusermount
^ set-uid bit
しかし。 FUSEはNFSホームディレクトリ内で動作することが報告されています。ホームディレクトリにスキーマがある場合でも、700
所有しているユーザーだけがアクセスできます。 NFSサーバーはデフォルトでthisに設定されていますroot_squash
。これは、「root ユーザーはユーザー none と同じアクセス権を持ちます」を意味します。
この2つの状況はなぜ違うのですか?
Fedora 28でテスト中です。 NFS に関するレポートは Ubuntu 18.04 で提供されます。これらの分布は年齢によって非常に似ていますが、わずかな違いがあるかもしれません。
答え1
まず、FUSEの実装を検討してくださいno_allow_others
。
有効な実際のUID(ユーザーID)はすべて一致する必要があります。 (GIDも同様です。)これはset-UIDプログラムがマウントにアクセスするのを防ぐためです。
https://github.com/torvalds/linux/blob/v4.18/fs/fuse/dir.c#L1024
ユーザー制御ファイルシステムを呼び出すと、
ファイルシステムデーモンは現在のプロセスのptraceに似た機能を提供します。これは
、ファイルシステムデーモンが実行された正確なファイルシステム操作を記録し、
他の方法では不可能な方法でリクエスタプロセスの動作を制御できることを意味します。
たとえば、リクエスタに対してDoSを
許可して、一定時間操作を遅らせることができます。
fusermount
それでは、正確に行われた作業を追跡してみましょう。私たちは試してみることができます
strace -f bindfs ...
そして
sudo perf trace -o trace.txt -a sleep 2; sleep 1; bindfs ...
最初はset-UID rootが原因で致命的なエラー「Permission Denied」が発生しましたstrace
。 2番目は成功しましたが、パスなどの文字列パラメータを表示できませんでした。これら2つのトレースは、致命的なエラーが発生するまで同じ一般的なコードパスを示すようです。これはstrace
、結果を使用して欠落している文字列パラメータを埋めることができることを意味します。
結果の最後の呼び出しは次のstrace
とおりです。
[pid 30609] mount("/home/alan-sysop/mnt", ".", "fuse", MS_NOSUID|MS_NODEV, "default_permissions,fd=5,rootmod"...) = -1 EPERM (Operation not permitted)
興味深い! "."
現在のディレクトリを表します。したがって、fusermount
マウントポイントで実行されていたでしょう...何とか。このトリックは、絶対パスを使用して現在アクセスできないディレクトリにアクセスするために使用されることがあります。
上にスクロールすると、fusermount
そのディレクトリに変更されたことがわかります。また、一部のUID関連(およびGID関連)システムコールにもよく合います。
[pid 30609] getuid() = 1000
[pid 30609] setfsuid(1000) = 1000
[pid 30609] getgid() = 1000
[pid 30609] setfsgid(1000) = 1000
[pid 30609] openat(AT_FDCWD, "/etc/fuse.conf", O_RDONLY) = 6
...
[pid 30609] lstat("/home/alan-sysop/mnt", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
[pid 30609] getuid() = 1000
[pid 30609] chdir("/home/alan-sysop/mnt") = 0
[pid 30609] lstat(".", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
[pid 30609] access(".", W_OK) = 0
[pid 30609] getuid() = 1000
[pid 30609] setfsuid(1000) = 1000
[pid 30609] setfsgid(1000) = 1000
セッションのUIDが「無効」であることが判明しましたstrace
。セッションでUIDダンスの部分をよりよく見ることができますperf trace
。 (読みやすくするために一番左の列を削除しました。)
getuid( ) = 1000
setfsuid(uid: 1000 ) = 0
getgid( ) = 1000
setfsgid(gid: 1000 ) = 1000
openat(dfd: CWD, filename: 0xa428e2bc ) = 6
...
close(fd: 6 ) = 0
lstat(filename: 0xa63882a0, statbuf: 0x7ffe7bd4f6d0 ) = 0
getuid( ) = 1000
chdir(filename: 0xa63882a0 ) = 0
lstat(filename: 0xa428eca5, statbuf: 0x7ffe7bd4f6d0 ) = 0
access(filename: 0xa428eca5, mode: W ) = 0
getuid( ) = 1000
setfsuid( ) = 1000
setfsgid(gid: 1000 ) = 1000
getuid( ) = 1000
呼び出しはand関数にsetfsuid()
あります。drop_privs()
restore_privs()
ヒューズインストーラ。
呼び出しchdir()
はという関数にこっそり隠されていますcheck_perm()
。
結論として
これがNFSで動作するのはなぜですか?答え:NFSはルートではなくUIDに設定されているfsuid
項目を確認するためです。fsgid
FUSEがないとFUSEで機能しないのはなぜですかallow_others
?答え:FUSEは.UIDではなく「実際の」UIDをチェックするからですfsuid
。