bpf, keys: Add a bpf keyring for program signature validation

BPF program signatures can currently be verified against one of the
system keyrings (builtin, secondary, platform) or against an arbitrary
user/session caller-supplied keyring named through keyring_id. There
is nothing in between: the system keyrings need a kernel rebuild or a
vouched-for enrollment to rotate a key, while a caller-supplied keyring
is fully controlled by the loader and therefore carries no trust on
its own (unless explicitly combined with BPF LSM to protect against
key tampering).

Add a dedicated bpf keyring to fill that gap, modelled after the
dm-verity keyring which was added in commit 033724b1c6 ("dm-verity:
add dm-verity keyring") and which can eventually be used also via
systemd [0] through the same enrollment method as in dm-verity's case.
It is selected with the new KEY_SPEC_BPF_KEYRING special key id and
gives an operator a place to enroll a BPF-only signing key at boot,
specifically scoped to BPF program loading and nothing else in the
kernel's trust hierarchy.

The id is reserved from the KEY_SPEC space so that the latter is not
linked into any process keyring, and lookup_user_key() resolves
KEY_SPEC_BPF_KEYRING constant instead of having to look it up via
/proc/keys first.

By default the keyring is sealed empty at init. Systems that want to
provision keys pass bpf.keyring_unsealed=1, which leaves the keyring
open for the initrd to add keys to. The keyring is only ever consulted
once it is both non-empty and restricted. An unrestricted keyring is
ignored.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://github.com/systemd/systemd/pull/43549 [0]
Link: https://lore.kernel.org/r/20260828175227.1537793-2-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Daniel Borkmann 2026-08-28 19:52:17 +02:00 committed by Alexei Starovoitov
parent 6ae934b5b7
commit 264d8fd279
8 changed files with 123 additions and 0 deletions

View File

@ -667,6 +667,14 @@ Kernel parameters
See Documentation/admin-guide/bootconfig.rst See Documentation/admin-guide/bootconfig.rst
bpf.keyring_unsealed=
[BPF] When set to 1, leave the bpf keyring unsealed
after initialization so that userspace can provision
keys. Once the keyring is restricted it becomes active
and can be used for BPF program signature verification.
See Documentation/bpf/signing.rst
bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards)
bttv.radio= Most important insmod options are available as bttv.radio= Most important insmod options are available as
kernel args too. kernel args too.

View File

