[PATCH bpf-next v9 3/9] bpf: Refactor reporting log_true_size for prog_load

Leon Hwang posted 9 patches 4 days, 23 hours ago
[PATCH bpf-next v9 3/9] bpf: Refactor reporting log_true_size for prog_load
Posted by Leon Hwang 4 days, 23 hours ago
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_prog_load_log_attr_init(): initialize the 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 <leon.hwang@linux.dev>
---
 include/linux/bpf.h          |  4 +++-
 include/linux/bpf_verifier.h | 10 ++++++++++
 kernel/bpf/log.c             | 35 +++++++++++++++++++++++++++++++++++
 kernel/bpf/syscall.c         |  8 +++++---
 kernel/bpf/verifier.c        | 13 +++----------
 5 files changed, 56 insertions(+), 14 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 8355b585cd18..c805b85b6f7a 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -631,6 +631,16 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
 	return log && log->level;
 }
 
+struct bpf_log_attr {
+	u32 offsetof_true_size;
+	u32 uattr_size;
+	bpfptr_t uattr;
+};
+
+int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
+				bpfptr_t uattr, u32 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..ff579fcba36f 100644
--- a/kernel/bpf/log.c
+++ b/kernel/bpf/log.c
@@ -863,3 +863,38 @@ void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_st
 	}
 	print_verifier_state(env, vstate, frameno, false);
 }
+
+static void bpf_log_attr_init(struct bpf_log_attr *attr_log, int offsetof_true_size, bpfptr_t uattr,
+			      u32 uattr_size)
+{
+	memset(attr_log, 0, sizeof(*attr_log));
+	attr_log->offsetof_true_size = offsetof_true_size;
+	attr_log->uattr_size = uattr_size;
+	attr_log->uattr = uattr;
+}
+
+int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
+				bpfptr_t uattr, u32 size)
+{
+	bpf_log_attr_init(attr_log, offsetof(union bpf_attr, log_true_size), uattr, size);
+	return 0;
+}
+
+int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log *log)
+{
+	u32 log_true_size;
+	size_t size;
+	int err;
+
+	if (!log)
+		return 0;
+
+	err = bpf_vlog_finalize(log, &log_true_size);
+
+	size = sizeof(log_true_size);
+	if (attr->uattr_size >= attr->offsetof_true_size + size &&
+	    copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, &log_true_size, size))
+		err = -EFAULT;
+
+	return err;
+}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index a58b16735e86..e81199361241 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2860,7 +2860,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;
@@ -3078,7 +3078,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;
 
@@ -6180,6 +6180,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size,
 		     bpfptr_t uattr_common, unsigned int size_common)
 {
 	struct bpf_common_attr attr_common;
+	struct bpf_log_attr attr_log;
 	union bpf_attr attr;
 	int err;
 
@@ -6231,7 +6232,8 @@ 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);
+		err = bpf_prog_load_log_attr_init(&attr_log, &attr, uattr, 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 6b62b6d57175..1489867671e0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -25604,12 +25604,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);
@@ -25808,17 +25808,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
Re: [PATCH bpf-next v9 3/9] bpf: Refactor reporting log_true_size for prog_load
Posted by Andrii Nakryiko 2 days, 17 hours ago
On Mon, Feb 2, 2026 at 6:42 AM Leon Hwang <leon.hwang@linux.dev> 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_prog_load_log_attr_init(): initialize the 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 <leon.hwang@linux.dev>
> ---
>  include/linux/bpf.h          |  4 +++-
>  include/linux/bpf_verifier.h | 10 ++++++++++
>  kernel/bpf/log.c             | 35 +++++++++++++++++++++++++++++++++++
>  kernel/bpf/syscall.c         |  8 +++++---
>  kernel/bpf/verifier.c        | 13 +++----------
>  5 files changed, 56 insertions(+), 14 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 8355b585cd18..c805b85b6f7a 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -631,6 +631,16 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
>         return log && log->level;
>  }
>
> +struct bpf_log_attr {
> +       u32 offsetof_true_size;
> +       u32 uattr_size;
> +       bpfptr_t uattr;
> +};
> +
> +int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
> +                               bpfptr_t uattr, u32 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..ff579fcba36f 100644
> --- a/kernel/bpf/log.c
> +++ b/kernel/bpf/log.c
> @@ -863,3 +863,38 @@ void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_st
>         }
>         print_verifier_state(env, vstate, frameno, false);
>  }
> +
> +static void bpf_log_attr_init(struct bpf_log_attr *attr_log, int offsetof_true_size, bpfptr_t uattr,
> +                             u32 uattr_size)
> +{
> +       memset(attr_log, 0, sizeof(*attr_log));
> +       attr_log->offsetof_true_size = offsetof_true_size;
> +       attr_log->uattr_size = uattr_size;
> +       attr_log->uattr = uattr;
> +}
> +
> +int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
> +                               bpfptr_t uattr, u32 size)
> +{
> +       bpf_log_attr_init(attr_log, offsetof(union bpf_attr, log_true_size), uattr, size);
> +       return 0;
> +}
> +
> +int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log *log)
> +{
> +       u32 log_true_size;
> +       size_t size;
> +       int err;
> +
> +       if (!log)
> +               return 0;

can this ever happen? why guard against this?

> +
> +       err = bpf_vlog_finalize(log, &log_true_size);
> +
> +       size = sizeof(log_true_size);
> +       if (attr->uattr_size >= attr->offsetof_true_size + size &&
> +           copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, &log_true_size, size))
> +               err = -EFAULT;

