Commit 87a8ebd6 authored by Eric W. Biederman's avatar Eric W. Biederman

userns: Restrict when proc and sysfs can be mounted

Only allow unprivileged mounts of proc and sysfs if they are already
mounted when the user namespace is created.

proc and sysfs are interesting because they have content that is
per namespace, and so fresh mounts are needed when new namespaces
are created while at the same time proc and sysfs have content that
is shared between every instance.

Respect the policy of who may see the shared content of proc and sysfs
by only allowing new mounts if there was an existing mount at the time
the user namespace was created.

In practice there are only two interesting cases: proc and sysfs are
mounted at their usual places, proc and sysfs are not mounted at all
(some form of mount namespace jail).

Cc: stable@vger.kernel.org
Acked-by: default avatarSerge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent a636b702
...@@ -2763,6 +2763,27 @@ bool current_chrooted(void) ...@@ -2763,6 +2763,27 @@ bool current_chrooted(void)
return chrooted; return chrooted;
} }
void update_mnt_policy(struct user_namespace *userns)
{
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
struct mount *mnt;
down_read(&namespace_sem);
list_for_each_entry(mnt, &ns->list, mnt_list) {
switch (mnt->mnt.mnt_sb->s_magic) {
case SYSFS_MAGIC:
userns->may_mount_sysfs = true;
break;
case PROC_SUPER_MAGIC:
userns->may_mount_proc = true;
break;
}
if (userns->may_mount_sysfs && userns->may_mount_proc)
break;
}
up_read(&namespace_sem);
}
static void *mntns_get(struct task_struct *task) static void *mntns_get(struct task_struct *task)
{ {
struct mnt_namespace *ns = NULL; struct mnt_namespace *ns = NULL;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/user_namespace.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/parser.h> #include <linux/parser.h>
...@@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, ...@@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
} else { } else {
ns = task_active_pid_ns(current); ns = task_active_pid_ns(current);
options = data; options = data;
if (!current_user_ns()->may_mount_proc)
return ERR_PTR(-EPERM);
} }
sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/user_namespace.h>
#include "sysfs.h" #include "sysfs.h"
...@@ -111,6 +112,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, ...@@ -111,6 +112,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
struct super_block *sb; struct super_block *sb;
int error; int error;
if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
return ERR_PTR(-EPERM);
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -26,6 +26,8 @@ struct user_namespace { ...@@ -26,6 +26,8 @@ struct user_namespace {
kuid_t owner; kuid_t owner;
kgid_t group; kgid_t group;
unsigned int proc_inum; unsigned int proc_inum;
bool may_mount_sysfs;
bool may_mount_proc;
}; };
extern struct user_namespace init_user_ns; extern struct user_namespace init_user_ns;
...@@ -82,4 +84,6 @@ static inline void put_user_ns(struct user_namespace *ns) ...@@ -82,4 +84,6 @@ static inline void put_user_ns(struct user_namespace *ns)
#endif #endif
void update_mnt_policy(struct user_namespace *userns);
#endif /* _LINUX_USER_H */ #endif /* _LINUX_USER_H */
...@@ -51,6 +51,8 @@ struct user_namespace init_user_ns = { ...@@ -51,6 +51,8 @@ struct user_namespace init_user_ns = {
.owner = GLOBAL_ROOT_UID, .owner = GLOBAL_ROOT_UID,
.group = GLOBAL_ROOT_GID, .group = GLOBAL_ROOT_GID,
.proc_inum = PROC_USER_INIT_INO, .proc_inum = PROC_USER_INIT_INO,
.may_mount_sysfs = true,
.may_mount_proc = true,
}; };
EXPORT_SYMBOL_GPL(init_user_ns); EXPORT_SYMBOL_GPL(init_user_ns);
......
...@@ -96,6 +96,8 @@ int create_user_ns(struct cred *new) ...@@ -96,6 +96,8 @@ int create_user_ns(struct cred *new)
set_cred_user_ns(new, ns); set_cred_user_ns(new, ns);
update_mnt_policy(ns);
return 0; return 0;
} }
......
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