@ -1735,6 +1735,7 @@ enum bpf_sig_keyring {
BPF_SIG_KEYRING_SECONDARY, BPF_SIG_KEYRING_SECONDARY,
BPF_SIG_KEYRING_PLATFORM, BPF_SIG_KEYRING_PLATFORM,
BPF_SIG_KEYRING_USER, BPF_SIG_KEYRING_USER,
BPF_SIG_KEYRING_BPF,
}; };
struct bpf_prog_aux { struct bpf_prog_aux {
@ -3819,6 +3820,7 @@ struct bpf_key {
#if defined(CONFIG_KEYS) && defined(CONFIG_BPF_SYSCALL) #if defined(CONFIG_KEYS) && defined(CONFIG_BPF_SYSCALL)
struct bpf_key *bpf_lookup_user_key(s32 serial, u64 flags); 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_system_key(u64 id);
struct bpf_key *bpf_lookup_keyring(void);
void bpf_key_put(struct bpf_key *bkey); void bpf_key_put(struct bpf_key *bkey);
int bpf_verify_pkcs7_signature(const struct bpf_dynptr *data_p, int bpf_verify_pkcs7_signature(const struct bpf_dynptr *data_p,
const struct bpf_dynptr *sig_p, const struct bpf_dynptr *sig_p,
@ -3839,6 +3841,11 @@ static inline struct bpf_key *bpf_lookup_system_key(u64 id)
return NULL; return NULL;
} }
static inline struct bpf_key *bpf_lookup_keyring(void)
{
return NULL;
}
static inline void bpf_key_put(struct bpf_key *bkey) static inline void bpf_key_put(struct bpf_key *bkey)
{ {
} }

View File

@ -440,6 +440,8 @@ extern key_ref_t keyring_search(key_ref_t keyring,
extern int keyring_restrict(key_ref_t keyring, const char *type, extern int keyring_restrict(key_ref_t keyring, const char *type,
const char *restriction); const char *restriction);
extern void key_register_bpf_keyring(struct key *keyring);
extern struct key *key_lookup(key_serial_t id); extern struct key *key_lookup(key_serial_t id);
static inline key_serial_t key_serial(const struct key *key) static inline key_serial_t key_serial(const struct key *key)

View File

@ -24,6 +24,7 @@
#define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */ #define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */
#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */ #define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */
#define KEY_SPEC_REQUESTOR_KEYRING -8 /* - key ID for request_key() dest keyring */ #define KEY_SPEC_REQUESTOR_KEYRING -8 /* - key ID for request_key() dest keyring */
#define KEY_SPEC_BPF_KEYRING -9 /* - key ID for the BPF-specific keyring */
/* request-key default keyrings */ /* request-key default keyrings */
#define KEY_REQKEY_DEFL_NO_CHANGE -1 #define KEY_REQKEY_DEFL_NO_CHANGE -1

View File

@ -27,6 +27,9 @@ obj-$(CONFIG_BPF_SYSCALL) += offload.o
obj-$(CONFIG_BPF_SYSCALL) += net_namespace.o obj-$(CONFIG_BPF_SYSCALL) += net_namespace.o
obj-$(CONFIG_BPF_SYSCALL) += tcx.o obj-$(CONFIG_BPF_SYSCALL) += tcx.o
endif endif
ifeq ($(CONFIG_KEYS),y)
obj-$(CONFIG_BPF_SYSCALL) += keys.o
endif
ifeq ($(CONFIG_PERF_EVENTS),y) ifeq ($(CONFIG_PERF_EVENTS),y)
obj-$(CONFIG_BPF_SYSCALL) += stackmap.o obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
endif endif

68
kernel/bpf/keys.c Normal file
View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2026 Isovalent */
#include <linux/bpf.h>
#include <linux/cred.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/key.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "bpf."
static struct key *bpf_keyring;
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");
struct bpf_key *bpf_lookup_keyring(void)
{
struct bpf_key *bkey;
if (!bpf_keyring)
return NULL;
if (!READ_ONCE(bpf_keyring->keys.nr_leaves_on_tree) ||
!READ_ONCE(bpf_keyring->restrict_link))
return NULL;
bkey = kmalloc_obj(*bkey);
if (!bkey)
return NULL;
bkey->key = bpf_keyring;
bkey->has_ref = false;
return bkey;
}
static int __init bpf_keyring_init(void)
{
struct key *keyring;
keyring = keyring_alloc(".bpf",
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
current_cred(), KEY_POS_SEARCH |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH |
KEY_USR_SETATTR, KEY_ALLOC_NOT_IN_QUOTA,
NULL, NULL);
if (IS_ERR(keyring)) {
pr_err("bpf: cannot allocate bpf keyring: %ld\n",
PTR_ERR(keyring));
return 0;
}
if (!bpf_keyring_unsealed &&
keyring_restrict(make_key_ref(keyring, true), NULL, NULL)) {
pr_err("bpf: cannot seal bpf keyring\n");
key_revoke(keyring);
key_put(keyring);
return 0;
}
bpf_keyring = keyring;
key_register_bpf_keyring(keyring);
return 0;
}
late_initcall(bpf_keyring_init);

View File

@ -24,6 +24,7 @@
#include <linux/bpf_lsm.h> #include <linux/bpf_lsm.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/verification.h> #include <linux/verification.h>
#include <linux/keyctl.h>
#include <linux/btf_ids.h> #include <linux/btf_ids.h>
#include <linux/poison.h> #include <linux/poison.h>
#include <linux/module.h> #include <linux/module.h>
@ -21127,6 +21128,8 @@ static enum bpf_sig_keyring bpf_classify_keyring(s32 keyring_id)
return BPF_SIG_KEYRING_SECONDARY; return BPF_SIG_KEYRING_SECONDARY;
case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING: case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING:
return BPF_SIG_KEYRING_PLATFORM; return BPF_SIG_KEYRING_PLATFORM;
case KEY_SPEC_BPF_KEYRING:
return BPF_SIG_KEYRING_BPF;
default: default:
return BPF_SIG_KEYRING_USER; return BPF_SIG_KEYRING_USER;
} }
@ -21164,9 +21167,15 @@ static int bpf_prog_verify_signature(struct bpf_verifier_env *env,
return -EINVAL; return -EINVAL;
if (system_keyring_id_check(attr->keyring_id) == 0) if (system_keyring_id_check(attr->keyring_id) == 0)
key = bpf_lookup_system_key(attr->keyring_id); key = bpf_lookup_system_key(attr->keyring_id);
else if (attr->keyring_id == KEY_SPEC_BPF_KEYRING)
key = bpf_lookup_keyring();
else else
key = bpf_lookup_user_key(attr->keyring_id, 0); key = bpf_lookup_user_key(attr->keyring_id, 0);
if (!key) { if (!key) {
if (attr->keyring_id == KEY_SPEC_BPF_KEYRING) {
verbose(env, "the bpf keyring is empty or has not been restricted\n");
return -ENOKEY;
}
verbose(env, "cannot resolve signing keyring with keyring_id %d\n", verbose(env, "cannot resolve signing keyring with keyring_id %d\n",
attr->keyring_id); attr->keyring_id);
return -EINVAL; return -EINVAL;

View File

@ -22,6 +22,9 @@
/* Session keyring create vs join semaphore */ /* Session keyring create vs join semaphore */
static DEFINE_MUTEX(key_session_mutex); static DEFINE_MUTEX(key_session_mutex);
/* BPF keyring reachable through KEY_SPEC_BPF_KEYRING */
static struct key *bpf_keyring __ro_after_init;
/* The root user's tracking struct */ /* The root user's tracking struct */
struct key_user root_key_user = { struct key_user root_key_user = {
.usage = REFCOUNT_INIT(3), .usage = REFCOUNT_INIT(3),
@ -590,6 +593,20 @@ bool lookup_user_key_possessed(const struct key *key,
return key == match_data->raw_data; return key == match_data->raw_data;
} }
/**
* key_register_bpf_keyring - Publish the BPF keyring for KEY_SPEC_BPF_KEYRING
* @keyring: The keyring to publish
*
* Make @keyring reachable by userspace through the KEY_SPEC_BPF_KEYRING
* special key ID, so that provisioning it does not require scraping its
* serial out of /proc/keys first. Called once, from an initcall, and never
* undone.
*/
void key_register_bpf_keyring(struct key *keyring)
{
bpf_keyring = keyring;
}
/* /*
* Look up a key ID given us by userspace with a given permissions mask to get * Look up a key ID given us by userspace with a given permissions mask to get
* the key it refers to. * the key it refers to.
@ -741,6 +758,14 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_BPF_KEYRING:
key = bpf_keyring;
if (!key)
goto error;
__key_get(key);
key_ref = make_key_ref(key, 0);
break;
default: default:
key_ref = ERR_PTR(-EINVAL); key_ref = ERR_PTR(-EINVAL);
if (id < 1) if (id < 1)