minor nit: return -EFAULT;

> +
> +       return err;
> +}

[...]
Re: [PATCH bpf-next v9 3/9] bpf: Refactor reporting log_true_size for prog_load
Posted by Leon Hwang 2 days, 11 hours ago

On 5/2/26 03:48, Andrii Nakryiko wrote:
> On Mon, Feb 2, 2026 at 6:42 AM Leon Hwang <leon.hwang@linux.dev> 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_prog_load_log_attr_init(): initialize the 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 <leon.hwang@linux.dev>
>> ---
>>  include/linux/bpf.h          |  4 +++-
>>  include/linux/bpf_verifier.h | 10 ++++++++++
>>  kernel/bpf/log.c             | 35 +++++++++++++++++++++++++++++++++++
>>  kernel/bpf/syscall.c         |  8 +++++---
>>  kernel/bpf/verifier.c        | 13 +++----------
>>  5 files changed, 56 insertions(+), 14 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 8355b585cd18..c805b85b6f7a 100644
>> --- a/include/linux/bpf_verifier.h
>> +++ b/include/linux/bpf_verifier.h
>> @@ -631,6 +631,16 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
>>         return log && log->level;
>>  }
>>
>> +struct bpf_log_attr {
>> +       u32 offsetof_true_size;
>> +       u32 uattr_size;
>> +       bpfptr_t uattr;
>> +};
>> +
>> +int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
>> +                               bpfptr_t uattr, u32 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..ff579fcba36f 100644
>> --- a/kernel/bpf/log.c
>> +++ b/kernel/bpf/log.c
>> @@ -863,3 +863,38 @@ void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_st
>>         }
>>         print_verifier_state(env, vstate, frameno, false);
>>  }
>> +
>> +static void bpf_log_attr_init(struct bpf_log_attr *attr_log, int offsetof_true_size, bpfptr_t uattr,
>> +                             u32 uattr_size)
>> +{
>> +       memset(attr_log, 0, sizeof(*attr_log));
>> +       attr_log->offsetof_true_size = offsetof_true_size;
>> +       attr_log->uattr_size = uattr_size;
>> +       attr_log->uattr = uattr;
>> +}
>> +
>> +int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
>> +                               bpfptr_t uattr, u32 size)
>> +{
>> +       bpf_log_attr_init(attr_log, offsetof(union bpf_attr, log_true_size), uattr, size);
>> +       return 0;
>> +}
>> +
>> +int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log *log)
>> +{
>> +       u32 log_true_size;
>> +       size_t size;
>> +       int err;
>> +
>> +       if (!log)
>> +               return 0;
> 
> can this ever happen? why guard against this?
> 

In patch #7, 'log' can be NULL when users do not provide 'log_buf'.

However, bpf_vlog_finalize() already guards against this case, so I'll
drop this check.

>> +
>> +       err = bpf_vlog_finalize(log, &log_true_size);
>> +
>> +       size = sizeof(log_true_size);
>> +       if (attr->uattr_size >= attr->offsetof_true_size + size &&
>> +           copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, &log_true_size, size))
>> +               err = -EFAULT;
> 
> minor nit: return -EFAULT;
> 

Ack.

Thanks,
Leon