On Wed, Feb 11, 2026 at 7:13 AM Leon Hwang <[email protected]> wrote: > > The next commit will add support for reporting logs via extended common > attributes, including 'log_true_size'. > > To prepare for that, refactor the 'log_true_size' reporting logic by > introducing a new struct bpf_log_attr to encapsulate log-related behavior: > > * bpf_log_attr_init(): initialize log fields, which will support > extended common attributes in the next commit. > * bpf_log_attr_finalize(): handle log finalization and write back > 'log_true_size' to userspace. > > Signed-off-by: Leon Hwang <[email protected]> > --- > include/linux/bpf.h | 4 +++- > include/linux/bpf_verifier.h | 11 +++++++++++ > kernel/bpf/log.c | 25 +++++++++++++++++++++++++ > kernel/bpf/syscall.c | 13 ++++++++++--- > kernel/bpf/verifier.c | 17 ++++------------- > 5 files changed, 53 insertions(+), 17 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index cd9b96434904..d4dbcc7ad156 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -2913,7 +2913,9 @@ int bpf_check_uarg_tail_zero(bpfptr_t uaddr, size_t > expected_size, > size_t actual_size); > > /* verify correctness of eBPF program */ > -int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr, > u32 uattr_size); > +struct bpf_log_attr; > +int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr, > + struct bpf_log_attr *attr_log); > > #ifndef CONFIG_BPF_JIT_ALWAYS_ON > void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth); > diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h > index ef8e45a362d9..dbd9bdb955b3 100644 > --- a/include/linux/bpf_verifier.h > +++ b/include/linux/bpf_verifier.h > @@ -635,6 +635,17 @@ static inline bool bpf_verifier_log_needed(const struct > bpf_verifier_log *log) > return log && log->level; > } > > +struct bpf_log_attr { > + char __user *log_buf; > + u32 log_size; > + u32 log_level; > + u32 __user *log_true_size; > +}; > + > +int bpf_log_attr_init(struct bpf_log_attr *log, u64 log_buf, u32 log_size, > u32 log_level, > + u32 __user *log_true_size); > +int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log > *log); > + > #define BPF_MAX_SUBPROGS 256 > > struct bpf_subprog_arg_info { > diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c > index a0c3b35de2ce..e31747b84fe2 100644 > --- a/kernel/bpf/log.c > +++ b/kernel/bpf/log.c > @@ -863,3 +863,28 @@ void print_insn_state(struct bpf_verifier_env *env, > const struct bpf_verifier_st > } > print_verifier_state(env, vstate, frameno, false); > } > + > +int bpf_log_attr_init(struct bpf_log_attr *log, u64 log_buf, u32 log_size, > u32 log_level, > + u32 __user *log_true_size) > +{ > + memset(log, 0, sizeof(*log)); > + log->log_buf = u64_to_user_ptr(log_buf); > + log->log_size = log_size; > + log->log_level = log_level; > + log->log_true_size = log_true_size; > + return 0; > +} > + > +int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log > *log) > +{ > + u32 log_true_size; > + int err; > + > + err = bpf_vlog_finalize(log, &log_true_size); > + > + if (attr->log_true_size && copy_to_user(attr->log_true_size, > &log_true_size, > + sizeof(log_true_size))) > + return -EFAULT; > + > + return err; > +} > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c > index 0e231c0b1d04..e86674811996 100644 > --- a/kernel/bpf/syscall.c > +++ b/kernel/bpf/syscall.c > @@ -2867,7 +2867,7 @@ static int bpf_prog_mark_insn_arrays_ready(struct > bpf_prog *prog) > /* last field in 'union bpf_attr' used by this command */ > #define BPF_PROG_LOAD_LAST_FIELD keyring_id > > -static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 > uattr_size) > +static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct > bpf_log_attr *attr_log) > { > enum bpf_prog_type type = attr->prog_type; > struct bpf_prog *prog, *dst_prog = NULL; > @@ -3085,7 +3085,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t > uattr, u32 uattr_size) > goto free_prog_sec; > > /* run eBPF verifier */ > - err = bpf_check(&prog, attr, uattr, uattr_size); > + err = bpf_check(&prog, attr, uattr, attr_log); > if (err < 0) > goto free_used_maps; > > @@ -6189,7 +6189,10 @@ static int prog_assoc_struct_ops(union bpf_attr *attr) > static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size, > bpfptr_t uattr_common, unsigned int size_common) > { > + bool from_user = !bpfptr_is_kernel(uattr); > struct bpf_common_attr attr_common; > + u32 __user *log_true_size = NULL; > + struct bpf_log_attr attr_log; > union bpf_attr attr; > int err; > > @@ -6241,7 +6244,11 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, > unsigned int size, > err = map_freeze(&attr); > break; > case BPF_PROG_LOAD: > - err = bpf_prog_load(&attr, uattr, size); > + if (from_user && size >= offsetofend(union bpf_attr, > log_true_size)) > + log_true_size = uattr.user + offsetof(union bpf_attr, > log_true_size);
LGTM, so Acked-by: Andrii Nakryiko <[email protected]> but it caught my eye that we will never return log_true_size if SYSCALL program tried to load another BPF program (light skeleton case), which seems limiting, but we can perhaps address that separately as a follow up > + err = bpf_log_attr_init(&attr_log, attr.log_buf, > attr.log_size, attr.log_level, > + log_true_size); > + err = err ?: bpf_prog_load(&attr, uattr, &attr_log); > break; > case BPF_OBJ_PIN: > err = bpf_obj_pin(&attr); > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index edf5342b982f..f1447b1878fd 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -25840,12 +25840,12 @@ static int compute_scc(struct bpf_verifier_env *env) > return err; > } > > -int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, > __u32 uattr_size) > +int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, > + struct bpf_log_attr *attr_log) > { > u64 start_time = ktime_get_ns(); > struct bpf_verifier_env *env; > int i, len, ret = -EINVAL, err; > - u32 log_true_size; > bool is_priv; > > BTF_TYPE_EMIT(enum bpf_features); > @@ -25892,9 +25892,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr > *attr, bpfptr_t uattr, __u3 > /* user could have requested verbose verifier output > * and supplied buffer to store the verification trace > */ > - ret = bpf_vlog_init(&env->log, attr->log_level, > - (char __user *) (unsigned long) attr->log_buf, > - attr->log_size); > + ret = bpf_vlog_init(&env->log, attr_log->log_level, > attr_log->log_buf, attr_log->log_size); > if (ret) > goto err_unlock; > > @@ -26044,17 +26042,10 @@ int bpf_check(struct bpf_prog **prog, union > bpf_attr *attr, bpfptr_t uattr, __u3 > env->prog->aux->verified_insns = env->insn_processed; > > /* preserve original error even if log finalization is successful */ > - err = bpf_vlog_finalize(&env->log, &log_true_size); > + err = bpf_log_attr_finalize(attr_log, &env->log); > if (err) > ret = err; > > - if (uattr_size >= offsetofend(union bpf_attr, log_true_size) && > - copy_to_bpfptr_offset(uattr, offsetof(union bpf_attr, > log_true_size), > - &log_true_size, sizeof(log_true_size))) { > - ret = -EFAULT; > - goto err_release_maps; > - } > - > if (ret) > goto err_release_maps; > > -- > 2.52.0 >

