FUSE 文件系统查看保存的 UID/GID?

FUSE 文件系统查看保存的 UID/GID?

在尝试创建一个在以普通用户身份启动程序然后以 root 用户身份启动程序之前读取某些配置的程序时,我注意到了这种奇怪的行为。我似乎在其他地方找不到提及它。普通文件系统使用有效 UID/GID 进行访问检查,但看起来 FUSE 似乎检查所有三个有效、真实和已保存(!!) UID/GID 进行访问。我最初只是删除了有效的 uid,以便稍后恢复它,但这让我不断收到权限错误,直到我意识到发生了什么。

为什么会出现这样的情况呢?为什么FUSE关心保存的uid/gid?

(我知道我可以设置allow_rootFUSE 并避免这种情况,这不是这个问题的目的)

用于演示的示例 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;
}

相关内容