mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
bpf: Expose signature verdict via bpf_prog_aux
BPF_PROG_LOAD verifies the loader signature but does not record the
outcome on the BPF program. [BPF] LSMs and audit can read attr->signature
and attr->keyring_id to infer "was this signed, and if so, against which
keyring".
Add prog->aux->sig (verdict + keyring_{type,serial}), populated by
bpf_prog_load before the LSM hook. keyring_type classifies the keyring
the load referenced (builtin, secondary, platform or user), while
keyring_serial records the serial of the keyring the signature was
actually validated against. System keyrings carry a pseudo key pointer
with no user-visible serial and are reported as 0, as are unsigned loads.
Failed verifications reject the load before the hook runs, so it observes
only either UNSIGNED or VERIFIED.
Signed-off-by: KP Singh <kpsingh@kernel.org>
Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260605213518.544262-1-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
ba033497f1
commit
63a673e8a4
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/static_call.h>
|
||||
#include <linux/memcontrol.h>
|
||||
#include <linux/cfi.h>
|
||||
#include <linux/key.h>
|
||||
#include <asm/rqspinlock.h>
|
||||
|
||||
struct bpf_verifier_env;
|
||||
|
|
@ -1674,6 +1675,19 @@ struct bpf_stream_stage {
|
|||
int len;
|
||||
};
|
||||
|
||||
enum bpf_sig_verdict {
|
||||
BPF_SIG_UNSIGNED = 0,
|
||||
BPF_SIG_VERIFIED,
|
||||
};
|
||||
|
||||
enum bpf_sig_keyring {
|
||||
BPF_SIG_KEYRING_NONE = 0,
|
||||
BPF_SIG_KEYRING_BUILTIN,
|
||||
BPF_SIG_KEYRING_SECONDARY,
|
||||
BPF_SIG_KEYRING_PLATFORM,
|
||||
BPF_SIG_KEYRING_USER,
|
||||
};
|
||||
|
||||
struct bpf_prog_aux {
|
||||
atomic64_t refcnt;
|
||||
u32 used_map_cnt;
|
||||
|
|
@ -1716,6 +1730,11 @@ struct bpf_prog_aux {
|
|||
bool changes_pkt_data;
|
||||
bool might_sleep;
|
||||
bool kprobe_write_ctx;
|
||||
struct {
|
||||
s32 keyring_serial;
|
||||
u8 keyring_type;
|
||||
u8 verdict;
|
||||
} sig;
|
||||
u64 prog_array_member_cnt; /* counts how many times as member of prog_array */
|
||||
struct mutex ext_mutex; /* mutex for is_extended and prog_array_member_cnt */
|
||||
struct bpf_arena *arena;
|
||||
|
|
@ -3697,8 +3716,14 @@ static inline int bpf_fd_reuseport_array_update_elem(struct bpf_map *map,
|
|||
#endif /* CONFIG_BPF_SYSCALL */
|
||||
#endif /* defined(CONFIG_INET) && defined(CONFIG_BPF_SYSCALL) */
|
||||
|
||||
#if defined(CONFIG_KEYS) && defined(CONFIG_BPF_SYSCALL)
|
||||
#ifdef CONFIG_KEYS
|
||||
struct bpf_key {
|
||||
struct key *key;
|
||||
bool has_ref;
|
||||
};
|
||||
#endif /* CONFIG_KEYS */
|
||||
|
||||
#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);
|
||||
void bpf_key_put(struct bpf_key *bkey);
|
||||
|
|
@ -3706,6 +3731,10 @@ int bpf_verify_pkcs7_signature(const struct bpf_dynptr *data_p,
|
|||
const struct bpf_dynptr *sig_p,
|
||||
struct bpf_key *trusted_keyring);
|
||||
|
||||
static inline s32 bpf_key_serial(const struct bpf_key *key)
|
||||
{
|
||||
return key->has_ref ? key->key->serial : 0;
|
||||
}
|
||||
#else
|
||||
static inline struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags)
|
||||
{
|
||||
|
|
@ -3727,6 +3756,11 @@ static inline int bpf_verify_pkcs7_signature(const struct bpf_dynptr *data_p,
|
|||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline s32 bpf_key_serial(const struct bpf_key *key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* defined(CONFIG_KEYS) && defined(CONFIG_BPF_SYSCALL) */
|
||||
|
||||
/* verifier prototypes for helper functions called from eBPF programs */
|
||||
|
|
@ -4002,15 +4036,6 @@ static inline void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype) {}
|
|||
static inline void bpf_cgroup_atype_put(int cgroup_atype) {}
|
||||
#endif /* CONFIG_BPF_LSM */
|
||||
|
||||
struct key;
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
struct bpf_key {
|
||||
struct key *key;
|
||||
bool has_ref;
|
||||
};
|
||||
#endif /* CONFIG_KEYS */
|
||||
|
||||
static inline bool type_is_alloc(u32 type)
|
||||
{
|
||||
return type & MEM_ALLOC;
|
||||
|
|
|
|||
|
|
@ -2871,8 +2871,22 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
|
|||
}
|
||||
}
|
||||
|
||||
static enum bpf_sig_keyring bpf_classify_keyring(s32 keyring_id)
|
||||
{
|
||||
switch (keyring_id) {
|
||||
case 0:
|
||||
return BPF_SIG_KEYRING_BUILTIN;
|
||||
case (s32)(unsigned long)VERIFY_USE_SECONDARY_KEYRING:
|
||||
return BPF_SIG_KEYRING_SECONDARY;
|
||||
case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING:
|
||||
return BPF_SIG_KEYRING_PLATFORM;
|
||||
default:
|
||||
return BPF_SIG_KEYRING_USER;
|
||||
}
|
||||
}
|
||||
|
||||
static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr,
|
||||
bool is_kernel)
|
||||
bool is_kernel, s32 *keyring_serial)
|
||||
{
|
||||
bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
|
||||
struct bpf_dynptr_kern sig_ptr, insns_ptr;
|
||||
|
|
@ -2908,7 +2922,8 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
|
|||
|
||||
err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
|
||||
(struct bpf_dynptr *)&sig_ptr, key);
|
||||
|
||||
if (!err)
|
||||
*keyring_serial = bpf_key_serial(key);
|
||||
bpf_key_put(key);
|
||||
kvfree(sig);
|
||||
return err;
|
||||
|
|
@ -3095,13 +3110,17 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
|
|||
|
||||
/* eBPF programs must be GPL compatible to use GPL-ed functions */
|
||||
prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
|
||||
|
||||
if (attr->signature) {
|
||||
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel);
|
||||
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel,
|
||||
&prog->aux->sig.keyring_serial);
|
||||
if (err)
|
||||
goto free_prog;
|
||||
prog->aux->sig.keyring_type = bpf_classify_keyring(attr->keyring_id);
|
||||
prog->aux->sig.verdict = BPF_SIG_VERIFIED;
|
||||
} else {
|
||||
prog->aux->sig.keyring_type = BPF_SIG_KEYRING_NONE;
|
||||
prog->aux->sig.verdict = BPF_SIG_UNSIGNED;
|
||||
}
|
||||
|
||||
prog->orig_prog = NULL;
|
||||
prog->jited = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user