通常のユーザーとしてプログラムを起動し、ルートとしてプログラムを開始する前に、いくつかの構成を読み取るプログラムを作成しようとしたときに、この奇妙な動作が見つかりました。他の場所では言及が見つからないようです。通常のファイルシステムはアクセス確認に有効なUID / GIDを使用しますが、FUSEはアクセスに有効で実際で保存されている(!!)3つのUID / GIDをすべて確認しているようです。最初は、後で復元できるように有効なuidを削除しましたが、何が起こっているのかがわかるまで権限エラーが発生し続けました。
なぜそのような状況がありますか? FUSEが保存されたuid / gidに興味があるのはなぜですか?
(FUSEを設定しallow_root
てこれを回避できることを知っています。これはこの質問の目的ではありません。)
デモ用サンプルCコード:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define measure() getresuid(&ruid, &euid, &suid); getresgid(&rgid, &egid, &sgid); printf("UID: %4d, %4d, %4d. GID: %4d, %4d, %4d \t\t", ruid, euid, suid, rgid, egid, sgid); fflush(stdout)
#define set(r,e,s) if (setresuid(0,0,0 ) != 0) return 1; if (setresgid(r,e,s ) != 0) return 1; if (setresuid(r, e, s) != 0) return 1;
#define attempt(r,e,s) set(r,e,s); measure(); test(argv[1])
void test(char* arg)
{
struct stat sb;
if (stat(arg, &sb) == -1)
perror("fail");
else
printf("Success\n");
}
int main(int argc, char *argv[])
{
uid_t ruid, euid, suid; gid_t rgid, egid, sgid;
measure();
printf("\n\n");
attempt(1000,0,0); // Expect: Fail. Actual: Fail
attempt(0, 1000,0); // Expect: ok. Actual: Fail
attempt(0, 0, 1000); // Expect: Fail. Actual: Fail
attempt(1000,1000,0); // Expect: ok. Actual: Fail
attempt(1000,0,1000); // Expect: Fail. Actual: Fail
attempt(0,1000,1000); // Expect: ok. Actual: Fail
attempt(1000,1000,1000); // Expect: ok. Actual: ok
return 0;
}
出力:
$ sshfs some-other-machine:/ /tmp/testit # I think any FUSE filesystem should "work"
$ gcc test.c -o test
$ sudo ./test /tmp/testit
UID: 0, 0, 0. GID: 0, 0, 0
UID: 1000, 0, 0. GID: 1000, 0, 0 fail: Permission denied
UID: 0, 1000, 0. GID: 0, 1000, 0 fail: Permission denied
UID: 0, 0, 1000. GID: 0, 0, 1000 fail: Permission denied
UID: 1000, 1000, 0. GID: 1000, 1000, 0 fail: Permission denied
UID: 1000, 0, 1000. GID: 1000, 0, 1000 fail: Permission denied
UID: 0, 1000, 1000. GID: 0, 1000, 1000 fail: Permission denied
UID: 1000, 1000, 1000. GID: 1000, 1000, 1000 Success
$
答え1
ご存知のように、 allow_root
/allow_other
オプションがないと、他のプロセスはファイルシステムにアクセスできません。これはファイルシステムを保護するのではなく、他のプロセスを保護するためのものです。したがって、アクセスプロセス中に他のアイデンティティへのヒントが少しでも、アクセスは許可されません。
以下は、この動作に関連するカーネルのコードです(fs/fuse/dir.c
)。
/*
* Calling into a user-controlled filesystem gives the filesystem
* daemon ptrace-like capabilities over the current process. This
* means, that the filesystem daemon is able to record the exact
* filesystem operations performed, and can also control the behavior
* of the requester process in otherwise impossible ways. For example
* it can delay the operation for arbitrary length of time allowing
* DoS against the requester.
*
* For this reason only those processes can call into the filesystem,
* for which the owner of the mount has ptrace privilege. This
* excludes processes started by other users, suid or sgid processes.
*/
int fuse_allow_current_process(struct fuse_conn *fc)
{
const struct cred *cred;
if (fc->allow_other)
return current_in_userns(fc->user_ns);
cred = current_cred();
if (uid_eq(cred->euid, fc->user_id) &&
uid_eq(cred->suid, fc->user_id) &&
uid_eq(cred->uid, fc->user_id) &&
gid_eq(cred->egid, fc->group_id) &&
gid_eq(cred->sgid, fc->group_id) &&
gid_eq(cred->gid, fc->group_id))
return 1;
return 0;
}