[PATCH bpf-next 02/11] bpf: Refuse caller-supplied keyrings when the bpf one is active

Daniel Borkmann <[email protected]>
Newsgroups org.kernel.vger.bpf
Message-ID <[email protected]>
Nothing changes for systems that do not use the bpf keyring. Without
bpf.keyring_unsealed=1 a caller-supplied keyring behaves exactly as
before, which also lets it serve as the staging step for software
installed onto a running system whose signing key is not enrolled
anywhere yet.

Passing bpf.keyring_unsealed=1 states that the bpf keyring is the trust
anchor for this boot, so from the first program load onwards a caller-
supplied keyring is refused with -EPERM. Deriving this from the boot
flag rather than from the keyring's runtime state keeps the decision
immutable from userspace.

Signed-off-by: Daniel Borkmann <[email protected]>
---
 .../admin-guide/kernel-parameters.txt         |  7 +++++
 include/linux/bpf.h                           |  6 ++++
 kernel/bpf/keys.c                             |  5 ++++
 kernel/bpf/verifier.c                         | 29 ++++++++++++-------
 4 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 2beb61092bb3..543f245cc255 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -673,6 +673,13 @@ Kernel parameters
 			keys. Once the keyring is restricted it becomes active
 			and can be used for BPF program signature verification.
 
+			Setting this also means that the bpf keyring is the
+			only keyring a loader may select for the rest of the
+			boot: caller-supplied user/session keyrings are
+			refused with -EPERM, whether or not provisioning
+			actually completed. Leaving it unset keeps the prior
+			behaviour, where a caller-supplied keyring is allowed.
+
 			See Documentation/bpf/signing.rst
 
 	bttv.card=	[HW,V4L] bttv (bt848 + bt878 based grabber cards)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 240e527c864b..f6ef16c938cb 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3821,6 +3821,7 @@ struct bpf_key {
 struct bpf_key *bpf_lookup_user_key(s32 serial, u64 flags);
 struct bpf_key *bpf_lookup_system_key(u64 id);
 struct bpf_key *bpf_lookup_keyring(void);
+bool bpf_keyring_enforced(void);
 void bpf_key_put(struct bpf_key *bkey);
 int bpf_verify_pkcs7_signature(const struct bpf_dynptr *data_p,
 			       const struct bpf_dynptr *sig_p,
@@ -3846,6 +3847,11 @@ static inline struct bpf_key *bpf_lookup_keyring(void)
 	return NULL;
 }
 
+static inline bool bpf_keyring_enforced(void)
+{
+	return false;
+}
+
 static inline void bpf_key_put(struct bpf_key *bkey)
 {
 }
diff --git a/kernel/bpf/keys.c b/kernel/bpf/keys.c
index dc4d3a33158a..60cb85295c89 100644
--- a/kernel/bpf/keys.c
+++ b/kernel/bpf/keys.c
@@ -18,6 +18,11 @@ static bool bpf_keyring_unsealed __ro_after_init;
 module_param_named(keyring_unsealed, bpf_keyring_unsealed, bool, 0444);
 MODULE_PARM_DESC(keyring_unsealed, "Leave the bpf keyring unsealed");
 
+bool bpf_keyring_enforced(void)
+{
+	return bpf_keyring_unsealed;
+}
+
 struct bpf_key *bpf_lookup_keyring(void)
 {
 	struct bpf_key *bkey;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3be8d51d35ac..a93a8dc427d8 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -21018,21 +21018,28 @@ static int bpf_prog_verify_signature(struct bpf_verifier_env *env,
 	if (!attr->signature_size ||
 	    attr->signature_size > KMALLOC_MAX_CACHE_SIZE)
 		return -EINVAL;
-	if (attr->keyring_id == VERIFY_USE_BPF_KEYRING) {
-		key = bpf_lookup_keyring();
-		if (!key) {
-			verbose(env, "the bpf keyring is empty or has not been restricted\n");
-			return -ENOKEY;
-		}
-	} else if (system_keyring_id_check(attr->keyring_id) == 0) {
+	if (!system_keyring_id_check(attr->keyring_id)) {
 		key = bpf_lookup_system_key(attr->keyring_id);
 	} else {
-		key = bpf_lookup_user_key(attr->keyring_id, 0);
+		if (attr->keyring_id != VERIFY_USE_BPF_KEYRING) {
+			if (bpf_keyring_enforced()) {
+				verbose(env, "caller-supplied keyring refused, use bpf keyring\n");
+				return -EPERM;
+			}
+			key = bpf_lookup_user_key(attr->keyring_id, 0);
+		} else {
+			key = bpf_lookup_keyring();
+		}
 	}
 	if (!key) {
-		verbose(env, "cannot resolve signing keyring with keyring_id %d\n",
-			attr->keyring_id);
-		return -EINVAL;
+		if (attr->keyring_id == VERIFY_USE_BPF_KEYRING) {
+			verbose(env, "the bpf keyring is empty or has not been restricted\n");
+			return -ENOKEY;
+		} else {
+			verbose(env, "cannot resolve signing keyring with keyring_id %d\n",
+				attr->keyring_id);
+			return -EINVAL;
+		}
 	}
 
 	sig = kvmemdup_bpfptr(usig, attr->signature_size);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.