]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Expose signature verdict via bpf_prog_aux
authorKP Singh <kpsingh@kernel.org>
Fri, 5 Jun 2026 21:35:17 +0000 (23:35 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 6 Jun 2026 03:33:48 +0000 (20:33 -0700)
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>
include/linux/bpf.h
kernel/bpf/syscall.c

index 8599b451dd7a29c68d4a5fc60669364b61a1d61a..f615b56730d2546c82b92eb595e3290e332a0b09 100644 (file)
@@ -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;
index c5d4ae957e87dbc0a6fabae88a1b3572c861324b..5fcfc32c7cb440a43b60d91b3ba8fcf6dc9a6702 100644 (file)
@@ -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;