Commit 537f7ccb authored by Eric W. Biederman's avatar Eric W. Biederman

mntns: Add a limit on the number of mount namespaces.

v2: Fixed the very obvious lack of setting ucounts
    on struct mnt_ns reported by Andrei Vagin, and the kbuild
    test report.
Reported-by: default avatarAndrei Vagin <avagin@openvz.org>
Acked-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 70328660
...@@ -10,6 +10,7 @@ struct mnt_namespace { ...@@ -10,6 +10,7 @@ struct mnt_namespace {
struct mount * root; struct mount * root;
struct list_head list; struct list_head list;
struct user_namespace *user_ns; struct user_namespace *user_ns;
struct ucounts *ucounts;
u64 seq; /* Sequence number to prevent loops */ u64 seq; /* Sequence number to prevent loops */
wait_queue_head_t poll; wait_queue_head_t poll;
u64 event; u64 event;
......
...@@ -2719,9 +2719,20 @@ long do_mount(const char *dev_name, const char __user *dir_name, ...@@ -2719,9 +2719,20 @@ long do_mount(const char *dev_name, const char __user *dir_name,
return retval; return retval;
} }
static struct ucounts *inc_mnt_namespaces(struct user_namespace *ns)
{
return inc_ucount(ns, current_euid(), UCOUNT_MNT_NAMESPACES);
}
static void dec_mnt_namespaces(struct ucounts *ucounts)
{
dec_ucount(ucounts, UCOUNT_MNT_NAMESPACES);
}
static void free_mnt_ns(struct mnt_namespace *ns) static void free_mnt_ns(struct mnt_namespace *ns)
{ {
ns_free_inum(&ns->ns); ns_free_inum(&ns->ns);
dec_mnt_namespaces(ns->ucounts);
put_user_ns(ns->user_ns); put_user_ns(ns->user_ns);
kfree(ns); kfree(ns);
} }
...@@ -2738,14 +2749,22 @@ static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); ...@@ -2738,14 +2749,22 @@ static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1);
static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
{ {
struct mnt_namespace *new_ns; struct mnt_namespace *new_ns;
struct ucounts *ucounts;
int ret; int ret;
ucounts = inc_mnt_namespaces(user_ns);
if (!ucounts)
return ERR_PTR(-ENFILE);
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns) if (!new_ns) {
dec_mnt_namespaces(ucounts);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
ret = ns_alloc_inum(&new_ns->ns); ret = ns_alloc_inum(&new_ns->ns);
if (ret) { if (ret) {
kfree(new_ns); kfree(new_ns);
dec_mnt_namespaces(ucounts);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
new_ns->ns.ops = &mntns_operations; new_ns->ns.ops = &mntns_operations;
...@@ -2756,6 +2775,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) ...@@ -2756,6 +2775,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
init_waitqueue_head(&new_ns->poll); init_waitqueue_head(&new_ns->poll);
new_ns->event = 0; new_ns->event = 0;
new_ns->user_ns = get_user_ns(user_ns); new_ns->user_ns = get_user_ns(user_ns);
new_ns->ucounts = ucounts;
return new_ns; return new_ns;
} }
......
...@@ -30,6 +30,7 @@ enum ucount_type { ...@@ -30,6 +30,7 @@ enum ucount_type {
UCOUNT_UTS_NAMESPACES, UCOUNT_UTS_NAMESPACES,
UCOUNT_IPC_NAMESPACES, UCOUNT_IPC_NAMESPACES,
UCOUNT_NET_NAMESPACES, UCOUNT_NET_NAMESPACES,
UCOUNT_MNT_NAMESPACES,
UCOUNT_CGROUP_NAMESPACES, UCOUNT_CGROUP_NAMESPACES,
UCOUNT_COUNTS, UCOUNT_COUNTS,
}; };
......
...@@ -72,6 +72,7 @@ static struct ctl_table user_table[] = { ...@@ -72,6 +72,7 @@ static struct ctl_table user_table[] = {
UCOUNT_ENTRY("max_uts_namespaces"), UCOUNT_ENTRY("max_uts_namespaces"),
UCOUNT_ENTRY("max_ipc_namespaces"), UCOUNT_ENTRY("max_ipc_namespaces"),
UCOUNT_ENTRY("max_net_namespaces"), UCOUNT_ENTRY("max_net_namespaces"),
UCOUNT_ENTRY("max_mnt_namespaces"),
UCOUNT_ENTRY("max_cgroup_namespaces"), UCOUNT_ENTRY("max_cgroup_namespaces"),
{ } { }
}; };
......
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