From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org,
"Eric W. Biederman" <ebiederm@xmission.com>
Subject: [PATCH 3.14 41/52] userns: Add a knob to disable setgroups on a per user namespace basis
Date: Tue, 6 Jan 2015 18:07:09 -0800 [thread overview]
Message-ID: <20150107020601.786490531@linuxfoundation.org> (raw)
In-Reply-To: <20150107020555.043793795@linuxfoundation.org>
3.14-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Eric W. Biederman" <ebiederm@xmission.com>
commit 9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8 upstream.
- 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.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
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(+)
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2555,6 +2555,57 @@ static const struct file_operations proc
.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,
@@ -2663,6 +2714,7 @@ static const struct pid_entry tgid_base_
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),
@@ -2998,6 +3050,7 @@ static const struct pid_entry tid_base_s
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
};
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -17,6 +17,10 @@ struct uid_gid_map { /* 64 bytes -- 1 ca
} 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 struct seq_operations proc_projid
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
--- 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),
--- 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
@@ -831,6 +836,84 @@ static bool new_idmap_permitted(const st
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;
@@ -840,6 +923,8 @@ bool userns_may_setgroups(const struct u
* 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;
next prev parent reply other threads:[~2015-01-07 2:11 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-07 2:06 [PATCH 3.14 00/52] 3.14.28-stable review Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 01/52] isofs: Fix infinite looping over CE entries Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 02/52] x86/tls: Validate TLS entries to protect espfix Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 03/52] x86/tls: Disallow unusual TLS segments Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 04/52] x86_64, switch_to(): Load TLS descriptors before switching DS and ES Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 05/52] x86, kvm: Clear paravirt_enabled on KVM guests for espfix32s benefit Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 06/52] md/bitmap: always wait for writes on unplug Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 07/52] mfd: tc6393xb: Fail ohci suspend if full state restore is required Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 08/52] mmc: dw_mmc: avoid write to CDTHRCTL on older versions Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 09/52] mmc: block: add newline to sysfs display of force_ro Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 10/52] mmc: sdhci-pci-o2micro: Fix Dell E5440 issue Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 11/52] megaraid_sas: corrected return of wait_event from abort frame path Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 12/52] scsi: correct return values for .eh_abort_handler implementations Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 13/52] nfs41: fix nfs4_proc_layoutget error handling Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 14/52] dm bufio: fix memleak when using a dm_buffers inline bio Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 15/52] dm crypt: use memzero_explicit for on-stack buffer Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 16/52] dm cache: only use overwrite optimisation for promotion when in writeback mode Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 17/52] dm cache: dirty flag was mistakenly being cleared when promoting via overwrite Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 18/52] dm space map metadata: fix sm_bootstrap_get_nr_blocks() Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 19/52] dm thin: fix inability to discard blocks when in out-of-data-space mode Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 20/52] dm thin: fix missing out-of-data-space to write mode transition if blocks are released Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 21/52] arm64: Add COMPAT_HWCAP_LPAE Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 22/52] ARM: tegra: Re-add removed SoC id macro to tegra_resume() Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 24/52] x86/tls: Dont validate lm in set_thread_area() after all Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 25/52] isofs: Fix unchecked printing of ER records Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 26/52] KEYS: Fix stale key registration at error path Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 28/52] mac80211: free management frame keys when removing station Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 29/52] mnt: Fix a memory stomp in umount Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 30/52] thermal: Fix error path in thermal_init() Greg Kroah-Hartman
2015-01-07 2:06 ` [PATCH 3.14 31/52] mnt: Implicitly add MNT_NODEV on remount when it was implicitly added by mount Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 32/52] mnt: Update unprivileged remount test Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 33/52] umount: Disallow unprivileged mount force Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 34/52] groups: Consolidate the setgroups permission checks Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 35/52] userns: Document what the invariant required for safe unprivileged mappings Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 36/52] userns: Dont allow setgroups until a gid mapping has been setablished Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 37/52] userns: Dont allow unprivileged creation of gid mappings Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 38/52] userns: Check euid no fsuid when establishing an unprivileged uid mapping Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 39/52] userns: Only allow the creator of the userns unprivileged mappings Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 40/52] userns: Rename id_map_mutex to userns_state_mutex Greg Kroah-Hartman
2015-01-07 2:07 ` Greg Kroah-Hartman [this message]
2015-01-07 2:07 ` [PATCH 3.14 42/52] userns: Allow setting gid_maps without privilege when setgroups is disabled Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 43/52] userns: Unbreak the unprivileged remount tests Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 44/52] audit: restore AUDIT_LOGINUID unset ABI Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 45/52] crypto: af_alg - fix backlog handling Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 46/52] ncpfs: return proper error from NCP_IOC_SETROOT ioctl Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 47/52] exit: pidns: alloc_pid() leaks pid_namespace if child_reaper is exiting Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 48/52] udf: Verify symlink size before loading it Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 49/52] eCryptfs: Force RO mount when encrypted view is enabled Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 50/52] eCryptfs: Remove buggy and unnecessary write in file name decode routine Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 51/52] Btrfs: do not move em to modified list when unpinning Greg Kroah-Hartman
2015-01-07 2:07 ` [PATCH 3.14 52/52] Btrfs: fix fs corruption on transaction abort if device supports discard Greg Kroah-Hartman
2015-01-07 13:42 ` [PATCH 3.14 00/52] 3.14.28-stable review Guenter Roeck
2015-01-07 23:34 ` Shuah Khan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150107020601.786490531@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=ebiederm@xmission.com \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).