summaryrefslogtreecommitdiffstats
path: root/userns-Add-a-knob-to-disable-setgroups-on-a-per-user.patch
diff options
context:
space:
mode:
Diffstat (limited to 'userns-Add-a-knob-to-disable-setgroups-on-a-per-user.patch')
-rw-r--r--userns-Add-a-knob-to-disable-setgroups-on-a-per-user.patch280
1 files changed, 0 insertions, 280 deletions
diff --git a/userns-Add-a-knob-to-disable-setgroups-on-a-per-user.patch b/userns-Add-a-knob-to-disable-setgroups-on-a-per-user.patch
deleted file mode 100644
index a55381706..000000000
--- a/userns-Add-a-knob-to-disable-setgroups-on-a-per-user.patch
+++ /dev/null
@@ -1,280 +0,0 @@
-From: "Eric W. Biederman" <ebiederm@xmission.com>
-Date: Tue, 2 Dec 2014 12:27:26 -0600
-Subject: [PATCH] userns: Add a knob to disable setgroups on a per user
- namespace basis
-
-- Expose the knob to user space through a proc file /proc/<pid>/setgroups
-
- A value of "deny" means the setgroups system call is disabled in the
- current processes user namespace and can not be enabled in the
- future in this user namespace.
-
- A value of "allow" means the segtoups system call is enabled.
-
-- Descendant user namespaces inherit the value of setgroups from
- their parents.
-
-- A proc file is used (instead of a sysctl) as sysctls currently do
- not allow checking the permissions at open time.
-
-- Writing to the proc file is restricted to before the gid_map
- for the user namespace is set.
-
- This ensures that disabling setgroups at a user namespace
- level will never remove the ability to call setgroups
- from a process that already has that ability.
-
- A process may opt in to the setgroups disable for itself by
- creating, entering and configuring a user namespace or by calling
- setns on an existing user namespace with setgroups disabled.
- Processes without privileges already can not call setgroups so this
- is a noop. Prodcess with privilege become processes without
- privilege when entering a user namespace and as with any other path
- to dropping privilege they would not have the ability to call
- setgroups. So this remains within the bounds of what is possible
- without a knob to disable setgroups permanently in a user namespace.
-
-Cc: stable@vger.kernel.org
-Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
----
- fs/proc/base.c | 53 ++++++++++++++++++++++++++
- include/linux/user_namespace.h | 7 ++++
- kernel/user.c | 1 +
- kernel/user_namespace.c | 85 ++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 146 insertions(+)
-
-diff --git a/fs/proc/base.c b/fs/proc/base.c
-index 772efa45a452..7dc3ea89ef1a 100644
---- a/fs/proc/base.c
-+++ b/fs/proc/base.c
-@@ -2464,6 +2464,57 @@ static const struct file_operations proc_projid_map_operations = {
- .llseek = seq_lseek,
- .release = proc_id_map_release,
- };
-+
-+static int proc_setgroups_open(struct inode *inode, struct file *file)
-+{
-+ struct user_namespace *ns = NULL;
-+ struct task_struct *task;
-+ int ret;
-+
-+ ret = -ESRCH;
-+ task = get_proc_task(inode);
-+ if (task) {
-+ rcu_read_lock();
-+ ns = get_user_ns(task_cred_xxx(task, user_ns));
-+ rcu_read_unlock();
-+ put_task_struct(task);
-+ }
-+ if (!ns)
-+ goto err;
-+
-+ if (file->f_mode & FMODE_WRITE) {
-+ ret = -EACCES;
-+ if (!ns_capable(ns, CAP_SYS_ADMIN))
-+ goto err_put_ns;
-+ }
-+
-+ ret = single_open(file, &proc_setgroups_show, ns);
-+ if (ret)
-+ goto err_put_ns;
-+
-+ return 0;
-+err_put_ns:
-+ put_user_ns(ns);
-+err:
-+ return ret;
-+}
-+
-+static int proc_setgroups_release(struct inode *inode, struct file *file)
-+{
-+ struct seq_file *seq = file->private_data;
-+ struct user_namespace *ns = seq->private;
-+ int ret = single_release(inode, file);
-+ put_user_ns(ns);
-+ return ret;
-+}
-+
-+static const struct file_operations proc_setgroups_operations = {
-+ .open = proc_setgroups_open,
-+ .write = proc_setgroups_write,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = proc_setgroups_release,
-+};
- #endif /* CONFIG_USER_NS */
-
- static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
-@@ -2572,6 +2623,7 @@ static const struct pid_entry tgid_base_stuff[] = {
- REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations),
- REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
- REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
-+ REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations),
- #endif
- #ifdef CONFIG_CHECKPOINT_RESTORE
- REG("timers", S_IRUGO, proc_timers_operations),
-@@ -2913,6 +2965,7 @@ static const struct pid_entry tid_base_stuff[] = {
- REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations),
- REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
- REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
-+ REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations),
- #endif
- };
-
-diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
-index 8d493083486a..9f3579ff543d 100644
---- a/include/linux/user_namespace.h
-+++ b/include/linux/user_namespace.h
-@@ -17,6 +17,10 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */
- } extent[UID_GID_MAP_MAX_EXTENTS];
- };
-
-+#define USERNS_SETGROUPS_ALLOWED 1UL
-+
-+#define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED
-+
- struct user_namespace {
- struct uid_gid_map uid_map;
- struct uid_gid_map gid_map;
-@@ -27,6 +31,7 @@ struct user_namespace {
- kuid_t owner;
- kgid_t group;
- unsigned int proc_inum;
-+ unsigned long flags;
-
- /* Register of per-UID persistent keyrings for this namespace */
- #ifdef CONFIG_PERSISTENT_KEYRINGS
-@@ -63,6 +68,8 @@ extern const struct seq_operations proc_projid_seq_operations;
- extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *);
- extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *);
- extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, loff_t *);
-+extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
-+extern int proc_setgroups_show(struct seq_file *m, void *v);
- extern bool userns_may_setgroups(const struct user_namespace *ns);
- #else
-
-diff --git a/kernel/user.c b/kernel/user.c
-index 4efa39350e44..2d09940c9632 100644
---- a/kernel/user.c
-+++ b/kernel/user.c
-@@ -51,6 +51,7 @@ struct user_namespace init_user_ns = {
- .owner = GLOBAL_ROOT_UID,
- .group = GLOBAL_ROOT_GID,
- .proc_inum = PROC_USER_INIT_INO,
-+ .flags = USERNS_INIT_FLAGS,
- #ifdef CONFIG_PERSISTENT_KEYRINGS
- .persistent_keyring_register_sem =
- __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
-diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
-index 44a555ac6104..6e80f4c1322b 100644
---- a/kernel/user_namespace.c
-+++ b/kernel/user_namespace.c
-@@ -100,6 +100,11 @@ int create_user_ns(struct cred *new)
- ns->owner = owner;
- ns->group = group;
-
-+ /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
-+ mutex_lock(&userns_state_mutex);
-+ ns->flags = parent_ns->flags;
-+ mutex_unlock(&userns_state_mutex);
-+
- set_cred_user_ns(new, ns);
-
- #ifdef CONFIG_PERSISTENT_KEYRINGS
-@@ -839,6 +844,84 @@ static bool new_idmap_permitted(const struct file *file,
- return false;
- }
-
-+int proc_setgroups_show(struct seq_file *seq, void *v)
-+{
-+ struct user_namespace *ns = seq->private;
-+ unsigned long userns_flags = ACCESS_ONCE(ns->flags);
-+
-+ seq_printf(seq, "%s\n",
-+ (userns_flags & USERNS_SETGROUPS_ALLOWED) ?
-+ "allow" : "deny");
-+ return 0;
-+}
-+
-+ssize_t proc_setgroups_write(struct file *file, const char __user *buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct seq_file *seq = file->private_data;
-+ struct user_namespace *ns = seq->private;
-+ char kbuf[8], *pos;
-+ bool setgroups_allowed;
-+ ssize_t ret;
-+
-+ /* Only allow a very narrow range of strings to be written */
-+ ret = -EINVAL;
-+ if ((*ppos != 0) || (count >= sizeof(kbuf)))
-+ goto out;
-+
-+ /* What was written? */
-+ ret = -EFAULT;
-+ if (copy_from_user(kbuf, buf, count))
-+ goto out;
-+ kbuf[count] = '\0';
-+ pos = kbuf;
-+
-+ /* What is being requested? */
-+ ret = -EINVAL;
-+ if (strncmp(pos, "allow", 5) == 0) {
-+ pos += 5;
-+ setgroups_allowed = true;
-+ }
-+ else if (strncmp(pos, "deny", 4) == 0) {
-+ pos += 4;
-+ setgroups_allowed = false;
-+ }
-+ else
-+ goto out;
-+
-+ /* Verify there is not trailing junk on the line */
-+ pos = skip_spaces(pos);
-+ if (*pos != '\0')
-+ goto out;
-+
-+ ret = -EPERM;
-+ mutex_lock(&userns_state_mutex);
-+ if (setgroups_allowed) {
-+ /* Enabling setgroups after setgroups has been disabled
-+ * is not allowed.
-+ */
-+ if (!(ns->flags & USERNS_SETGROUPS_ALLOWED))
-+ goto out_unlock;
-+ } else {
-+ /* Permanently disabling setgroups after setgroups has
-+ * been enabled by writing the gid_map is not allowed.
-+ */
-+ if (ns->gid_map.nr_extents != 0)
-+ goto out_unlock;
-+ ns->flags &= ~USERNS_SETGROUPS_ALLOWED;
-+ }
-+ mutex_unlock(&userns_state_mutex);
-+
-+ /* Report a successful write */
-+ *ppos = count;
-+ ret = count;
-+out:
-+ return ret;
-+out_unlock:
-+ mutex_unlock(&userns_state_mutex);
-+ goto out;
-+}
-+
- bool userns_may_setgroups(const struct user_namespace *ns)
- {
- bool allowed;
-@@ -848,6 +931,8 @@ bool userns_may_setgroups(const struct user_namespace *ns)
- * the user namespace has been established.
- */
- allowed = ns->gid_map.nr_extents != 0;
-+ /* Is setgroups allowed? */
-+ allowed = allowed && (ns->flags & USERNS_SETGROUPS_ALLOWED);
- mutex_unlock(&userns_state_mutex);
-
- return allowed;
---
-2.1.0
-