diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2016-08-08 14:37:37 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-08-31 07:28:35 -0500 |
commit | 537f7ccb396804c6d0057b93ba8eb104ba44f851 (patch) | |
tree | 0fbb44ee9bb13aed8c9e3fedede97c07dcf2a4da | |
parent | 703286608a220d53584cca5986aad5305eec75ed (diff) |
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: Andrei Vagin <avagin@openvz.org>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | fs/mount.h | 1 | ||||
-rw-r--r-- | fs/namespace.c | 22 | ||||
-rw-r--r-- | include/linux/user_namespace.h | 1 | ||||
-rw-r--r-- | kernel/ucount.c | 1 |
4 files changed, 24 insertions, 1 deletions
diff --git a/fs/mount.h b/fs/mount.h index 14db05d424f7..e037981d8351 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -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; diff --git a/fs/namespace.c b/fs/namespace.c index 7bb2cda3bfef..491b8f3e4c9a 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -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; } diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index c6bc980b06a9..30ffe10cda18 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -30,6 +30,7 @@ enum ucount_type { UCOUNT_UTS_NAMESPACES, UCOUNT_IPC_NAMESPACES, UCOUNT_NET_NAMESPACES, + UCOUNT_MNT_NAMESPACES, UCOUNT_CGROUP_NAMESPACES, UCOUNT_COUNTS, }; diff --git a/kernel/ucount.c b/kernel/ucount.c index 205f1a07faac..9d20d5dd298a 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -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"), { } }; |