* [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
* [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
* [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 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 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 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
* 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 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 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
* 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