[PATCH bpf-next 02/13] bpf: include prog BTF in the signed loader signature scope
KP Singh
kpsingh at kernel.org
Fri May 22 02:32:22 UTC 2026
bpf_prog_verify_signature hashes only prog->insnsi, so FUNC names
in prog BTF are not covered by the signature. Since we need to
support kfuncs for loader programs with prog BTF information, the
signature needs to cover BTF so that it can be trusted.
When attr->prog_btf_fd is set, build the verify dynptr over
insns || raw_btf so the signature covers both. Fall back to insns-only
otherwise so existing signed lskels keep loading. Hoist the
prog_btf_fd resolution into bpf_prog_load so the BTF is available
before signature verification.
Signed-off-by: KP Singh <kpsingh at kernel.org>
---
include/linux/btf.h | 1 +
kernel/bpf/btf.c | 8 +++++++
kernel/bpf/check_btf.c | 18 +++-------------
kernel/bpf/syscall.c | 49 +++++++++++++++++++++++++++++++++++++-----
4 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 48108471c5b1..ab1fe7c8df20 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -216,6 +216,7 @@ int btf_type_snprintf_show(const struct btf *btf, u32 type_id, void *obj,
int btf_get_fd_by_id(u32 id);
u32 btf_obj_id(const struct btf *btf);
bool btf_is_kernel(const struct btf *btf);
+const void *btf_get_raw_data(const struct btf *btf, u32 *data_size);
bool btf_is_module(const struct btf *btf);
bool btf_is_vmlinux(const struct btf *btf);
struct module *btf_try_get_module(const struct btf *btf);
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index a62d78581207..6f1d9b3ba6a3 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8322,11 +8322,19 @@ u32 btf_obj_id(const struct btf *btf)
return READ_ONCE(btf->id);
}
+const void *btf_get_raw_data(const struct btf *btf, u32 *data_size)
+{
+ if (data_size)
+ *data_size = btf->data_size;
+ return btf->data;
+}
+
bool btf_is_kernel(const struct btf *btf)
{
return btf->kernel_btf;
}
+
bool btf_is_module(const struct btf *btf)
{
return btf->kernel_btf && strcmp(btf->name, "vmlinux") != 0;
diff --git a/kernel/bpf/check_btf.c b/kernel/bpf/check_btf.c
index 93bebe6fe12e..c52cc859abac 100644
--- a/kernel/bpf/check_btf.c
+++ b/kernel/bpf/check_btf.c
@@ -411,28 +411,16 @@ int bpf_check_btf_info_early(struct bpf_verifier_env *env,
const union bpf_attr *attr,
bpfptr_t uattr)
{
- struct btf *btf;
- int err;
-
if (!attr->func_info_cnt && !attr->line_info_cnt) {
if (check_abnormal_return(env))
return -EINVAL;
return 0;
}
- btf = btf_get_by_fd(attr->prog_btf_fd);
- if (IS_ERR(btf))
- return PTR_ERR(btf);
- if (btf_is_kernel(btf)) {
- btf_put(btf);
- return -EACCES;
- }
- env->prog->aux->btf = btf;
+ if (env->prog->aux->btf)
+ return check_btf_func_early(env, attr, uattr);
- err = check_btf_func_early(env, attr, uattr);
- if (err)
- return err;
- return 0;
+ return -EINVAL;
}
int bpf_check_btf_info(struct bpf_verifier_env *env,
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 51fe8d77bb39..6d1db5eaad3c 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2816,9 +2816,11 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
bool is_kernel)
{
bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
- struct bpf_dynptr_kern sig_ptr, insns_ptr;
+ struct bpf_dynptr_kern sig_ptr, data_ptr;
struct bpf_key *key = NULL;
- void *sig;
+ u32 insns_sz, btf_sz = 0;
+ const void *btf_data = NULL;
+ void *sig, *data = NULL;
int err = 0;
/*
@@ -2842,14 +2844,34 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
return PTR_ERR(sig);
}
+ insns_sz = prog->len * sizeof(struct bpf_insn);
+
+ if (prog->aux->btf)
+ btf_data = btf_get_raw_data(prog->aux->btf, &btf_sz);
+
+ if (bpf_dynptr_check_size(insns_sz + btf_sz)) {
+ err = -E2BIG;
+ goto out;
+ }
+ data = kvmalloc(insns_sz + btf_sz, GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memcpy(data, prog->insnsi, insns_sz);
+ if (btf_sz)
+ memcpy(data + insns_sz, btf_data, btf_sz);
+
+ bpf_dynptr_init(&data_ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0,
+ insns_sz + btf_sz);
bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0,
attr->signature_size);
- bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0,
- prog->len * sizeof(struct bpf_insn));
- err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
+ err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&data_ptr,
(struct bpf_dynptr *)&sig_ptr, key);
+out:
+ kvfree(data);
bpf_key_put(key);
kvfree(sig);
return err;
@@ -3037,6 +3059,21 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
/* eBPF programs must be GPL compatible to use GPL-ed functions */
prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
+ if (attr->prog_btf_fd) {
+ struct btf *btf = btf_get_by_fd(attr->prog_btf_fd);
+
+ if (IS_ERR(btf)) {
+ err = PTR_ERR(btf);
+ goto free_prog;
+ }
+ if (btf_is_kernel(btf)) {
+ btf_put(btf);
+ err = -EACCES;
+ goto free_prog;
+ }
+ prog->aux->btf = btf;
+ }
+
if (attr->signature) {
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel);
if (err)
@@ -3148,6 +3185,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
free_uid(prog->aux->user);
if (prog->aux->attach_btf)
btf_put(prog->aux->attach_btf);
+ if (prog->aux->btf)
+ btf_put(prog->aux->btf);
bpf_prog_free(prog);
put_token:
bpf_token_put(token);
--
2.53.0
More information about the Linux-security-module-archive
mailing list