* [PATCH bpf-next v1 0/3] Add support to emit verifier warnings
@ 2026-03-29 21:25 Kumar Kartikeya Dwivedi
2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd,
kernel-team
Currently, there are only two ways of communicating information to the user
when a program is verified, success or failure with a verbose verifier log.
Some information is meant to be more discretionary, e.g. warning about use of
kfuncs that are deprecated, and may be removed in future kernel releases.
For this purpose, we can make use of the program's stderr stream. Until the
program is finished loading and actually attached somewhere, it cannot write to
its own stream. This means that there is a point where all collected verifier
warnings can be flushed and displayed to the user.
An example is shown below.
$ ./test_progs -t kfunc_implicit_args/test_kfunc_implicit_arg_legacy_impl -v
...
libbpf: prog 'test_kfunc_implicit_arg_legacy_impl': VERIFIER WARNINGS:
WARNING: kfunc_implicit_args.c:40 calls deprecated kfunc bpf_kfunc_implicit_arg_legacy_impl(), which will be removed.
WARNING: Switch to kfunc bpf_kfunc_implicit_arg_legacy() instead.
WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(bpf_kfunc_implicit_arg_legacy).
...
Once GCC BTF tags are available this can be done by annotating kfuncs with
appropriate tags containing the deprecation message, until then we put it in
the verifier for _impl suffixed kfuncs that have been replaced with
KF_IMPLICIT_ARGS variants.
Kumar Kartikeya Dwivedi (3):
bpf: Extract bpf_get_linfo_file_line
bpf: Emit verifier warnings through prog stderr
libbpf: Wire up verifier warning display logic
include/linux/bpf.h | 11 ++++++++
include/linux/bpf_verifier.h | 3 +-
kernel/bpf/core.c | 32 ++++++++++++++++------
kernel/bpf/log.c | 6 ++--
kernel/bpf/verifier.c | 53 ++++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.c | 23 ++++++++++++++++
6 files changed, 115 insertions(+), 13 deletions(-)
base-commit: b6b5e0ebd429d66ce37ae5af649a74ea1f041d92
--
2.52.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line 2026-03-29 21:25 [PATCH bpf-next v1 0/3] Add support to emit verifier warnings Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 ` Kumar Kartikeya Dwivedi 2026-03-30 11:28 ` Mykyta Yatsenko ` (2 more replies) 2026-03-29 21:25 ` [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr Kumar Kartikeya Dwivedi 2026-03-29 21:25 ` [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic Kumar Kartikeya Dwivedi 2 siblings, 3 replies; 12+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Extract bpf_get_linfo_file_line as its own function so that the logic to obtain the file, line, and line number for a given program can be shared in subsequent patches. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> --- include/linux/bpf.h | 2 ++ kernel/bpf/core.c | 32 +++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 05b34a6355b0..2c4f92085d79 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -3946,6 +3946,8 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog) return prog->aux->func_idx != 0; } +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, + const char **filep, const char **linep, int *nump); int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, const char **linep, int *nump); struct bpf_prog *bpf_prog_find_from_stack(void); diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 1af5fb3f21d9..052dd78a2d81 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -3313,6 +3313,28 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(xdp_bulk_tx); #ifdef CONFIG_BPF_SYSCALL +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, + const char **filep, const char **linep, int *nump) +{ + /* Get base component of the file path. */ + if (filep) { + *filep = btf_name_by_offset(btf, linfo->file_name_off); + *filep = kbasename(*filep); + } + + /* Obtain the source line, and strip whitespace in prefix. */ + if (linep) { + *linep = btf_name_by_offset(btf, linfo->line_off); + while (isspace(**linep)) + *linep += 1; + } + + if (nump) + *nump = BPF_LINE_INFO_LINE_NUM(linfo->line_col); + + return 0; +} + int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, const char **linep, int *nump) { @@ -3347,15 +3369,7 @@ int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char * if (idx == -1) return -ENOENT; - /* Get base component of the file path. */ - *filep = btf_name_by_offset(btf, linfo[idx].file_name_off); - *filep = kbasename(*filep); - /* Obtain the source line, and strip whitespace in prefix. */ - *linep = btf_name_by_offset(btf, linfo[idx].line_off); - while (isspace(**linep)) - *linep += 1; - *nump = BPF_LINE_INFO_LINE_NUM(linfo[idx].line_col); - return 0; + return bpf_get_linfo_file_line(btf, &linfo[idx], filep, linep, nump); } struct walk_stack_ctx { -- 2.52.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line 2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi @ 2026-03-30 11:28 ` Mykyta Yatsenko 2026-03-30 12:27 ` Puranjay Mohan 2026-03-30 12:35 ` Puranjay Mohan 2 siblings, 0 replies; 12+ messages in thread From: Mykyta Yatsenko @ 2026-03-30 11:28 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi, bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Kumar Kartikeya Dwivedi <memxor@gmail.com> writes: > Extract bpf_get_linfo_file_line as its own function so that the logic to > obtain the file, line, and line number for a given program can be shared > in subsequent patches. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > --- The patch extracted bpf_get_linfo_file_line() and modified it slightly to support optional output arguments. Acked-by: Mykyta Yatsenko <yatsenko@meta.com> > include/linux/bpf.h | 2 ++ > kernel/bpf/core.c | 32 +++++++++++++++++++++++--------- > 2 files changed, 25 insertions(+), 9 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 05b34a6355b0..2c4f92085d79 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -3946,6 +3946,8 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog) > return prog->aux->func_idx != 0; > } > > +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, > + const char **filep, const char **linep, int *nump); > int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, > const char **linep, int *nump); > struct bpf_prog *bpf_prog_find_from_stack(void); > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 1af5fb3f21d9..052dd78a2d81 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -3313,6 +3313,28 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(xdp_bulk_tx); > > #ifdef CONFIG_BPF_SYSCALL > > +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, > + const char **filep, const char **linep, int *nump) > +{ > + /* Get base component of the file path. */ > + if (filep) { > + *filep = btf_name_by_offset(btf, linfo->file_name_off); > + *filep = kbasename(*filep); > + } > + > + /* Obtain the source line, and strip whitespace in prefix. */ > + if (linep) { > + *linep = btf_name_by_offset(btf, linfo->line_off); > + while (isspace(**linep)) > + *linep += 1; > + } > + > + if (nump) > + *nump = BPF_LINE_INFO_LINE_NUM(linfo->line_col); > + > + return 0; > +} > + > int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, > const char **linep, int *nump) > { > @@ -3347,15 +3369,7 @@ int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char * > if (idx == -1) > return -ENOENT; > > - /* Get base component of the file path. */ > - *filep = btf_name_by_offset(btf, linfo[idx].file_name_off); > - *filep = kbasename(*filep); > - /* Obtain the source line, and strip whitespace in prefix. */ > - *linep = btf_name_by_offset(btf, linfo[idx].line_off); > - while (isspace(**linep)) > - *linep += 1; > - *nump = BPF_LINE_INFO_LINE_NUM(linfo[idx].line_col); > - return 0; > + return bpf_get_linfo_file_line(btf, &linfo[idx], filep, linep, nump); > } > > struct walk_stack_ctx { > -- > 2.52.0 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line 2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi 2026-03-30 11:28 ` Mykyta Yatsenko @ 2026-03-30 12:27 ` Puranjay Mohan 2026-03-30 12:35 ` Puranjay Mohan 2 siblings, 0 replies; 12+ messages in thread From: Puranjay Mohan @ 2026-03-30 12:27 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi, bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Kumar Kartikeya Dwivedi <memxor@gmail.com> writes: > Extract bpf_get_linfo_file_line as its own function so that the logic to > obtain the file, line, and line number for a given program can be shared > in subsequent patches. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Reviewed-by: Puranjay Mohan <puranjay@kernel.org> > --- > include/linux/bpf.h | 2 ++ > kernel/bpf/core.c | 32 +++++++++++++++++++++++--------- > 2 files changed, 25 insertions(+), 9 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 05b34a6355b0..2c4f92085d79 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -3946,6 +3946,8 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog) > return prog->aux->func_idx != 0; > } > > +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, > + const char **filep, const char **linep, int *nump); > int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, > const char **linep, int *nump); > struct bpf_prog *bpf_prog_find_from_stack(void); > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 1af5fb3f21d9..052dd78a2d81 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -3313,6 +3313,28 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(xdp_bulk_tx); > > #ifdef CONFIG_BPF_SYSCALL > > +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, > + const char **filep, const char **linep, int *nump) > +{ > + /* Get base component of the file path. */ > + if (filep) { > + *filep = btf_name_by_offset(btf, linfo->file_name_off); > + *filep = kbasename(*filep); > + } > + > + /* Obtain the source line, and strip whitespace in prefix. */ > + if (linep) { > + *linep = btf_name_by_offset(btf, linfo->line_off); > + while (isspace(**linep)) > + *linep += 1; > + } > + > + if (nump) > + *nump = BPF_LINE_INFO_LINE_NUM(linfo->line_col); > + > + return 0; > +} > + > int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, > const char **linep, int *nump) > { > @@ -3347,15 +3369,7 @@ int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char * > if (idx == -1) > return -ENOENT; > > - /* Get base component of the file path. */ > - *filep = btf_name_by_offset(btf, linfo[idx].file_name_off); > - *filep = kbasename(*filep); > - /* Obtain the source line, and strip whitespace in prefix. */ > - *linep = btf_name_by_offset(btf, linfo[idx].line_off); > - while (isspace(**linep)) > - *linep += 1; > - *nump = BPF_LINE_INFO_LINE_NUM(linfo[idx].line_col); > - return 0; > + return bpf_get_linfo_file_line(btf, &linfo[idx], filep, linep, nump); > } > > struct walk_stack_ctx { > -- > 2.52.0 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line 2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi 2026-03-30 11:28 ` Mykyta Yatsenko 2026-03-30 12:27 ` Puranjay Mohan @ 2026-03-30 12:35 ` Puranjay Mohan 2 siblings, 0 replies; 12+ messages in thread From: Puranjay Mohan @ 2026-03-30 12:35 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi, bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Kumar Kartikeya Dwivedi <memxor@gmail.com> writes: > Extract bpf_get_linfo_file_line as its own function so that the logic to > obtain the file, line, and line number for a given program can be shared > in subsequent patches. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > --- > include/linux/bpf.h | 2 ++ > kernel/bpf/core.c | 32 +++++++++++++++++++++++--------- > 2 files changed, 25 insertions(+), 9 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 05b34a6355b0..2c4f92085d79 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -3946,6 +3946,8 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog) > return prog->aux->func_idx != 0; > } > > +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, > + const char **filep, const char **linep, int *nump); > int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, > const char **linep, int *nump); > struct bpf_prog *bpf_prog_find_from_stack(void); > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 1af5fb3f21d9..052dd78a2d81 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -3313,6 +3313,28 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(xdp_bulk_tx); > > #ifdef CONFIG_BPF_SYSCALL > > +int bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo, > + const char **filep, const char **linep, int *nump) > +{ > + /* Get base component of the file path. */ > + if (filep) { > + *filep = btf_name_by_offset(btf, linfo->file_name_off); > + *filep = kbasename(*filep); > + } > + > + /* Obtain the source line, and strip whitespace in prefix. */ > + if (linep) { > + *linep = btf_name_by_offset(btf, linfo->line_off); > + while (isspace(**linep)) > + *linep += 1; > + } > + > + if (nump) > + *nump = BPF_LINE_INFO_LINE_NUM(linfo->line_col); > + > + return 0; Nit: Just realized that this always returns 0, should be make this return void? > +} > + > int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char **filep, > const char **linep, int *nump) > { > @@ -3347,15 +3369,7 @@ int bpf_prog_get_file_line(struct bpf_prog *prog, unsigned long ip, const char * > if (idx == -1) > return -ENOENT; > > - /* Get base component of the file path. */ > - *filep = btf_name_by_offset(btf, linfo[idx].file_name_off); > - *filep = kbasename(*filep); > - /* Obtain the source line, and strip whitespace in prefix. */ > - *linep = btf_name_by_offset(btf, linfo[idx].line_off); > - while (isspace(**linep)) > - *linep += 1; > - *nump = BPF_LINE_INFO_LINE_NUM(linfo[idx].line_col); > - return 0; > + return bpf_get_linfo_file_line(btf, &linfo[idx], filep, linep, nump); > } > > struct walk_stack_ctx { > -- > 2.52.0 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr 2026-03-29 21:25 [PATCH bpf-next v1 0/3] Add support to emit verifier warnings Kumar Kartikeya Dwivedi 2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 ` Kumar Kartikeya Dwivedi 2026-03-30 11:39 ` Mykyta Yatsenko 2026-03-30 15:02 ` Alexei Starovoitov 2026-03-29 21:25 ` [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic Kumar Kartikeya Dwivedi 2 siblings, 2 replies; 12+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team There is a class of messages that aren't treated as hard errors, such that the program must be rejected, but should be surfaced to the user to make them aware that while the program succeeded, parts of their program are exhibiting behavior that needs attention. One example is usage of kfuncs that are supposed to be deprecated, and may be dropped in the future, though are preserved for now for backwards compatibility. Add support for emitting a warning message to the BPF program's stderr stream whenever we detect usage of a _impl suffixed kfunc, which have now been replaced with KF_IMPLICIT_ARGS variants. For this purpose, introduce bpf_stream_pr_warn() as a convenience wrapper, and then mark bpf_find_linfo() as global to allow its usage in the verifier to find the linfo corresponding to an instruction index. To make the message more helpful, recommend usage of bpf_ksym_exists() as a way for the user to write backwards compatible BPF code that works on older kernels offering _impl suffixed kfuncs. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> --- include/linux/bpf.h | 9 ++++++ include/linux/bpf_verifier.h | 3 +- kernel/bpf/log.c | 6 ++-- kernel/bpf/verifier.c | 53 ++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 2c4f92085d79..d0158edd27b2 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -3912,6 +3912,15 @@ int bpf_stream_stage_dump_stack(struct bpf_stream_stage *ss); bpf_stream_stage_free(&ss); \ }) +#define bpf_stream_pr_warn(prog, fmt, ...) \ + ({ \ + struct bpf_stream_stage __ss; \ + \ + bpf_stream_stage(__ss, prog, BPF_STDERR, ({ \ + bpf_stream_printk(__ss, fmt, ##__VA_ARGS__); \ + })); \ + }) + #ifdef CONFIG_BPF_LSM void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype); void bpf_cgroup_atype_put(int cgroup_atype); diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 090aa26d1c98..5683c06f5a90 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -873,7 +873,8 @@ int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level, char __user *log_buf, u32 log_size); void bpf_vlog_reset(struct bpf_verifier_log *log, u64 new_pos); int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual); - +const struct bpf_line_info *bpf_find_linfo(const struct bpf_verifier_env *env, + u32 insn_off); __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, u32 insn_off, const char *prefix_fmt, ...); diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 37d72b052192..598b494ded36 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -329,8 +329,8 @@ __printf(2, 3) void bpf_log(struct bpf_verifier_log *log, } EXPORT_SYMBOL_GPL(bpf_log); -static const struct bpf_line_info * -find_linfo(const struct bpf_verifier_env *env, u32 insn_off) +const struct bpf_line_info * +bpf_find_linfo(const struct bpf_verifier_env *env, u32 insn_off) { const struct bpf_line_info *linfo; const struct bpf_prog *prog; @@ -390,7 +390,7 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, return; prev_linfo = env->prev_linfo; - linfo = find_linfo(env, insn_off); + linfo = bpf_find_linfo(env, insn_off); if (!linfo || linfo == prev_linfo) return; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8c1cf2eb6cbb..f50e0ebd0ded 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3206,6 +3206,7 @@ struct bpf_kfunc_desc { u32 func_id; s32 imm; u16 offset; + bool warned_deprecated; unsigned long addr; }; @@ -14045,6 +14046,53 @@ static int fetch_kfunc_arg_meta(struct bpf_verifier_env *env, return 0; } +static bool get_insn_file_line(const struct bpf_verifier_env *env, u32 insn_off, + const char **filep, int *linep) +{ + const struct bpf_line_info *linfo; + + if (!env->prog->aux->btf) + return false; + + linfo = bpf_find_linfo(env, insn_off); + if (!linfo) + return false; + + if (bpf_get_linfo_file_line(env->prog->aux->btf, linfo, filep, NULL, linep)) + return false; + return true; +} + +static void warn_for_deprecated_kfuncs(struct bpf_verifier_env *env, + struct bpf_kfunc_desc *desc, + const char *func_name, + int insn_idx) +{ + int repl_len, line; + const char *file; + + if (desc->warned_deprecated) + return; + + if (!func_name || !strends(func_name, KF_IMPL_SUFFIX)) + return; + + repl_len = strlen(func_name) - strlen(KF_IMPL_SUFFIX); + + if (get_insn_file_line(env, insn_idx, &file, &line)) + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s:%u", file, line); + else + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "insn #%d", insn_idx); + + bpf_stream_pr_warn(env->prog, + "WARNING: %s calls deprecated kfunc %s(), which will be removed.\n" + "WARNING: Switch to kfunc %.*s() instead.\n" + "WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(%.*s).\n", + env->tmp_str_buf, func_name, repl_len, func_name, repl_len, func_name); + + desc->warned_deprecated = true; +} + /* check special kfuncs and return: * 1 - not fall-through to 'else' branch, continue verification * 0 - fall-through to 'else' branch @@ -14231,6 +14279,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, { bool sleepable, rcu_lock, rcu_unlock, preempt_disable, preempt_enable; u32 i, nargs, ptr_type_id, release_ref_obj_id; + struct bpf_kfunc_desc *desc; struct bpf_reg_state *regs = cur_regs(env); const char *func_name, *ptr_type_name; const struct btf_type *t, *ptr_type; @@ -14253,6 +14302,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, func_name = meta.func_name; insn_aux = &env->insn_aux_data[insn_idx]; + desc = find_kfunc_desc(env->prog, insn->imm, insn->off); + if (desc) + warn_for_deprecated_kfuncs(env, desc, func_name, insn_idx); + insn_aux->is_iter_next = is_iter_next_kfunc(&meta); if (!insn->off && -- 2.52.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr 2026-03-29 21:25 ` [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr Kumar Kartikeya Dwivedi @ 2026-03-30 11:39 ` Mykyta Yatsenko 2026-03-30 12:39 ` Puranjay Mohan 2026-03-30 15:02 ` Alexei Starovoitov 1 sibling, 1 reply; 12+ messages in thread From: Mykyta Yatsenko @ 2026-03-30 11:39 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi, bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Kumar Kartikeya Dwivedi <memxor@gmail.com> writes: > There is a class of messages that aren't treated as hard errors, such > that the program must be rejected, but should be surfaced to the user to > make them aware that while the program succeeded, parts of their program > are exhibiting behavior that needs attention. One example is usage of > kfuncs that are supposed to be deprecated, and may be dropped in the > future, though are preserved for now for backwards compatibility. > > Add support for emitting a warning message to the BPF program's stderr > stream whenever we detect usage of a _impl suffixed kfunc, which have > now been replaced with KF_IMPLICIT_ARGS variants. For this purpose, > introduce bpf_stream_pr_warn() as a convenience wrapper, and then mark > bpf_find_linfo() as global to allow its usage in the verifier to find > the linfo corresponding to an instruction index. > > To make the message more helpful, recommend usage of bpf_ksym_exists() > as a way for the user to write backwards compatible BPF code that works > on older kernels offering _impl suffixed kfuncs. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > --- In the commit message: ..such that the program must __not__ be rejected.. > include/linux/bpf.h | 9 ++++++ > include/linux/bpf_verifier.h | 3 +- > kernel/bpf/log.c | 6 ++-- > kernel/bpf/verifier.c | 53 ++++++++++++++++++++++++++++++++++++ > 4 files changed, 67 insertions(+), 4 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 2c4f92085d79..d0158edd27b2 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -3912,6 +3912,15 @@ int bpf_stream_stage_dump_stack(struct bpf_stream_stage *ss); > bpf_stream_stage_free(&ss); \ > }) > > +#define bpf_stream_pr_warn(prog, fmt, ...) \ > + ({ \ > + struct bpf_stream_stage __ss; \ > + \ > + bpf_stream_stage(__ss, prog, BPF_STDERR, ({ \ > + bpf_stream_printk(__ss, fmt, ##__VA_ARGS__); \ > + })); \ > + }) > + > #ifdef CONFIG_BPF_LSM > void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype); > void bpf_cgroup_atype_put(int cgroup_atype); > diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h > index 090aa26d1c98..5683c06f5a90 100644 > --- a/include/linux/bpf_verifier.h > +++ b/include/linux/bpf_verifier.h > @@ -873,7 +873,8 @@ int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level, > char __user *log_buf, u32 log_size); > void bpf_vlog_reset(struct bpf_verifier_log *log, u64 new_pos); > int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual); > - > +const struct bpf_line_info *bpf_find_linfo(const struct bpf_verifier_env *env, > + u32 insn_off); > __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, > u32 insn_off, > const char *prefix_fmt, ...); > diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c > index 37d72b052192..598b494ded36 100644 > --- a/kernel/bpf/log.c > +++ b/kernel/bpf/log.c > @@ -329,8 +329,8 @@ __printf(2, 3) void bpf_log(struct bpf_verifier_log *log, > } > EXPORT_SYMBOL_GPL(bpf_log); > > -static const struct bpf_line_info * > -find_linfo(const struct bpf_verifier_env *env, u32 insn_off) > +const struct bpf_line_info * > +bpf_find_linfo(const struct bpf_verifier_env *env, u32 insn_off) > { > const struct bpf_line_info *linfo; > const struct bpf_prog *prog; > @@ -390,7 +390,7 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, > return; > > prev_linfo = env->prev_linfo; > - linfo = find_linfo(env, insn_off); > + linfo = bpf_find_linfo(env, insn_off); > if (!linfo || linfo == prev_linfo) > return; > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 8c1cf2eb6cbb..f50e0ebd0ded 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -3206,6 +3206,7 @@ struct bpf_kfunc_desc { > u32 func_id; > s32 imm; > u16 offset; > + bool warned_deprecated; > unsigned long addr; > }; > > @@ -14045,6 +14046,53 @@ static int fetch_kfunc_arg_meta(struct bpf_verifier_env *env, > return 0; > } > > +static bool get_insn_file_line(const struct bpf_verifier_env *env, u32 insn_off, > + const char **filep, int *linep) > +{ > + const struct bpf_line_info *linfo; > + > + if (!env->prog->aux->btf) > + return false; > + > + linfo = bpf_find_linfo(env, insn_off); > + if (!linfo) > + return false; > + > + if (bpf_get_linfo_file_line(env->prog->aux->btf, linfo, filep, NULL, linep)) > + return false; > + return true; > +} > + > +static void warn_for_deprecated_kfuncs(struct bpf_verifier_env *env, > + struct bpf_kfunc_desc *desc, > + const char *func_name, > + int insn_idx) > +{ > + int repl_len, line; > + const char *file; > + > + if (desc->warned_deprecated) > + return; > + > + if (!func_name || !strends(func_name, KF_IMPL_SUFFIX)) > + return; > + > + repl_len = strlen(func_name) - strlen(KF_IMPL_SUFFIX); > + > + if (get_insn_file_line(env, insn_idx, &file, &line)) > + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s:%u", file, line); > + else > + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "insn #%d", insn_idx); > + > + bpf_stream_pr_warn(env->prog, > + "WARNING: %s calls deprecated kfunc %s(), which will be removed.\n" > + "WARNING: Switch to kfunc %.*s() instead.\n" > + "WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(%.*s).\n", > + env->tmp_str_buf, func_name, repl_len, func_name, repl_len, func_name); > + > + desc->warned_deprecated = true; > +} Commit message suggests this is a generic functionality that we plan to use for all kinds of deprecations, but this function looks tightly coupled to KF_IMPL_SUFFIX functions. I think we can make it a bit friendlier to extending if split into 2 separate helpers: is_kfunc_deprecated() and warn_deprecated_kfunc(), so in future new logic for detecting deprecated funcs goes straight to is_kfunc_deprecated() and we make sure printing and file/line extractions are not changed. > + > /* check special kfuncs and return: > * 1 - not fall-through to 'else' branch, continue verification > * 0 - fall-through to 'else' branch > @@ -14231,6 +14279,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, > { > bool sleepable, rcu_lock, rcu_unlock, preempt_disable, preempt_enable; > u32 i, nargs, ptr_type_id, release_ref_obj_id; > + struct bpf_kfunc_desc *desc; > struct bpf_reg_state *regs = cur_regs(env); > const char *func_name, *ptr_type_name; > const struct btf_type *t, *ptr_type; > @@ -14253,6 +14302,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, > func_name = meta.func_name; > insn_aux = &env->insn_aux_data[insn_idx]; > > + desc = find_kfunc_desc(env->prog, insn->imm, insn->off); > + if (desc) > + warn_for_deprecated_kfuncs(env, desc, func_name, insn_idx); > + > insn_aux->is_iter_next = is_iter_next_kfunc(&meta); > > if (!insn->off && > -- > 2.52.0 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr 2026-03-30 11:39 ` Mykyta Yatsenko @ 2026-03-30 12:39 ` Puranjay Mohan 0 siblings, 0 replies; 12+ messages in thread From: Puranjay Mohan @ 2026-03-30 12:39 UTC (permalink / raw) To: Mykyta Yatsenko, Kumar Kartikeya Dwivedi, bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Mykyta Yatsenko <mykyta.yatsenko5@gmail.com> writes: > Kumar Kartikeya Dwivedi <memxor@gmail.com> writes: > >> There is a class of messages that aren't treated as hard errors, such >> that the program must be rejected, but should be surfaced to the user to >> make them aware that while the program succeeded, parts of their program >> are exhibiting behavior that needs attention. One example is usage of >> kfuncs that are supposed to be deprecated, and may be dropped in the >> future, though are preserved for now for backwards compatibility. >> >> Add support for emitting a warning message to the BPF program's stderr >> stream whenever we detect usage of a _impl suffixed kfunc, which have >> now been replaced with KF_IMPLICIT_ARGS variants. For this purpose, >> introduce bpf_stream_pr_warn() as a convenience wrapper, and then mark >> bpf_find_linfo() as global to allow its usage in the verifier to find >> the linfo corresponding to an instruction index. >> >> To make the message more helpful, recommend usage of bpf_ksym_exists() >> as a way for the user to write backwards compatible BPF code that works >> on older kernels offering _impl suffixed kfuncs. >> >> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> >> --- > In the commit message: ..such that the program must __not__ be rejected.. >> include/linux/bpf.h | 9 ++++++ >> include/linux/bpf_verifier.h | 3 +- >> kernel/bpf/log.c | 6 ++-- >> kernel/bpf/verifier.c | 53 ++++++++++++++++++++++++++++++++++++ >> 4 files changed, 67 insertions(+), 4 deletions(-) >> >> diff --git a/include/linux/bpf.h b/include/linux/bpf.h >> index 2c4f92085d79..d0158edd27b2 100644 >> --- a/include/linux/bpf.h >> +++ b/include/linux/bpf.h >> @@ -3912,6 +3912,15 @@ int bpf_stream_stage_dump_stack(struct bpf_stream_stage *ss); >> bpf_stream_stage_free(&ss); \ >> }) >> >> +#define bpf_stream_pr_warn(prog, fmt, ...) \ >> + ({ \ >> + struct bpf_stream_stage __ss; \ >> + \ >> + bpf_stream_stage(__ss, prog, BPF_STDERR, ({ \ >> + bpf_stream_printk(__ss, fmt, ##__VA_ARGS__); \ >> + })); \ >> + }) >> + >> #ifdef CONFIG_BPF_LSM >> void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype); >> void bpf_cgroup_atype_put(int cgroup_atype); >> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h >> index 090aa26d1c98..5683c06f5a90 100644 >> --- a/include/linux/bpf_verifier.h >> +++ b/include/linux/bpf_verifier.h >> @@ -873,7 +873,8 @@ int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level, >> char __user *log_buf, u32 log_size); >> void bpf_vlog_reset(struct bpf_verifier_log *log, u64 new_pos); >> int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual); >> - >> +const struct bpf_line_info *bpf_find_linfo(const struct bpf_verifier_env *env, >> + u32 insn_off); >> __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, >> u32 insn_off, >> const char *prefix_fmt, ...); >> diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c >> index 37d72b052192..598b494ded36 100644 >> --- a/kernel/bpf/log.c >> +++ b/kernel/bpf/log.c >> @@ -329,8 +329,8 @@ __printf(2, 3) void bpf_log(struct bpf_verifier_log *log, >> } >> EXPORT_SYMBOL_GPL(bpf_log); >> >> -static const struct bpf_line_info * >> -find_linfo(const struct bpf_verifier_env *env, u32 insn_off) >> +const struct bpf_line_info * >> +bpf_find_linfo(const struct bpf_verifier_env *env, u32 insn_off) >> { >> const struct bpf_line_info *linfo; >> const struct bpf_prog *prog; >> @@ -390,7 +390,7 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, >> return; >> >> prev_linfo = env->prev_linfo; >> - linfo = find_linfo(env, insn_off); >> + linfo = bpf_find_linfo(env, insn_off); >> if (!linfo || linfo == prev_linfo) >> return; >> >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index 8c1cf2eb6cbb..f50e0ebd0ded 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c >> @@ -3206,6 +3206,7 @@ struct bpf_kfunc_desc { >> u32 func_id; >> s32 imm; >> u16 offset; >> + bool warned_deprecated; >> unsigned long addr; >> }; >> >> @@ -14045,6 +14046,53 @@ static int fetch_kfunc_arg_meta(struct bpf_verifier_env *env, >> return 0; >> } >> >> +static bool get_insn_file_line(const struct bpf_verifier_env *env, u32 insn_off, >> + const char **filep, int *linep) >> +{ >> + const struct bpf_line_info *linfo; >> + >> + if (!env->prog->aux->btf) >> + return false; >> + >> + linfo = bpf_find_linfo(env, insn_off); >> + if (!linfo) >> + return false; >> + >> + if (bpf_get_linfo_file_line(env->prog->aux->btf, linfo, filep, NULL, linep)) >> + return false; >> + return true; >> +} >> + >> +static void warn_for_deprecated_kfuncs(struct bpf_verifier_env *env, >> + struct bpf_kfunc_desc *desc, >> + const char *func_name, >> + int insn_idx) >> +{ >> + int repl_len, line; >> + const char *file; >> + >> + if (desc->warned_deprecated) >> + return; >> + >> + if (!func_name || !strends(func_name, KF_IMPL_SUFFIX)) >> + return; >> + >> + repl_len = strlen(func_name) - strlen(KF_IMPL_SUFFIX); >> + >> + if (get_insn_file_line(env, insn_idx, &file, &line)) >> + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s:%u", file, line); >> + else >> + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "insn #%d", insn_idx); >> + >> + bpf_stream_pr_warn(env->prog, >> + "WARNING: %s calls deprecated kfunc %s(), which will be removed.\n" >> + "WARNING: Switch to kfunc %.*s() instead.\n" >> + "WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(%.*s).\n", >> + env->tmp_str_buf, func_name, repl_len, func_name, repl_len, func_name); >> + >> + desc->warned_deprecated = true; >> +} > Commit message suggests this is a generic functionality that we plan to > use for all kinds of deprecations, but this function looks tightly > coupled to KF_IMPL_SUFFIX functions. I think we can make it a bit > friendlier to extending if split into 2 separate helpers: > is_kfunc_deprecated() and warn_deprecated_kfunc(), so in future new > logic for detecting deprecated funcs goes straight to > is_kfunc_deprecated() and we make sure printing and file/line > extractions are not changed. I agree with splitting this into two separate helpers. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr 2026-03-29 21:25 ` [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr Kumar Kartikeya Dwivedi 2026-03-30 11:39 ` Mykyta Yatsenko @ 2026-03-30 15:02 ` Alexei Starovoitov 1 sibling, 0 replies; 12+ messages in thread From: Alexei Starovoitov @ 2026-03-30 15:02 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, Kernel Team On Sun, Mar 29, 2026 at 2:25 PM Kumar Kartikeya Dwivedi <memxor@gmail.com> wrote: > > There is a class of messages that aren't treated as hard errors, such > that the program must be rejected, but should be surfaced to the user to > make them aware that while the program succeeded, parts of their program > are exhibiting behavior that needs attention. One example is usage of > kfuncs that are supposed to be deprecated, and may be dropped in the > future, though are preserved for now for backwards compatibility. > > Add support for emitting a warning message to the BPF program's stderr > stream whenever we detect usage of a _impl suffixed kfunc, which have > now been replaced with KF_IMPLICIT_ARGS variants. For this purpose, > introduce bpf_stream_pr_warn() as a convenience wrapper, and then mark > bpf_find_linfo() as global to allow its usage in the verifier to find > the linfo corresponding to an instruction index. > > To make the message more helpful, recommend usage of bpf_ksym_exists() > as a way for the user to write backwards compatible BPF code that works > on older kernels offering _impl suffixed kfuncs. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > --- > include/linux/bpf.h | 9 ++++++ > include/linux/bpf_verifier.h | 3 +- > kernel/bpf/log.c | 6 ++-- > kernel/bpf/verifier.c | 53 ++++++++++++++++++++++++++++++++++++ > 4 files changed, 67 insertions(+), 4 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 2c4f92085d79..d0158edd27b2 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -3912,6 +3912,15 @@ int bpf_stream_stage_dump_stack(struct bpf_stream_stage *ss); > bpf_stream_stage_free(&ss); \ > }) > > +#define bpf_stream_pr_warn(prog, fmt, ...) \ > + ({ \ > + struct bpf_stream_stage __ss; \ > + \ > + bpf_stream_stage(__ss, prog, BPF_STDERR, ({ \ > + bpf_stream_printk(__ss, fmt, ##__VA_ARGS__); \ Warnings are helpful, but delivering them via streams feels odd. streams should have been an interface for run-time where either bpf core, kfuncs, or progs themselves send messages to user space. These warns come from the verifier. So conceptually fit better into verifier log. libbpf doesn't use it by default, but maybe it should. Eventually we will have common_attr in sys_bpf and other commands like map_create will print human readable errors. pw-bot: cr ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic 2026-03-29 21:25 [PATCH bpf-next v1 0/3] Add support to emit verifier warnings Kumar Kartikeya Dwivedi 2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi 2026-03-29 21:25 ` [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 ` Kumar Kartikeya Dwivedi 2026-03-30 12:56 ` Mykyta Yatsenko 2026-03-30 23:46 ` Andrii Nakryiko 2 siblings, 2 replies; 12+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-03-29 21:25 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Wire up the flushing of all accumulated messages in a program's stderr stream after verification is complete. An example is shown below of a warning printed now about usage of deprecated kfuncs. $ ./test_progs -t kfunc_implicit_args/test_kfunc_implicit_arg_legacy_impl -v ... libbpf: prog 'test_kfunc_implicit_arg_legacy_impl': VERIFIER WARNINGS: WARNING: kfunc_implicit_args.c:40 calls deprecated kfunc bpf_kfunc_implicit_arg_legacy_impl(), which will be removed. WARNING: Switch to kfunc bpf_kfunc_implicit_arg_legacy() instead. WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(bpf_kfunc_implicit_arg_legacy). ... Note that test_progs overrides the default logging function, hence -v is necessary. By default these messages would be printed for the user. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> --- tools/lib/bpf/libbpf.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 9ea41f40dc82..f308bacd083f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -7826,6 +7826,27 @@ static int libbpf_prepare_prog_load(struct bpf_program *prog, static void fixup_verifier_log(struct bpf_program *prog, char *buf, size_t buf_sz); +static void bpf_object_load_prog_emit_stderr(struct bpf_program *prog, int prog_fd) +{ + char chunk[256]; + bool emitted = false; + int ret; + + while ((ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, chunk, + sizeof(chunk), NULL)) > 0) { + if (!emitted) { + pr_warn("prog '%s': VERIFIER WARNINGS:\n", prog->name); + emitted = true; + } + libbpf_print(LIBBPF_WARN, "%.*s", ret, chunk); + } + + if (ret < 0) { + pr_debug("prog '%s': failed to read BPF stderr stream: %s\n", + prog->name, errstr(ret)); + } +} + static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, const char *license, __u32 kern_version, int *prog_fd) @@ -7950,6 +7971,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog prog->name, log_buf); } + bpf_object_load_prog_emit_stderr(prog, ret); + if (obj->has_rodata && kernel_supports(obj, FEAT_PROG_BIND_MAP)) { struct bpf_map *map; int i; -- 2.52.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic 2026-03-29 21:25 ` [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic Kumar Kartikeya Dwivedi @ 2026-03-30 12:56 ` Mykyta Yatsenko 2026-03-30 23:46 ` Andrii Nakryiko 1 sibling, 0 replies; 12+ messages in thread From: Mykyta Yatsenko @ 2026-03-30 12:56 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi, bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team Kumar Kartikeya Dwivedi <memxor@gmail.com> writes: > Wire up the flushing of all accumulated messages in a program's stderr > stream after verification is complete. An example is shown below of a > warning printed now about usage of deprecated kfuncs. > > $ ./test_progs -t kfunc_implicit_args/test_kfunc_implicit_arg_legacy_impl -v > ... > libbpf: prog 'test_kfunc_implicit_arg_legacy_impl': VERIFIER WARNINGS: > WARNING: kfunc_implicit_args.c:40 calls deprecated kfunc bpf_kfunc_implicit_arg_legacy_impl(), which will be removed. > WARNING: Switch to kfunc bpf_kfunc_implicit_arg_legacy() instead. > WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(bpf_kfunc_implicit_arg_legacy). > ... > > Note that test_progs overrides the default logging function, hence -v is > necessary. By default these messages would be printed for the user. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > --- > tools/lib/bpf/libbpf.c | 23 +++++++++++++++++++++++ > 1 file changed, 23 insertions(+) > > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > index 9ea41f40dc82..f308bacd083f 100644 > --- a/tools/lib/bpf/libbpf.c > +++ b/tools/lib/bpf/libbpf.c > @@ -7826,6 +7826,27 @@ static int libbpf_prepare_prog_load(struct bpf_program *prog, > > static void fixup_verifier_log(struct bpf_program *prog, char *buf, size_t buf_sz); > > +static void bpf_object_load_prog_emit_stderr(struct bpf_program *prog, int prog_fd) nit: Not sure if this function name is a good choice: it does not take bpf object and does not load the program, I'd rather name it bpf_program_emit_verifier_stderr(). The implementation looks correct. Acked-by: Mykyta Yatsenko <yatsenko@meta.com> > +{ > + char chunk[256]; > + bool emitted = false; > + int ret; > + > + while ((ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, chunk, > + sizeof(chunk), NULL)) > 0) { > + if (!emitted) { > + pr_warn("prog '%s': VERIFIER WARNINGS:\n", prog->name); > + emitted = true; > + } > + libbpf_print(LIBBPF_WARN, "%.*s", ret, chunk); > + } > + > + if (ret < 0) { > + pr_debug("prog '%s': failed to read BPF stderr stream: %s\n", > + prog->name, errstr(ret)); > + } > +} > + > static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog, > struct bpf_insn *insns, int insns_cnt, > const char *license, __u32 kern_version, int *prog_fd) > @@ -7950,6 +7971,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog > prog->name, log_buf); > } > > + bpf_object_load_prog_emit_stderr(prog, ret); > + > if (obj->has_rodata && kernel_supports(obj, FEAT_PROG_BIND_MAP)) { > struct bpf_map *map; > int i; > -- > 2.52.0 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic 2026-03-29 21:25 ` [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic Kumar Kartikeya Dwivedi 2026-03-30 12:56 ` Mykyta Yatsenko @ 2026-03-30 23:46 ` Andrii Nakryiko 1 sibling, 0 replies; 12+ messages in thread From: Andrii Nakryiko @ 2026-03-30 23:46 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman, Ihor Solodrai, kkd, kernel-team On Sun, Mar 29, 2026 at 2:25 PM Kumar Kartikeya Dwivedi <memxor@gmail.com> wrote: > > Wire up the flushing of all accumulated messages in a program's stderr > stream after verification is complete. An example is shown below of a > warning printed now about usage of deprecated kfuncs. > > $ ./test_progs -t kfunc_implicit_args/test_kfunc_implicit_arg_legacy_impl -v > ... > libbpf: prog 'test_kfunc_implicit_arg_legacy_impl': VERIFIER WARNINGS: > WARNING: kfunc_implicit_args.c:40 calls deprecated kfunc bpf_kfunc_implicit_arg_legacy_impl(), which will be removed. > WARNING: Switch to kfunc bpf_kfunc_implicit_arg_legacy() instead. > WARNING: For older kernels, choose the kfunc using bpf_ksym_exists(bpf_kfunc_implicit_arg_legacy). > ... > > Note that test_progs overrides the default logging function, hence -v is > necessary. By default these messages would be printed for the user. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > --- > tools/lib/bpf/libbpf.c | 23 +++++++++++++++++++++++ > 1 file changed, 23 insertions(+) > > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > index 9ea41f40dc82..f308bacd083f 100644 > --- a/tools/lib/bpf/libbpf.c > +++ b/tools/lib/bpf/libbpf.c > @@ -7826,6 +7826,27 @@ static int libbpf_prepare_prog_load(struct bpf_program *prog, > > static void fixup_verifier_log(struct bpf_program *prog, char *buf, size_t buf_sz); > > +static void bpf_object_load_prog_emit_stderr(struct bpf_program *prog, int prog_fd) > +{ > + char chunk[256]; > + bool emitted = false; > + int ret; > + > + while ((ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, chunk, > + sizeof(chunk), NULL)) > 0) { > + if (!emitted) { > + pr_warn("prog '%s': VERIFIER WARNINGS:\n", prog->name); > + emitted = true; > + } > + libbpf_print(LIBBPF_WARN, "%.*s", ret, chunk); > + } > + > + if (ret < 0) { > + pr_debug("prog '%s': failed to read BPF stderr stream: %s\n", > + prog->name, errstr(ret)); instead of potentially spamming debug logs with this, let's detect if streams are supported and not even try to read warnings? Also, why 256 byte buffer? 1-4KB isn't a big deal, it's user space > + } > +} > + > static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog, > struct bpf_insn *insns, int insns_cnt, > const char *license, __u32 kern_version, int *prog_fd) > @@ -7950,6 +7971,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog > prog->name, log_buf); > } > > + bpf_object_load_prog_emit_stderr(prog, ret); just inline this, we inline bind map logic, so why not this one? > + > if (obj->has_rodata && kernel_supports(obj, FEAT_PROG_BIND_MAP)) { > struct bpf_map *map; > int i; > -- > 2.52.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-03-30 23:46 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-29 21:25 [PATCH bpf-next v1 0/3] Add support to emit verifier warnings Kumar Kartikeya Dwivedi 2026-03-29 21:25 ` [PATCH bpf-next v1 1/3] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi 2026-03-30 11:28 ` Mykyta Yatsenko 2026-03-30 12:27 ` Puranjay Mohan 2026-03-30 12:35 ` Puranjay Mohan 2026-03-29 21:25 ` [PATCH bpf-next v1 2/3] bpf: Emit verifier warnings through prog stderr Kumar Kartikeya Dwivedi 2026-03-30 11:39 ` Mykyta Yatsenko 2026-03-30 12:39 ` Puranjay Mohan 2026-03-30 15:02 ` Alexei Starovoitov 2026-03-29 21:25 ` [PATCH bpf-next v1 3/3] libbpf: Wire up verifier warning display logic Kumar Kartikeya Dwivedi 2026-03-30 12:56 ` Mykyta Yatsenko 2026-03-30 23:46 ` Andrii Nakryiko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox