[PATCH bpf-next v2 1/5] bpf: Verify signed loader metadata at load time

Daniel Borkmann daniel at iogearbox.net
Wed Jun 24 15:37:17 UTC 2026


Hi Paul,

On 6/24/26 5:12 PM, Paul Moore wrote:
> On Wed, Jun 24, 2026 at 10:03 AM Daniel Borkmann <daniel at iogearbox.net> wrote:
[...]
>>   include/linux/bpf_verifier.h |   1 +
>>   kernel/bpf/syscall.c         |  76 +---------------
>>   kernel/bpf/verifier.c        | 163 ++++++++++++++++++++++++++++++++++-
>>   3 files changed, 165 insertions(+), 75 deletions(-)
> 
> ...
> 
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index b44106c8ea75..026b61d78bdb 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -3189,10 +3121,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
>>          if (err < 0)
>>                  goto free_prog;
>>
>> -       err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel);
>> -       if (err)
>> -               goto free_prog;
>> -
>>          /* run eBPF verifier */
>>          err = bpf_check(&prog, attr, uattr, attr_log);
>>          if (err < 0)
> 
> We must preserve the existing location of the call into the
> security_bpf_prog_load() hook as some users rely on this hook being
> called *before* the verifier runs.

Keep in mind that the verifier /at this point/ of the new location did
_not_ verify anything. So there is no heavy-duty work happening yet at
security_bpf_prog_load. The work that is done before security_bpf_prog_load
is basically setting up the env, initializing the verifier log, and doing
the process_fd_array which is resolving the map/BTF objects. But it did
not walk any instructions etc, so semantics of the security_bpf_prog_load
hook did not change from a user PoV.

>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 2abc79dbf281..9cd2b62da380 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -19758,11 +19895,28 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
>>          ret = bpf_vlog_init(&env->log, attr_log->level, attr_log->ubuf, attr_log->size);
>>          if (ret)
>>                  goto err_unlock;
>> +       if (env->check_signature) {
>> +               ret = bpf_prog_calc_tag(env->prog);
>> +               if (ret < 0)
>> +                       goto skip_full_check;
>> +       }
>>
>>          ret = process_fd_array(env, attr, uattr);
>>          if (ret)
>>                  goto skip_full_check;
>>
>> +       if (env->check_signature) {
>> +               ret = bpf_prog_verify_signature(env, attr, uattr.is_kernel);
>> +               if (ret)
>> +                       goto skip_full_check;
>> +               signed_map_cnt = env->used_map_cnt;
>> +       }
>> +
>> +       ret = security_bpf_prog_load(env->prog, attr, env->prog->aux->token,
>> +                                    uattr.is_kernel);
>> +       if (ret)
>> +               goto skip_full_check;
> 
> We can always create a new LSM hook for this call site, e.g.
> security_bpf_prog_verify_signature(...).
> 
>>          mark_verifier_state_clean(env);
>>
>>          if (IS_ERR(btf_vmlinux)) {
> 




More information about the Linux-security-module-archive mailing list