mntns: Add a limit on the number of mount namespaces.
authorEric W. Biederman <ebiederm@xmission.com>
Mon, 8 Aug 2016 19:37:37 +0000 (14:37 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Wed, 31 Aug 2016 12:28:35 +0000 (07:28 -0500)
v2: Fixed the very obvious lack of setting ucounts
    on struct mnt_ns reported by Andrei Vagin, and the kbuild
    test report.

Reported-by: Andrei Vagin <avagin@openvz.org>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/mount.h
fs/namespace.c
include/linux/user_namespace.h
kernel/ucount.c

index 14db05d..e037981 100644 (file)
@@ -10,6 +10,7 @@ struct mnt_namespace {
        struct mount *  root;
        struct list_head        list;
        struct user_namespace   *user_ns;
+       struct ucounts          *ucounts;
        u64                     seq;    /* Sequence number to prevent loops */
        wait_queue_head_t poll;
        u64 event;
index 7bb2cda..491b8f3 100644 (file)
@@ -2719,9 +2719,20 @@ dput_out:
        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)
 {
        ns_free_inum(&ns->ns);
+       dec_mnt_namespaces(ns->ucounts);
        put_user_ns(ns->user_ns);
        kfree(ns);
 }
@@ -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)
 {
        struct mnt_namespace *new_ns;
+       struct ucounts *ucounts;
        int ret;
 
+       ucounts = inc_mnt_namespaces(user_ns);
+       if (!ucounts)
+               return ERR_PTR(-ENFILE);
+
        new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
-       if (!new_ns)
+       if (!new_ns) {
+               dec_mnt_namespaces(ucounts);
                return ERR_PTR(-ENOMEM);
+       }
        ret = ns_alloc_inum(&new_ns->ns);
        if (ret) {
                kfree(new_ns);
+               dec_mnt_namespaces(ucounts);
                return ERR_PTR(ret);
        }
        new_ns->ns.ops = &mntns_operations;
@@ -2756,6 +2775,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
        init_waitqueue_head(&new_ns->poll);
        new_ns->event = 0;
        new_ns->user_ns = get_user_ns(user_ns);
+       new_ns->ucounts = ucounts;
        return new_ns;
 }
 
index c6bc980..30ffe10 100644 (file)
@@ -30,6 +30,7 @@ enum ucount_type {
        UCOUNT_UTS_NAMESPACES,
        UCOUNT_IPC_NAMESPACES,
        UCOUNT_NET_NAMESPACES,
+       UCOUNT_MNT_NAMESPACES,
        UCOUNT_CGROUP_NAMESPACES,
        UCOUNT_COUNTS,
 };
index 205f1a0..9d20d5d 100644 (file)
@@ -72,6 +72,7 @@ static struct ctl_table user_table[] = {
        UCOUNT_ENTRY("max_uts_namespaces"),
        UCOUNT_ENTRY("max_ipc_namespaces"),
        UCOUNT_ENTRY("max_net_namespaces"),
+       UCOUNT_ENTRY("max_mnt_namespaces"),
        UCOUNT_ENTRY("max_cgroup_namespaces"),
        { }
 };