Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote: > The unix semantics are that credentials are checked at open time. Sigh. The problem is that there's more than one actual "open" involved. fd = fsopen("ext4"); <--- #1 whatever_interface(fd, "s /dev/sda1"); whatever_interface(fd, "o journal_path=/dev/sda2"); do_the_create_thing(fd); <--- #2 and #3 The initial check to see whether you can mount or not is done at #1. But later there are two nested file opens. Internally, deep down inside the block layer, /dev/sda1 and /dev/sda2 are opened and further permissions checks are done, whether you like it or not. But these have no access to the creds attached to fd as things currently stand. So we have three choices: (1) Pass the creds from ->get_tree() all the way down into pathwalk and make sure *every* check that pathwalk does uses it. (2) When do_the_create_thing() is invoked, it wraps the call to ->get_tree() with override_creds(file->f_cred). (3) Forget using an fd to refer to the context. fsopen() takes absolutely everything, perhaps as a kv array and spits out an O_PATH fd. You don't get improved error reporting, you don't get a chance for interaction - say with the server, to construct an ID mapping table - and you don't get the chance to query the superblock before creating a mount. So, something like: struct fsopen_param { unsigned int type, const char *key; const void *val; unsigned int val_len; }; mfd = fsopen(const char *fs_type, unsigned int flags, /* CLOEXEC */ const struct fsopen_param *params, unsigned int param_count, unsigned int ms_flags /* eg. MNT_NOEXEC */); For example: struct fsopen_param params[] = { { fsopen_source, "dev.fs", "/dev/sda1" } { fsopen_source, "dev.journal", "/dev/sda2" } { fsopen_option, "user_xattr" } { fsopen_option, "data", "journal" } { fsopen_option, "jqfmt", "vfsv1" } { fsopen_security, "selinux.context", "unconfined_u..." } }; mfd = fsopen("ext4", FSOPEN_CLOEXEC, params, ARRAY_SIZE(params), MNT_NOEXEC); There would need to be an fsreconfig() also in a similar vein. David