mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
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:
parent
6ae934b5b7
commit
264d8fd279
|
|
@ -667,6 +667,14 @@ Kernel parameters
|
|||
|
||||
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.radio= Most important insmod options are available as
|
||||
kernel args too.
|
||||
|
|
|
|||
|
|
@ -1735,6 +1735,7 @@ enum bpf_sig_keyring {
|
|||
BPF_SIG_KEYRING_SECONDARY,
|
||||
BPF_SIG_KEYRING_PLATFORM,
|
||||
BPF_SIG_KEYRING_USER,
|
||||
BPF_SIG_KEYRING_BPF,
|
||||
};
|
||||
|
||||
struct bpf_prog_aux {
|
||||
|
|
@ -3819,6 +3820,7 @@ struct bpf_key {
|
|||
#if defined(CONFIG_KEYS) && defined(CONFIG_BPF_SYSCALL)
|
||||
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);
|
||||
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,
|
||||
|
|
@ -3839,6 +3841,11 @@ static inline struct bpf_key *bpf_lookup_system_key(u64 id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct bpf_key *bpf_lookup_keyring(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void bpf_key_put(struct bpf_key *bkey)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
const char *restriction);
|
||||
|
||||
extern void key_register_bpf_keyring(struct key *keyring);
|
||||
|
||||
extern struct key *key_lookup(key_serial_t id);
|
||||
|
||||
static inline key_serial_t key_serial(const struct key *key)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#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_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 */
|
||||
#define KEY_REQKEY_DEFL_NO_CHANGE -1
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ obj-$(CONFIG_BPF_SYSCALL) += offload.o
|
|||
obj-$(CONFIG_BPF_SYSCALL) += net_namespace.o
|
||||
obj-$(CONFIG_BPF_SYSCALL) += tcx.o
|
||||
endif
|
||||
ifeq ($(CONFIG_KEYS),y)
|
||||
obj-$(CONFIG_BPF_SYSCALL) += keys.o
|
||||
endif
|
||||
ifeq ($(CONFIG_PERF_EVENTS),y)
|
||||
obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
|
||||
endif
|
||||
|
|
|
|||
68
kernel/bpf/keys.c
Normal file
68
kernel/bpf/keys.c
Normal 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);
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/bpf_lsm.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/verification.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/btf_ids.h>
|
||||
#include <linux/poison.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;
|
||||
case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING:
|
||||
return BPF_SIG_KEYRING_PLATFORM;
|
||||
case KEY_SPEC_BPF_KEYRING:
|
||||
return BPF_SIG_KEYRING_BPF;
|
||||
default:
|
||||
return BPF_SIG_KEYRING_USER;
|
||||
}
|
||||
|
|
@ -21164,9 +21167,15 @@ static int bpf_prog_verify_signature(struct bpf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
if (system_keyring_id_check(attr->keyring_id) == 0)
|
||||
key = bpf_lookup_system_key(attr->keyring_id);
|
||||
else if (attr->keyring_id == KEY_SPEC_BPF_KEYRING)
|
||||
key = bpf_lookup_keyring();
|
||||
else
|
||||
key = bpf_lookup_user_key(attr->keyring_id, 0);
|
||||
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",
|
||||
attr->keyring_id);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
/* Session keyring create vs join semaphore */
|
||||
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 */
|
||||
struct key_user root_key_user = {
|
||||
.usage = REFCOUNT_INIT(3),
|
||||
|
|
@ -590,6 +593,20 @@ bool lookup_user_key_possessed(const struct key *key,
|
|||
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
|
||||
* 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);
|
||||
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:
|
||||
key_ref = ERR_PTR(-EINVAL);
|
||||
if (id < 1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user