Skip to content

Commit 3492715

Browse files
sinkapAlexei Starovoitov
authored andcommitted
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. Tested-by: [email protected] Signed-off-by: KP Singh <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 5a427fd commit 3492715

File tree

7 files changed

+68
-3
lines changed

7 files changed

+68
-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
@@ -1611,6 +1611,16 @@ union bpf_attr {
16111611
* continuous.
16121612
*/
16131613
__u32 fd_array_cnt;
1614+
/* Pointer to a buffer containing the signature of the BPF
1615+
* program.
1616+
*/
1617+
__aligned_u64 signature;
1618+
/* Size of the signature buffer in bytes. */
1619+
__u32 signature_size;
1620+
/* ID of the kernel keyring to be used for signature
1621+
* verification.
1622+
*/
1623+
__s32 keyring_id;
16141624
};
16151625

16161626
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
@@ -3898,7 +3898,7 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p,
38983898

38993899
return verify_pkcs7_signature(data, data_len, sig, sig_len,
39003900
trusted_keyring->key,
3901-
VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
3901+
VERIFYING_BPF_SIGNATURE, NULL,
39023902
NULL);
39033903
#else
39043904
return -EOPNOTSUPP;

kernel/bpf/syscall.c

Lines changed: 44 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>
@@ -2785,8 +2786,44 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
27852786
}
27862787
}
27872788

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

27912828
static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
27922829
{
@@ -2950,6 +2987,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
29502987
/* eBPF programs must be GPL compatible to use GPL-ed functions */
29512988
prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
29522989

2990+
if (attr->signature) {
2991+
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel);
2992+
if (err)
2993+
goto free_prog;
2994+
}
2995+
29532996
prog->orig_prog = NULL;
29542997
prog->jited = 0;
29552998

tools/include/uapi/linux/bpf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,16 @@ union bpf_attr {
16111611
* continuous.
16121612
*/
16131613
__u32 fd_array_cnt;
1614+
/* Pointer to a buffer containing the signature of the BPF
1615+
* program.
1616+
*/
1617+
__aligned_u64 signature;
1618+
/* Size of the signature buffer in bytes. */
1619+
__u32 signature_size;
1620+
/* ID of the kernel keyring to be used for signature
1621+
* verification.
1622+
*/
1623+
__s32 keyring_id;
16141624
};
16151625

16161626
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)