From: Jonathan Calmels <jcalmels@3xx0.net>
To: brauner@kernel.org, ebiederm@xmission.com,
Jonathan Corbet <corbet@lwn.net>,
Paul Moore <paul@paul-moore.com>,
James Morris <jmorris@namei.org>,
"Serge E. Hallyn" <serge@hallyn.com>,
KP Singh <kpsingh@kernel.org>,
Matt Bobrowski <mattbobrowski@google.com>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Martin KaFai Lau <martin.lau@linux.dev>,
Eduard Zingerman <eddyz87@gmail.com>, Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
Stanislav Fomichev <sdf@google.com>, Hao Luo <haoluo@google.com>,
Jiri Olsa <jolsa@kernel.org>,
Luis Chamberlain <mcgrof@kernel.org>, Kees Cook <kees@kernel.org>,
Joel Granados <j.granados@samsung.com>,
John Johansen <john.johansen@canonical.com>,
David Howells <dhowells@redhat.com>,
Jarkko Sakkinen <jarkko@kernel.org>,
Stephen Smalley <stephen.smalley.work@gmail.com>,
Ondrej Mosnacek <omosnace@redhat.com>,
Mykola Lysenko <mykolal@fb.com>, Shuah Khan <shuah@kernel.org>
Cc: containers@lists.linux.dev, Jonathan Calmels <jcalmels@3xx0.net>,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-doc@vger.kernel.org, linux-security-module@vger.kernel.org,
bpf@vger.kernel.org, apparmor@lists.ubuntu.com,
keyrings@vger.kernel.org, selinux@vger.kernel.org,
linux-kselftest@vger.kernel.org
Subject: [PATCH v2 3/4] capabilities: Add sysctl to mask off userns caps
Date: Sun, 9 Jun 2024 03:43:36 -0700 [thread overview]
Message-ID: <20240609104355.442002-4-jcalmels@3xx0.net> (raw)
In-Reply-To: <20240609104355.442002-1-jcalmels@3xx0.net>
This patch adds a new system-wide userns capability mask designed to mask
off capabilities in user namespaces.
This mask is controlled through a sysctl and can be set early in the boot
process or on the kernel command line to exclude known capabilities from
ever being gained in namespaces. Once set, it can be further restricted to
exert dynamic policies on the system (e.g. ward off a potential exploit).
Changing this mask requires privileges in the initial user namespace
over the newly introduced CAP_SYS_CONTROL.
Example:
# sysctl -qw kernel.cap_userns_mask=0x1fffffdffff && \
unshare -r grep Cap /proc/self/status
CapInh: 0000000000000000
CapPrm: 000001fffffdffff
CapEff: 000001fffffdffff
CapBnd: 000001fffffdffff
CapAmb: 0000000000000000
CapUNs: 000001fffffdffff
Signed-off-by: Jonathan Calmels <jcalmels@3xx0.net>
---
include/linux/user_namespace.h | 7 ++++
include/uapi/linux/capability.h | 6 ++-
kernel/sysctl.c | 10 +++++
kernel/user_namespace.c | 63 +++++++++++++++++++++++++++++
security/selinux/include/classmap.h | 5 ++-
5 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 6030a8235617..d958d4819608 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_USER_NAMESPACE_H
#define _LINUX_USER_NAMESPACE_H
+#include <linux/capability.h>
#include <linux/kref.h>
#include <linux/nsproxy.h>
#include <linux/ns_common.h>
@@ -14,6 +15,12 @@
#define UID_GID_MAP_MAX_BASE_EXTENTS 5
#define UID_GID_MAP_MAX_EXTENTS 340
+#ifdef CONFIG_SYSCTL
+extern kernel_cap_t cap_userns_mask;
+int cap_userns_sysctl_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *lenp, loff_t *ppos);
+#endif
+
struct uid_gid_extent {
u32 first;
u32 lower_first;
diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
index 5bb906098697..e2c5e4bb2eb0 100644
--- a/include/uapi/linux/capability.h
+++ b/include/uapi/linux/capability.h
@@ -418,7 +418,11 @@ struct vfs_ns_cap_data {
#define CAP_CHECKPOINT_RESTORE 40
-#define CAP_LAST_CAP CAP_CHECKPOINT_RESTORE
+/* Allow setting the system userns capability mask. */
+
+#define CAP_SYS_CONTROL 41
+
+#define CAP_LAST_CAP CAP_SYS_CONTROL
#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e0b917328cf9..95b27a92c63c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -62,6 +62,7 @@
#include <linux/sched/sysctl.h>
#include <linux/mount.h>
#include <linux/userfaultfd_k.h>
+#include <linux/user_namespace.h>
#include <linux/pid.h>
#include "../lib/kstrtox.h"
@@ -1846,6 +1847,15 @@ static struct ctl_table kern_table[] = {
.mode = 0444,
.proc_handler = proc_dointvec,
},
+#ifdef CONFIG_USER_NS
+ {
+ .procname = "cap_userns_mask",
+ .data = &cap_userns_mask,
+ .maxlen = sizeof(kernel_cap_t),
+ .mode = 0644,
+ .proc_handler = cap_userns_sysctl_handler,
+ },
+#endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
{
.procname = "unknown_nmi_panic",
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 53848e2b68cd..e513d87ed102 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -26,6 +26,63 @@
static struct kmem_cache *user_ns_cachep __ro_after_init;
static DEFINE_MUTEX(userns_state_mutex);
+#ifdef CONFIG_SYSCTL
+static DEFINE_SPINLOCK(cap_userns_lock);
+kernel_cap_t cap_userns_mask = CAP_FULL_SET;
+
+int cap_userns_sysctl_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table t;
+ unsigned long mask_array[2];
+ kernel_cap_t new_mask, *mask;
+ int err;
+
+ if (write && !capable(CAP_SYS_CONTROL))
+ return -EPERM;
+
+ /*
+ * convert from the global kernel_cap_t to the ulong array to print to
+ * userspace if this is a read.
+ *
+ * capabilities are exposed as one 64-bit value or two 32-bit values
+ * depending on the architecture
+ */
+ mask = table->data;
+ spin_lock(&cap_userns_lock);
+ mask_array[0] = (unsigned long) mask->val;
+ if (BITS_PER_LONG != 64)
+ mask_array[1] = mask->val >> BITS_PER_LONG;
+ spin_unlock(&cap_userns_lock);
+
+ t = *table;
+ t.data = &mask_array;
+
+ /*
+ * actually read or write and array of ulongs from userspace. Remember
+ * these are least significant bits first
+ */
+ err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
+ if (err < 0)
+ return err;
+
+ new_mask.val = mask_array[0];
+ if (BITS_PER_LONG != 64)
+ new_mask.val += (u64)mask_array[1] << BITS_PER_LONG;
+
+ /*
+ * Drop everything not in the new_mask (but don't add things)
+ */
+ if (write) {
+ spin_lock(&cap_userns_lock);
+ *mask = cap_intersect(*mask, new_mask);
+ spin_unlock(&cap_userns_lock);
+ }
+
+ return 0;
+}
+#endif
+
static bool new_idmap_permitted(const struct file *file,
struct user_namespace *ns, int cap_setid,
struct uid_gid_map *map);
@@ -46,6 +103,12 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
/* Limit userns capabilities to our parent's bounding set. */
if (iscredsecure(cred, SECURE_USERNS_STRICT_CAPS))
cred->cap_userns = cap_intersect(cred->cap_userns, cred->cap_bset);
+#ifdef CONFIG_SYSCTL
+ /* Mask off userns capabilities that are not permitted by the system-wide mask. */
+ spin_lock(&cap_userns_lock);
+ cred->cap_userns = cap_intersect(cred->cap_userns, cap_userns_mask);
+ spin_unlock(&cap_userns_lock);
+#endif
/* Start with the capabilities defined in the userns set. */
cred->cap_bset = cred->cap_userns;
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 7229c9bf6c27..8f3ede7aac92 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -34,9 +34,10 @@
#define COMMON_CAP2_PERMS \
"mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", \
- "audit_read", "perfmon", "bpf", "checkpoint_restore"
+ "audit_read", "perfmon", "bpf", "checkpoint_restore", \
+ "sys_control"
-#if CAP_LAST_CAP > CAP_CHECKPOINT_RESTORE
+#if CAP_LAST_CAP > CAP_SYS_CONTROL
#error New capability defined, please update COMMON_CAP2_PERMS.
#endif
--
2.45.2
next prev parent reply other threads:[~2024-06-09 10:40 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-09 10:43 [PATCH v2 0/4] Introduce user namespace capabilities Jonathan Calmels
2024-06-09 10:43 ` [PATCH v2 1/4] capabilities: Add " Jonathan Calmels
2024-06-10 1:50 ` Serge E. Hallyn
2024-06-10 8:47 ` Jonathan Calmels
2024-06-10 12:48 ` Serge E. Hallyn
2024-06-10 13:00 ` Serge E. Hallyn
2024-06-11 8:20 ` Jonathan Calmels
2024-06-15 15:19 ` Serge E. Hallyn
2024-06-09 10:43 ` [PATCH v2 2/4] capabilities: Add securebit to restrict userns caps Jonathan Calmels
2024-06-10 2:33 ` Serge E. Hallyn
2024-06-10 9:46 ` Jonathan Calmels
2024-06-10 13:05 ` Serge E. Hallyn
2024-06-28 14:43 ` Jarkko Sakkinen
2024-06-28 14:45 ` Jarkko Sakkinen
2024-06-09 10:43 ` Jonathan Calmels [this message]
2024-06-09 10:43 ` [PATCH v2 4/4] bpf,lsm: Allow editing capabilities in BPF-LSM hooks Jonathan Calmels
2024-06-10 0:18 ` Paul Moore
2024-06-11 8:09 ` Jonathan Calmels
2024-06-11 10:31 ` John Johansen
2024-06-11 19:01 ` Paul Moore
2024-06-11 22:20 ` Jonathan Calmels
2024-06-11 22:38 ` Paul Moore
2024-06-12 8:20 ` Jonathan Calmels
2024-06-12 17:29 ` Paul Moore
2024-06-13 3:54 ` John Johansen
2024-06-13 8:50 ` Jonathan Calmels
2024-06-13 20:55 ` Paul Moore
2024-06-15 15:20 ` Serge E. Hallyn
2024-06-13 10:45 ` Dr. Greg
2024-06-13 20:43 ` Paul Moore
2024-06-10 20:12 ` [PATCH v2 0/4] Introduce user namespace capabilities Josef Bacik
2024-06-11 8:33 ` Jonathan Calmels
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=20240609104355.442002-4-jcalmels@3xx0.net \
--to=jcalmels@3xx0.net \
--cc=andrii@kernel.org \
--cc=apparmor@lists.ubuntu.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=containers@lists.linux.dev \
--cc=corbet@lwn.net \
--cc=daniel@iogearbox.net \
--cc=dhowells@redhat.com \
--cc=ebiederm@xmission.com \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=j.granados@samsung.com \
--cc=jarkko@kernel.org \
--cc=jmorris@namei.org \
--cc=john.fastabend@gmail.com \
--cc=john.johansen@canonical.com \
--cc=jolsa@kernel.org \
--cc=kees@kernel.org \
--cc=keyrings@vger.kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=mattbobrowski@google.com \
--cc=mcgrof@kernel.org \
--cc=mykolal@fb.com \
--cc=omosnace@redhat.com \
--cc=paul@paul-moore.com \
--cc=sdf@google.com \
--cc=selinux@vger.kernel.org \
--cc=serge@hallyn.com \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=stephen.smalley.work@gmail.com \
--cc=yonghong.song@linux.dev \
/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