Commit a6435940 authored by Christian Brauner's avatar Christian Brauner

mount: attach mappings to mounts

In order to support per-mount idmappings vfsmounts are marked with user
namespaces. The idmapping of the user namespace will be used to map the
ids of vfs objects when they are accessed through that mount. By default
all vfsmounts are marked with the initial user namespace. The initial
user namespace is used to indicate that a mount is not idmapped. All
operations behave as before.

Based on prior discussions we want to attach the whole user namespace
and not just a dedicated idmapping struct. This allows us to reuse all
the helpers that already exist for dealing with idmappings instead of
introducing a whole new range of helpers. In addition, if we decide in
the future that we are confident enough to enable unprivileged users to
setup idmapped mounts the permission checking can take into account
whether the caller is privileged in the user namespace the mount is
currently marked with.
Later patches enforce that once a mount has been idmapped it can't be
remapped. This keeps permission checking and life-cycle management
simple. Users wanting to change the idmapped can always create a new
detached mount with a different idmapping.

Add a new mnt_userns member to vfsmount and two simple helpers to
retrieve the mnt_userns from vfsmounts and files.

The idea to attach user namespaces to vfsmounts has been floated around
in various forms at Linux Plumbers in ~2018 with the original idea
tracing back to a discussion in 2017 at a conference in St. Petersburg
between Christoph, Tycho, and myself.

Link: https://lore.kernel.org/r/20210121131959.646623-2-christian.brauner@ubuntu.com
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 19c329f6
...@@ -210,6 +210,7 @@ static struct mount *alloc_vfsmnt(const char *name) ...@@ -210,6 +210,7 @@ static struct mount *alloc_vfsmnt(const char *name)
INIT_HLIST_NODE(&mnt->mnt_mp_list); INIT_HLIST_NODE(&mnt->mnt_mp_list);
INIT_LIST_HEAD(&mnt->mnt_umounting); INIT_LIST_HEAD(&mnt->mnt_umounting);
INIT_HLIST_HEAD(&mnt->mnt_stuck_children); INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
mnt->mnt.mnt_userns = &init_user_ns;
} }
return mnt; return mnt;
...@@ -547,6 +548,11 @@ int sb_prepare_remount_readonly(struct super_block *sb) ...@@ -547,6 +548,11 @@ int sb_prepare_remount_readonly(struct super_block *sb)
static void free_vfsmnt(struct mount *mnt) static void free_vfsmnt(struct mount *mnt)
{ {
struct user_namespace *mnt_userns;
mnt_userns = mnt_user_ns(&mnt->mnt);
if (mnt_userns != &init_user_ns)
put_user_ns(mnt_userns);
kfree_const(mnt->mnt_devname); kfree_const(mnt->mnt_devname);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
free_percpu(mnt->mnt_pcp); free_percpu(mnt->mnt_pcp);
...@@ -1055,6 +1061,9 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, ...@@ -1055,6 +1061,9 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL); mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);
atomic_inc(&sb->s_active); atomic_inc(&sb->s_active);
mnt->mnt.mnt_userns = mnt_user_ns(&old->mnt);
if (mnt->mnt.mnt_userns != &init_user_ns)
mnt->mnt.mnt_userns = get_user_ns(mnt->mnt.mnt_userns);
mnt->mnt.mnt_sb = sb; mnt->mnt.mnt_sb = sb;
mnt->mnt.mnt_root = dget(root); mnt->mnt.mnt_root = dget(root);
mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_mountpoint = mnt->mnt.mnt_root;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/fs_types.h> #include <linux/fs_types.h>
#include <linux/build_bug.h> #include <linux/build_bug.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/mount.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <uapi/linux/fs.h> #include <uapi/linux/fs.h>
...@@ -2231,6 +2232,7 @@ struct file_system_type { ...@@ -2231,6 +2232,7 @@ struct file_system_type {
#define FS_HAS_SUBTYPE 4 #define FS_HAS_SUBTYPE 4
#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */
#define FS_DISALLOW_NOTIFY_PERM 16 /* Disable fanotify permission events */ #define FS_DISALLOW_NOTIFY_PERM 16 /* Disable fanotify permission events */
#define FS_ALLOW_IDMAP 32 /* FS has been updated to handle vfs idmappings. */
#define FS_THP_SUPPORT 8192 /* Remove once all fs converted */ #define FS_THP_SUPPORT 8192 /* Remove once all fs converted */
#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */
int (*init_fs_context)(struct fs_context *); int (*init_fs_context)(struct fs_context *);
...@@ -2517,6 +2519,10 @@ struct filename { ...@@ -2517,6 +2519,10 @@ struct filename {
}; };
static_assert(offsetof(struct filename, iname) % sizeof(long) == 0); static_assert(offsetof(struct filename, iname) % sizeof(long) == 0);
static inline struct user_namespace *file_mnt_user_ns(struct file *file)
{
return mnt_user_ns(file->f_path.mnt);
}
extern long vfs_truncate(const struct path *, loff_t); extern long vfs_truncate(const struct path *, loff_t);
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp); struct file *filp);
......
...@@ -72,8 +72,14 @@ struct vfsmount { ...@@ -72,8 +72,14 @@ struct vfsmount {
struct dentry *mnt_root; /* root of the mounted tree */ struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */ struct super_block *mnt_sb; /* pointer to superblock */
int mnt_flags; int mnt_flags;
struct user_namespace *mnt_userns;
} __randomize_layout; } __randomize_layout;
static inline struct user_namespace *mnt_user_ns(const struct vfsmount *mnt)
{
return mnt->mnt_userns;
}
struct file; /* forward dec */ struct file; /* forward dec */
struct path; struct path;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment