Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1448012 > unrolled thread
| Started by | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| First post | 2016-07-21 19:00 +0200 |
| Last post | 2016-07-23 04:30 +0200 |
| Articles | 10 — 4 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH v2 00/10] userns: sysctl limits for namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-21 19:00 +0200
[PATCH v2 08/10] cgroupns: Add a limit on the number of cgroup namespaces "Eric W. Biederman" <ebiederm@xmission.com> - 2016-07-21 19:00 +0200
[PATCH v2 10/10] mntns: Add a limit on the number of mount namespaces. "Eric W. Biederman" <ebiederm@xmission.com> - 2016-07-21 19:00 +0200
[PATCH v2 07/10] ipcns: Add a limit on the number of ipc namespaces "Eric W. Biederman" <ebiederm@xmission.com> - 2016-07-21 19:00 +0200
[PATCH v2 01/10] sysctl: Stop implicitly passing current into sysctl_table_root.lookup "Eric W. Biederman" <ebiederm@xmission.com> - 2016-07-21 19:00 +0200
[PATCH v2 03/10] userns: Add a limit on the number of user namespaces "Eric W. Biederman" <ebiederm@xmission.com> - 2016-07-21 19:00 +0200
Re: [PATCH v2 00/10] userns: sysctl limits for namespaces Colin Walters <walters@verbum.org> - 2016-07-22 15:40 +0200
Re: [PATCH v2 00/10] userns: sysctl limits for namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-22 21:00 +0200
Re: [PATCH v2 00/10] userns: sysctl limits for namespaces Kees Cook <keescook@chromium.org> - 2016-07-22 23:50 +0200
Re: [PATCH v2 00/10] userns: sysctl limits for namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-23 04:30 +0200
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-21 19:00 +0200 |
| Subject | [PATCH v2 00/10] userns: sysctl limits for namespaces |
| Message-ID | <rXpuh-1Dd-3@gated-at.bofh.it> |
This patchset addresses two use cases:
- Implement a sane upper bound on the number of namespaces.
- Provide a way for sandboxes to limit the attack surface from
namespaces.
The maximum sane case I can imagine is if every process is a fat
process, so I set the maximum number of namespaces to the maximum
number of threads.
I make these limits recursive and per user namespace so that a
usernamespace root can reduce the limits further. If a user namespace
root raises the limit the limit in the parent namespace will be honored.
I have cut this implementation to the bare minimum needed to achieve
these objectives.
Does anyone know if there is a proper error code to return for resource
limit exceeded? I am currently using -EUSERS or -ENFILE but both of
those feel a little wrong.
Assuming nothing problematic shows up in the review I will add these to
my user namespace tree.
These patches are also available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing
Changes since v1:
- Compilation issues with !CONFIG_SYSCTL and !CONFIG_USER_NS have been addressed
- Comment improvements.
- A few names have been changed to be clearer.
Eric W. Biederman (10):
sysctl: Stop implicitly passing current into sysctl_table_root.lookup
userns: Add per user namespace sysctls.
userns: Add a limit on the number of user namespaces
userns: Generalize the user namespace count into ucount
pidns: Add a limit on the number of pid namespaces
utsns: Add a limit on the number of uts namespaces
ipcns: Add a limit on the number of ipc namespaces
cgroupns: Add a limit on the number of cgroup namespaces
netns: Add a limit on the number of net namespaces
mntns: Add a limit on the number of mount namespaces.
fs/namespace.c | 19 ++++-
fs/proc/proc_sysctl.c | 14 +--
include/linux/sysctl.h | 3 +-
include/linux/user_namespace.h | 40 +++++++++
ipc/namespace.c | 42 ++++++---
kernel/cgroup.c | 15 ++++
kernel/fork.c | 5 ++
kernel/pid_namespace.c | 22 ++++-
kernel/user_namespace.c | 188 ++++++++++++++++++++++++++++++++++++++---
kernel/utsname.c | 31 +++++--
net/core/net_namespace.c | 15 ++++
net/sysctl_net.c | 4 +-
12 files changed, 355 insertions(+), 43 deletions(-)
Eric
[toc] | [next] | [standalone]
| From | "Eric W. Biederman" <ebiederm@xmission.com> |
|---|---|
| Date | 2016-07-21 19:00 +0200 |
| Subject | [PATCH v2 08/10] cgroupns: Add a limit on the number of cgroup namespaces |
| Message-ID | <rXpuj-1Dd-45@gated-at.bofh.it> |
| In reply to | #1448012 |
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
include/linux/user_namespace.h | 1 +
kernel/cgroup.c | 15 +++++++++++++++
kernel/user_namespace.c | 1 +
3 files changed, 17 insertions(+)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 367cf08ff63d..1a3a9cb93277 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -27,6 +27,7 @@ enum ucounts {
UCOUNT_PID_NAMESPACES,
UCOUNT_UTS_NAMESPACES,
UCOUNT_IPC_NAMESPACES,
+ UCOUNT_CGROUP_NAMESPACES,
UCOUNT_COUNTS,
};
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 86cb5c6e8932..240eec43390b 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6260,6 +6260,16 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd)
/* cgroup namespaces */
+static bool inc_cgroup_namespaces(struct user_namespace *ns)
+{
+ return inc_ucount(ns, UCOUNT_CGROUP_NAMESPACES);
+}
+
+static void dec_cgroup_namespaces(struct user_namespace *ns)
+{
+ dec_ucount(ns, UCOUNT_CGROUP_NAMESPACES);
+}
+
static struct cgroup_namespace *alloc_cgroup_ns(void)
{
struct cgroup_namespace *new_ns;
@@ -6281,6 +6291,7 @@ static struct cgroup_namespace *alloc_cgroup_ns(void)
void free_cgroup_ns(struct cgroup_namespace *ns)
{
put_css_set(ns->root_cset);
+ dec_cgroup_namespaces(ns->user_ns);
put_user_ns(ns->user_ns);
ns_free_inum(&ns->ns);
kfree(ns);
@@ -6305,6 +6316,9 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
+ if (!inc_cgroup_namespaces(user_ns))
+ return ERR_PTR(-ENFILE);
+
mutex_lock(&cgroup_mutex);
spin_lock_bh(&css_set_lock);
@@ -6317,6 +6331,7 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
new_ns = alloc_cgroup_ns();
if (IS_ERR(new_ns)) {
put_css_set(cset);
+ dec_cgroup_namespaces(user_ns);
return new_ns;
}
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 060d3e099f87..1cf074cb47e2 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -80,6 +80,7 @@ static struct ctl_table userns_table[] = {
UCOUNT_ENTRY("max_pid_namespaces"),
UCOUNT_ENTRY("max_uts_namespaces"),
UCOUNT_ENTRY("max_ipc_namespaces"),
+ UCOUNT_ENTRY("max_cgroup_namespaces"),
{ }
};
#endif /* CONFIG_SYSCTL */
--
2.8.3
[toc] | [prev] | [next] | [standalone]
| From | "Eric W. Biederman" <ebiederm@xmission.com> |
|---|---|
| Date | 2016-07-21 19:00 +0200 |
| Subject | [PATCH v2 10/10] mntns: Add a limit on the number of mount namespaces. |
| Message-ID | <rXpuj-1Dd-47@gated-at.bofh.it> |
| In reply to | #1448012 |
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
fs/namespace.c | 19 ++++++++++++++++++-
include/linux/user_namespace.h | 1 +
kernel/user_namespace.c | 1 +
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index aabe8e397fc3..3942ae6c34f5 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2718,9 +2718,20 @@ dput_out:
return retval;
}
+static bool inc_mnt_namespaces(struct user_namespace *ns)
+{
+ return inc_ucount(ns, UCOUNT_MNT_NAMESPACES);
+}
+
+static void dec_mnt_namespaces(struct user_namespace *ns)
+{
+ dec_ucount(ns, UCOUNT_MNT_NAMESPACES);
+}
+
static void free_mnt_ns(struct mnt_namespace *ns)
{
ns_free_inum(&ns->ns);
+ dec_mnt_namespaces(ns->user_ns);
put_user_ns(ns->user_ns);
kfree(ns);
}
@@ -2739,12 +2750,18 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
struct mnt_namespace *new_ns;
int ret;
+ if (!inc_mnt_namespaces(user_ns))
+ return ERR_PTR(-ENFILE);
+
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
- if (!new_ns)
+ if (!new_ns) {
+ dec_mnt_namespaces(user_ns);
return ERR_PTR(-ENOMEM);
+ }
ret = ns_alloc_inum(&new_ns->ns);
if (ret) {
kfree(new_ns);
+ dec_mnt_namespaces(user_ns);
return ERR_PTR(ret);
}
new_ns->ns.ops = &mntns_operations;
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index f86afa536baf..ee0e9d7b2e67 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -28,6 +28,7 @@ enum ucounts {
UCOUNT_UTS_NAMESPACES,
UCOUNT_IPC_NAMESPACES,
UCOUNT_NET_NAMESPACES,
+ UCOUNT_MNT_NAMESPACES,
UCOUNT_CGROUP_NAMESPACES,
UCOUNT_COUNTS,
};
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index e326ca722ae0..f6702d84afab 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -81,6 +81,7 @@ static struct ctl_table userns_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"),
{ }
};
--
2.8.3
[toc] | [prev] | [next] | [standalone]
| From | "Eric W. Biederman" <ebiederm@xmission.com> |
|---|---|
| Date | 2016-07-21 19:00 +0200 |
| Subject | [PATCH v2 07/10] ipcns: Add a limit on the number of ipc namespaces |
| Message-ID | <rXpuj-1Dd-59@gated-at.bofh.it> |
| In reply to | #1448012 |
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
include/linux/user_namespace.h | 1 +
ipc/namespace.c | 42 +++++++++++++++++++++++++++++++-----------
kernel/user_namespace.c | 1 +
3 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index bed2506081fe..367cf08ff63d 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -26,6 +26,7 @@ enum ucounts {
UCOUNT_USER_NAMESPACES,
UCOUNT_PID_NAMESPACES,
UCOUNT_UTS_NAMESPACES,
+ UCOUNT_IPC_NAMESPACES,
UCOUNT_COUNTS,
};
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 04cb07eb81f1..3996a1e41a1d 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -16,33 +16,42 @@
#include "util.h"
+static bool inc_ipc_namespaces(struct user_namespace *ns)
+{
+ return inc_ucount(ns, UCOUNT_IPC_NAMESPACES);
+}
+
+static void dec_ipc_namespaces(struct user_namespace *ns)
+{
+ dec_ucount(ns, UCOUNT_IPC_NAMESPACES);
+}
+
static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
struct ipc_namespace *old_ns)
{
struct ipc_namespace *ns;
int err;
+ err = -ENFILE;
+ if (!inc_ipc_namespaces(user_ns))
+ goto fail;
+
+ err = -ENOMEM;
ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
if (ns == NULL)
- return ERR_PTR(-ENOMEM);
+ goto fail_dec;
err = ns_alloc_inum(&ns->ns);
- if (err) {
- kfree(ns);
- return ERR_PTR(err);
- }
+ if (err)
+ goto fail_free;
ns->ns.ops = &ipcns_operations;
atomic_set(&ns->count, 1);
ns->user_ns = get_user_ns(user_ns);
err = mq_init_ns(ns);
- if (err) {
- put_user_ns(ns->user_ns);
- ns_free_inum(&ns->ns);
- kfree(ns);
- return ERR_PTR(err);
- }
+ if (err)
+ goto fail_put;
atomic_inc(&nr_ipc_ns);
sem_init_ns(ns);
@@ -50,6 +59,16 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
shm_init_ns(ns);
return ns;
+
+fail_put:
+ put_user_ns(ns->user_ns);
+ ns_free_inum(&ns->ns);
+fail_free:
+ kfree(ns);
+fail_dec:
+ dec_ipc_namespaces(user_ns);
+fail:
+ return ERR_PTR(err);
}
struct ipc_namespace *copy_ipcs(unsigned long flags,
@@ -98,6 +117,7 @@ static void free_ipc_ns(struct ipc_namespace *ns)
shm_exit_ns(ns);
atomic_dec(&nr_ipc_ns);
+ dec_ipc_namespaces(ns->user_ns);
put_user_ns(ns->user_ns);
ns_free_inum(&ns->ns);
kfree(ns);
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 6b205c24e888..060d3e099f87 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -79,6 +79,7 @@ static struct ctl_table userns_table[] = {
UCOUNT_ENTRY("max_user_namespaces"),
UCOUNT_ENTRY("max_pid_namespaces"),
UCOUNT_ENTRY("max_uts_namespaces"),
+ UCOUNT_ENTRY("max_ipc_namespaces"),
{ }
};
#endif /* CONFIG_SYSCTL */
--
2.8.3
[toc] | [prev] | [next] | [standalone]
| From | "Eric W. Biederman" <ebiederm@xmission.com> |
|---|---|
| Date | 2016-07-21 19:00 +0200 |
| Subject | [PATCH v2 01/10] sysctl: Stop implicitly passing current into sysctl_table_root.lookup |
| Message-ID | <rXpuh-1Dd-5@gated-at.bofh.it> |
| In reply to | #1448012 |
Passing nsproxy into sysctl_table_root.lookup was a premature
optimization in attempt to avoid depending on current. The
directory /proc/self/sys has not appeared and if and when
it does this code will need to be reviewed closely and reworked
anyway. So remove the premature optimization.
Acked-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
fs/proc/proc_sysctl.c | 14 +++++++-------
include/linux/sysctl.h | 3 +--
net/sysctl_net.c | 4 ++--
3 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 5e57c3e46e1d..534630687489 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -72,7 +72,7 @@ static DEFINE_SPINLOCK(sysctl_lock);
static void drop_sysctl_table(struct ctl_table_header *header);
static int sysctl_follow_link(struct ctl_table_header **phead,
- struct ctl_table **pentry, struct nsproxy *namespaces);
+ struct ctl_table **pentry);
static int insert_links(struct ctl_table_header *head);
static void put_links(struct ctl_table_header *header);
@@ -319,11 +319,11 @@ static void sysctl_head_finish(struct ctl_table_header *head)
}
static struct ctl_table_set *
-lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
+lookup_header_set(struct ctl_table_root *root)
{
struct ctl_table_set *set = &root->default_set;
if (root->lookup)
- set = root->lookup(root, namespaces);
+ set = root->lookup(root);
return set;
}
@@ -491,7 +491,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
goto out;
if (S_ISLNK(p->mode)) {
- ret = sysctl_follow_link(&h, &p, current->nsproxy);
+ ret = sysctl_follow_link(&h, &p);
err = ERR_PTR(ret);
if (ret)
goto out;
@@ -659,7 +659,7 @@ static bool proc_sys_link_fill_cache(struct file *file,
if (S_ISLNK(table->mode)) {
/* It is not an error if we can not follow the link ignore it */
- int err = sysctl_follow_link(&head, &table, current->nsproxy);
+ int err = sysctl_follow_link(&head, &table);
if (err)
goto out;
}
@@ -976,7 +976,7 @@ static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
}
static int sysctl_follow_link(struct ctl_table_header **phead,
- struct ctl_table **pentry, struct nsproxy *namespaces)
+ struct ctl_table **pentry)
{
struct ctl_table_header *head;
struct ctl_table_root *root;
@@ -988,7 +988,7 @@ static int sysctl_follow_link(struct ctl_table_header **phead,
ret = 0;
spin_lock(&sysctl_lock);
root = (*pentry)->data;
- set = lookup_header_set(root, namespaces);
+ set = lookup_header_set(root);
dir = xlate_dir(set, (*phead)->parent);
if (IS_ERR(dir))
ret = PTR_ERR(dir);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index fa7bc29925c9..6385b331f2b9 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -154,8 +154,7 @@ struct ctl_table_set {
struct ctl_table_root {
struct ctl_table_set default_set;
- struct ctl_table_set *(*lookup)(struct ctl_table_root *root,
- struct nsproxy *namespaces);
+ struct ctl_table_set *(*lookup)(struct ctl_table_root *root);
int (*permissions)(struct ctl_table_header *head, struct ctl_table *table);
};
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index ed98c1fc3de1..2951f229a855 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -27,9 +27,9 @@
#endif
static struct ctl_table_set *
-net_ctl_header_lookup(struct ctl_table_root *root, struct nsproxy *namespaces)
+net_ctl_header_lookup(struct ctl_table_root *root)
{
- return &namespaces->net_ns->sysctls;
+ return ¤t->nsproxy->net_ns->sysctls;
}
static int is_seen(struct ctl_table_set *set)
--
2.8.3
[toc] | [prev] | [next] | [standalone]
| From | "Eric W. Biederman" <ebiederm@xmission.com> |
|---|---|
| Date | 2016-07-21 19:00 +0200 |
| Subject | [PATCH v2 03/10] userns: Add a limit on the number of user namespaces |
| Message-ID | <rXpuj-1Dd-43@gated-at.bofh.it> |
| In reply to | #1448016 |
Export the export the maximum number of user namespaces as
/proc/sys/userns/max_user_namespaces.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
include/linux/user_namespace.h | 2 ++
kernel/fork.c | 2 ++
kernel/user_namespace.c | 69 +++++++++++++++++++++++++++++++++++++-----
3 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 7d59af1f08f1..ba6a995178f9 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -43,6 +43,8 @@ struct user_namespace {
struct ctl_table_set set;
struct ctl_table_header *sysctls;
#endif
+ int max_user_namespaces;
+ atomic_t user_namespaces;
};
extern struct user_namespace init_user_ns;
diff --git a/kernel/fork.c b/kernel/fork.c
index 5c2c355aa97f..95d5498c463f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -323,6 +323,8 @@ void __init fork_init(void)
init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
init_task.signal->rlim[RLIMIT_SIGPENDING] =
init_task.signal->rlim[RLIMIT_NPROC];
+
+ init_user_ns.max_user_namespaces = max_threads;
}
int __weak arch_dup_task_struct(struct task_struct *dst,
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 10afbb55dfc2..0061550e3282 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -29,6 +29,7 @@ static DEFINE_MUTEX(userns_state_mutex);
static bool new_idmap_permitted(const struct file *file,
struct user_namespace *ns, int cap_setid,
struct uid_gid_map *map);
+#define COUNT_MAX (INT_MAX - 1)
#ifdef CONFIG_SYSCTL
static struct ctl_table_set *
@@ -63,7 +64,18 @@ static struct ctl_table_root set_root = {
.permissions = set_permissions,
};
+static int zero = 0;
+static int count_max = COUNT_MAX;
static struct ctl_table userns_table[] = {
+ {
+ .procname = "max_user_namespaces",
+ .data = &init_user_ns.max_user_namespaces,
+ .maxlen = sizeof(init_user_ns.max_user_namespaces),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &count_max,
+ },
{ }
};
#endif /* CONFIG_SYSCTL */
@@ -75,6 +87,8 @@ static bool setup_userns_sysctls(struct user_namespace *ns)
setup_sysctl_set(&ns->set, &set_root, set_is_seen);
tbl = kmemdup(userns_table, sizeof(userns_table), GFP_KERNEL);
if (tbl) {
+ tbl[0].data = &ns->max_user_namespaces;
+
ns->sysctls = __register_sysctl_table(&ns->set, "userns", tbl);
}
if (!ns->sysctls) {
@@ -113,6 +127,34 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
cred->user_ns = user_ns;
}
+static bool inc_user_namespaces(struct user_namespace *ns)
+{
+ struct user_namespace *pos, *bad;
+ for (pos = ns; pos; pos = pos->parent) {
+ int max = READ_ONCE(pos->max_user_namespaces);
+ int sum = atomic_inc_return(&pos->user_namespaces);
+ if (sum > max)
+ goto fail;
+ }
+ return true;
+fail:
+ bad = pos;
+ atomic_dec(&pos->user_namespaces);
+ for (pos = ns; pos != bad; pos = pos->parent)
+ atomic_dec(&pos->user_namespaces);
+
+ return false;
+}
+
+static void dec_user_namespaces(struct user_namespace *ns)
+{
+ struct user_namespace *pos;
+ for (pos = ns; pos; pos = pos->parent) {
+ int dec = atomic_dec_if_positive(&pos->user_namespaces);
+ WARN_ON_ONCE(dec < 0);
+ }
+}
+
/*
* Create a new user namespace, deriving the creator from the user in the
* passed credentials, and replacing that user with the new root user for the
@@ -128,8 +170,12 @@ int create_user_ns(struct cred *new)
kgid_t group = new->egid;
int ret;
+ ret = -EUSERS;
if (parent_ns->level > 32)
- return -EUSERS;
+ goto fail;
+
+ if (!inc_user_namespaces(parent_ns))
+ goto fail;
/*
* Verify that we can not violate the policy of which files
@@ -137,26 +183,27 @@ int create_user_ns(struct cred *new)
* by verifing that the root directory is at the root of the
* mount namespace which allows all files to be accessed.
*/
+ ret = -EPERM;
if (current_chrooted())
- return -EPERM;
+ goto fail_dec;
/* The creator needs a mapping in the parent user namespace
* or else we won't be able to reasonably tell userspace who
* created a user_namespace.
*/
+ ret = -EPERM;
if (!kuid_has_mapping(parent_ns, owner) ||
!kgid_has_mapping(parent_ns, group))
- return -EPERM;
+ goto fail_dec;
+ ret = -ENOMEM;
ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL);
if (!ns)
- return -ENOMEM;
+ goto fail_dec;
ret = ns_alloc_inum(&ns->ns);
- if (ret) {
- kmem_cache_free(user_ns_cachep, ns);
- return ret;
- }
+ if (ret)
+ goto fail_free;
ns->ns.ops = &userns_operations;
atomic_set(&ns->count, 1);
@@ -165,6 +212,7 @@ int create_user_ns(struct cred *new)
ns->level = parent_ns->level + 1;
ns->owner = owner;
ns->group = group;
+ ns->max_user_namespaces = COUNT_MAX;
/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
mutex_lock(&userns_state_mutex);
@@ -185,7 +233,11 @@ fail_keyring:
key_put(ns->persistent_keyring_register);
#endif
ns_free_inum(&ns->ns);
+fail_free:
kmem_cache_free(user_ns_cachep, ns);
+fail_dec:
+ dec_user_namespaces(parent_ns);
+fail:
return ret;
}
@@ -221,6 +273,7 @@ void free_user_ns(struct user_namespace *ns)
#endif
ns_free_inum(&ns->ns);
kmem_cache_free(user_ns_cachep, ns);
+ dec_user_namespaces(parent);
ns = parent;
} while (atomic_dec_and_test(&parent->count));
}
--
2.8.3
[toc] | [prev] | [next] | [standalone]
| From | Colin Walters <walters@verbum.org> |
|---|---|
| Date | 2016-07-22 15:40 +0200 |
| Message-ID | <rXIQh-6tq-21@gated-at.bofh.it> |
| In reply to | #1448012 |
On Thu, Jul 21, 2016, at 12:39 PM, Eric W. Biederman wrote: > > This patchset addresses two use cases: > - Implement a sane upper bound on the number of namespaces. > - Provide a way for sandboxes to limit the attack surface from > namespaces. Perhaps this is obvious, but since you didn't quite explicitly state it; do you see this as obsoleting the existing downstream patches mentioned in: https://lwn.net/Articles/673597/ It seems conceptually similar to Kees' original approach, right? The high level makes sense to me...most interesting is per-userns sysctls. I'll note most current container managers mount /proc/sys read-only, and Docker specifically drops CAP_SYS_RESOURCE by default, so they'd likely need to learn how to undo that if one wanted to support recursive container usage. We'd probably need to evaluate the safety of having /proc/sys writable generally. (Also it's rather common to filter out CLONE_NEWUSER via seccomp, but that's easy to undo) But that's the flip side - if we're aiming primarily for an upstreamable way to *limit* namespace usage, it seems sane to me.
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-22 21:00 +0200 |
| Message-ID | <rXNPX-195-1@gated-at.bofh.it> |
| In reply to | #1448589 |
Colin Walters <walters@verbum.org> writes: > On Thu, Jul 21, 2016, at 12:39 PM, Eric W. Biederman wrote: >> >> This patchset addresses two use cases: >> - Implement a sane upper bound on the number of namespaces. >> - Provide a way for sandboxes to limit the attack surface from >> namespaces. > > Perhaps this is obvious, but since you didn't quite explicitly state it; > do you see this as obsoleting the existing downstream patches > mentioned in: > https://lwn.net/Articles/673597/ > It seems conceptually similar to Kees' original approach, right? Similar yes, and I expect it fills the need. My primary difference is that I believe this approach makes sense from a perspective of assuming that user namespaces or other namespaces are not any buggier than any other piece of kernel code and that people will use them. I don't see these limits making sense from a perspective that user namespaces are flawed and distro kernels should not have enabled them in the first place. That was my perception right or wrong of Kees patches and the related patches that landed in Ubuntu and Debian. With Kees approach I could not see how to handle the case where some applications on the system wanted user namespaces and others don't. Which made it very nasty for future evolution and more deployment of user namespaces. Being per user namespace these limits can be used to sandbox applications without affecting the rest of the system. > The high level makes sense to me...most interesting is > per-userns sysctls. I'll note most current container managers > mount /proc/sys read-only, and Docker specifically drops > CAP_SYS_RESOURCE by default, so they'd likely need to learn > how to undo that if one wanted to support recursive container usage. > We'd probably need to evaluate the safety of having /proc/sys > writable generally. (Also it's rather common to filter out CLONE_NEWUSER > via seccomp, but that's easy to undo) Just using a user namespace replaces most of those precautions. > But that's the flip side - if we're aiming primarily for an upstreamable > way to *limit* namespace usage, it seems sane to me. Yes. The primary target is to stop applications that have gone buggy and allocated a crazy number of namespaces. The secondary target is to allow sandboxes to disable creation of additional namespaces. Just set the limit to 0 and drop caps, or similarly set the limit to 1 and create another fresh set of nested namespaces. Eric
[toc] | [prev] | [next] | [standalone]
| From | Kees Cook <keescook@chromium.org> |
|---|---|
| Date | 2016-07-22 23:50 +0200 |
| Message-ID | <rXQut-2Qh-3@gated-at.bofh.it> |
| In reply to | #1448725 |
On Fri, Jul 22, 2016 at 11:45 AM, Eric W. Biederman <ebiederm@xmission.com> wrote: > Colin Walters <walters@verbum.org> writes: > >> On Thu, Jul 21, 2016, at 12:39 PM, Eric W. Biederman wrote: >>> >>> This patchset addresses two use cases: >>> - Implement a sane upper bound on the number of namespaces. >>> - Provide a way for sandboxes to limit the attack surface from >>> namespaces. >> >> Perhaps this is obvious, but since you didn't quite explicitly state it; >> do you see this as obsoleting the existing downstream patches >> mentioned in: >> https://lwn.net/Articles/673597/ >> It seems conceptually similar to Kees' original approach, right? > > Similar yes, and I expect it fills the need. My primary difference is > that I believe this approach makes sense from a perspective of assuming > that user namespaces or other namespaces are not any buggier than any > other piece of kernel code and that people will use them. > > I don't see these limits making sense from a perspective that user > namespaces are flawed and distro kernels should not have enabled them in > the first place. That was my perception right or wrong of Kees patches > and the related patches that landed in Ubuntu and Debian. > > With Kees approach I could not see how to handle the case where some > applications on the system wanted user namespaces and others don't. > Which made it very nasty for future evolution and more deployment of > user namespaces. Being per user namespace these limits can be used to > sandbox applications without affecting the rest of the system. While it certainly works for my use-case (init ns max_usernamespaces=0), I don't see how this helps the case of "let user foobar open 1 userns, but everyone else is 0", which is likely the middle ground between "just turn it off" and "everyone gets to create usernamespaces". I'm personally not interested in that level of granularity, but in earlier discussions it sounded like this was something you wanted? -Kees -- Kees Cook Chrome OS & Brillo Security
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-23 04:30 +0200 |
| Message-ID | <rXURs-5Av-7@gated-at.bofh.it> |
| In reply to | #1448800 |
Kees Cook <keescook@chromium.org> writes: > On Fri, Jul 22, 2016 at 11:45 AM, Eric W. Biederman > <ebiederm@xmission.com> wrote: >> Colin Walters <walters@verbum.org> writes: >> >>> On Thu, Jul 21, 2016, at 12:39 PM, Eric W. Biederman wrote: >>>> >>>> This patchset addresses two use cases: >>>> - Implement a sane upper bound on the number of namespaces. >>>> - Provide a way for sandboxes to limit the attack surface from >>>> namespaces. >>> >>> Perhaps this is obvious, but since you didn't quite explicitly state it; >>> do you see this as obsoleting the existing downstream patches >>> mentioned in: >>> https://lwn.net/Articles/673597/ >>> It seems conceptually similar to Kees' original approach, right? >> >> Similar yes, and I expect it fills the need. My primary difference is >> that I believe this approach makes sense from a perspective of assuming >> that user namespaces or other namespaces are not any buggier than any >> other piece of kernel code and that people will use them. >> >> I don't see these limits making sense from a perspective that user >> namespaces are flawed and distro kernels should not have enabled them in >> the first place. That was my perception right or wrong of Kees patches >> and the related patches that landed in Ubuntu and Debian. >> >> With Kees approach I could not see how to handle the case where some >> applications on the system wanted user namespaces and others don't. >> Which made it very nasty for future evolution and more deployment of >> user namespaces. Being per user namespace these limits can be used to >> sandbox applications without affecting the rest of the system. > > While it certainly works for my use-case (init ns > max_usernamespaces=0), I don't see how this helps the case of "let > user foobar open 1 userns, but everyone else is 0", which is likely > the middle ground between "just turn it off" and "everyone gets to > create usernamespaces". I'm personally not interested in that level of > granularity, but in earlier discussions it sounded like this was > something you wanted? So the case I really care about is when there is limited use, so people don't have to redesign their applications. In this case if you want to disable things in a sandbox like way you just create a user namespace and set the count to 0 in that user namespace. A whole system disable I tend to think is a stupid configuration for a new system. It gets into people negotiating for what they need, and I don't see that as sustainable. I prefer good usable defaults. I would have loved to have done something with per user limits so it could be disabled for a selection of users, but it turns out the kernel doesn't have appropriate data structures for to hold limits for users that have not logged in. And in practice I don't care the case where 1 user is allowed but not the others, I care about disallow this user/program that is in a sandbox. I also seem to recall people have problems with using seccomp to disable things. All of that said a per user policy is easily implemented in pam by setting the size count for a specific user to 0. I do think a limit to catch applications that go crazy is very sane, and that is primarily what is implemented here. Eric
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web