Skip to content

Commit 0cee967

Browse files
committed
bpf: Implement signature verification for BPF programs
This patch extends the BPF_PROG_LOAD command by adding three new fields to `union bpf_attr` in the user-space API: - signature: A pointer to the signature blob. - signature_size: The size of the signature blob. - keyring_id: The serial number of a loaded kernel keyring (e.g., the user or session keyring) containing the trusted public keys. When a BPF program is loaded with a signature, the kernel: 1. Retrieves the trusted keyring using the provided `keyring_id`. 2. Verifies the supplied signature against the BPF program's instruction buffer. 3. If the signature is valid and was generated by a key in the trusted keyring, the program load proceeds. 4. If no signature is provided, the load proceeds as before, allowing for backward compatibility. LSMs can chose to restrict unsigned programs and implement a security policy. 5. If signature verification fails for any reason, the program is not loaded. Signed-off-by: KP Singh <[email protected]>
1 parent 826a517 commit 0cee967

File tree

7 files changed

+66
-3
lines changed

7 files changed

+66
-3
lines changed

crypto/asymmetric_keys/pkcs7_verify.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
429429
/* Authattr presence checked in parser */
430430
break;
431431
case VERIFYING_UNSPECIFIED_SIGNATURE:
432+
case VERIFYING_BPF_SIGNATURE:
432433
if (pkcs7->data_type != OID_data) {
433434
pr_warn("Invalid unspecified sig (not pkcs7-data)\n");
434435
return -EKEYREJECTED;

include/linux/verification.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum key_being_used_for {
3636
VERIFYING_KEY_SIGNATURE,
3737
VERIFYING_KEY_SELF_SIGNATURE,
3838
VERIFYING_UNSPECIFIED_SIGNATURE,
39+
VERIFYING_BPF_SIGNATURE,
3940
NR__KEY_BEING_USED_FOR
4041
};
4142
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION

include/uapi/linux/bpf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,16 @@ union bpf_attr {
16071607
* continuous.
16081608
*/
16091609
__u32 fd_array_cnt;
1610+
/* Pointer to a buffer containing the signature of the BPF
1611+
* program.
1612+
*/
1613+
__aligned_u64 signature;
1614+
/* Size of the signature buffer in bytes. */
1615+
__u32 signature_size;
1616+
/* ID of the kernel keyring to be used for signature
1617+
* verification.
1618+
*/
1619+
__s32 keyring_id;
16101620
};
16111621

16121622
struct { /* anonymous struct used by BPF_OBJ_* commands */

kernel/bpf/helpers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3853,7 +3853,7 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p,
38533853

38543854
return verify_pkcs7_signature(data, data_len, sig, sig_len,
38553855
trusted_keyring->key,
3856-
VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
3856+
VERIFYING_BPF_SIGNATURE, NULL,
38573857
NULL);
38583858
#else
38593859
return -EOPNOTSUPP;

kernel/bpf/syscall.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <linux/tracepoint.h>
4040
#include <linux/overflow.h>
4141
#include <linux/cookie.h>
42+
#include <linux/verification.h>
4243

4344
#include <net/netfilter/nf_bpf_link.h>
4445
#include <net/netkit.h>
@@ -2786,8 +2787,42 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
27862787
}
27872788
}
27882789

2790+
static noinline int bpf_prog_verify_signature(struct bpf_prog *prog,
2791+
union bpf_attr *attr,
2792+
bool is_kernel)
2793+
{
2794+
bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
2795+
struct bpf_dynptr_kern sig_ptr, insns_ptr;
2796+
struct bpf_key *key = NULL;
2797+
void *sig;
2798+
int err = 0;
2799+
2800+
if (system_keyring_id_check(attr->keyring_id) == 0)
2801+
key = bpf_lookup_system_key(attr->keyring_id);
2802+
else
2803+
key = bpf_lookup_user_key(attr->keyring_id, 0);
2804+
2805+
sig = kvmemdup_bpfptr(usig, attr->signature_size);
2806+
if (IS_ERR(sig)) {
2807+
bpf_key_put(key);
2808+
return -ENOMEM;
2809+
}
2810+
2811+
bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0,
2812+
attr->signature_size);
2813+
bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0,
2814+
prog->len * sizeof(struct bpf_insn));
2815+
2816+
err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
2817+
(struct bpf_dynptr *)&sig_ptr, key);
2818+
2819+
bpf_key_put(key);
2820+
kvfree(sig);
2821+
return err;
2822+
}
2823+
27892824
/* last field in 'union bpf_attr' used by this command */
2790-
#define BPF_PROG_LOAD_LAST_FIELD fd_array_cnt
2825+
#define BPF_PROG_LOAD_LAST_FIELD keyring_id
27912826

27922827
static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
27932828
{
@@ -2951,6 +2986,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
29512986
/* eBPF programs must be GPL compatible to use GPL-ed functions */
29522987
prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
29532988

2989+
if (attr->signature) {
2990+
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel);
2991+
if (err)
2992+
goto free_prog;
2993+
}
2994+
29542995
prog->orig_prog = NULL;
29552996
prog->jited = 0;
29562997

tools/include/uapi/linux/bpf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,16 @@ union bpf_attr {
16071607
* continuous.
16081608
*/
16091609
__u32 fd_array_cnt;
1610+
/* Pointer to a buffer containing the signature of the BPF
1611+
* program.
1612+
*/
1613+
__aligned_u64 signature;
1614+
/* Size of the signature buffer in bytes. */
1615+
__u32 signature_size;
1616+
/* ID of the kernel keyring to be used for signature
1617+
* verification.
1618+
*/
1619+
__s32 keyring_id;
16101620
};
16111621

16121622
struct { /* anonymous struct used by BPF_OBJ_* commands */

tools/lib/bpf/bpf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
240240
const struct bpf_insn *insns, size_t insn_cnt,
241241
struct bpf_prog_load_opts *opts)
242242
{
243-
const size_t attr_sz = offsetofend(union bpf_attr, fd_array_cnt);
243+
const size_t attr_sz = offsetofend(union bpf_attr, keyring_id);
244244
void *finfo = NULL, *linfo = NULL;
245245
const char *func_info, *line_info;
246246
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;

0 commit comments

Comments
 (0)