summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-08-08 22:37:37 +0300
committerEric W. Biederman <ebiederm@xmission.com>2016-08-31 15:28:35 +0300
commit537f7ccb396804c6d0057b93ba8eb104ba44f851 (patch)
tree0fbb44ee9bb13aed8c9e3fedede97c07dcf2a4da
parent703286608a220d53584cca5986aad5305eec75ed (diff)
downloadlinux-537f7ccb396804c6d0057b93ba8eb104ba44f851.tar.xz
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.h1
-rw-r--r--fs/namespace.c22
-rw-r--r--include/linux/user_namespace.h1
-rw-r--r--kernel/ucount.c1
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"),
{ }
};