start massaging the checks in sget_...(): move to sget_userns()
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 12 May 2019 17:18:42 +0000 (13:18 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 25 May 2019 21:59:55 +0000 (17:59 -0400)
there are 3 remaining callers of sget_userns() - sget(), mount_ns()
and mount_pseudo_xattr().  Extra check in sget() is conditional
upon mount being neither KERNMOUNT nor SUBMOUNT, the identical one
in mount_ns() - upon being not KERNMOUNT; mount_pseudo_xattr()
has no such checks at all.

However, mount_ns() is never used with SUBMOUNT and mount_pseudo_xattr()
is used only for KERNMOUNT, so both would be fine with the same logics
as currently done in sget(), allowing to consolidate the entire thing
in sget_userns() itself.

That's not where these checks will end up in the long run, though -
the whole reason why they'd been done so deep in the bowels of
mount(2) was that there had been no way for a filesystem to specify
which userns to look at until it has entered ->mount().

Now there is a place where filesystem could override the defaults -
->init_fs_context().  Which allows to pull the checks out into
the callers of vfs_get_tree().  That'll take quite a bit of
massage, but that mess is possible to tease apart.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/super.c

index 2739f57515f81d8fad4bc4edc83d4c98773308d9..9c371a04e1b64d57305fa4eb20529c07a9316310 100644 (file)
@@ -583,6 +583,10 @@ struct super_block *sget_userns(struct file_system_type *type,
        struct super_block *old;
        int err;
 
+       /* Ensure the requestor has permissions over the target filesystem */
+       if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
+               return ERR_PTR(-EPERM);
+
        if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) &&
            !(type->fs_flags & FS_USERNS_MOUNT) &&
            !capable(CAP_SYS_ADMIN))
@@ -653,10 +657,6 @@ struct super_block *sget(struct file_system_type *type,
        if (flags & SB_SUBMOUNT)
                user_ns = &init_user_ns;
 
-       /* Ensure the requestor has permissions over the target filesystem */
-       if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
-
        return sget_userns(type, test, set, flags, user_ns, data);
 }
 
@@ -1164,12 +1164,6 @@ struct dentry *mount_ns(struct file_system_type *fs_type,
 {
        struct super_block *sb;
 
-       /* Don't allow mounting unless the caller has CAP_SYS_ADMIN
-        * over the namespace.
-        */
-       if (!(flags & SB_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
-
        sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags,
                         user_ns, ns);
        if (IS_ERR(sb))