From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Martin KaFai Lau <martin.lau@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v2 6/6] libbpf: Flush verifier warning messages by default
Date: Wed, 8 Apr 2026 04:13:57 +0200 [thread overview]
Message-ID: <20260408021359.3786905-7-memxor@gmail.com> (raw)
In-Reply-To: <20260408021359.3786905-1-memxor@gmail.com>
Allow passing a log buffer with log_level = 0, and also set the log
buffer by default when loading a program, so that warnings can be
captured and flushed, such that we can notify users of deprecation
messages from the verifier even if program succeeds in loading.
Use the presence of enum bpf_features member to disable passing log_buf
with log_level = 0 as the verifier will reject the program due to an
invalid attribute. Low-level bpf_prog_load() API is relaxed, and will
continue passing on older kernels as long as callers don't pass log_buf
unconditionally.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
tools/lib/bpf/bpf.c | 5 +--
tools/lib/bpf/features.c | 56 +++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.c | 20 +++++++-----
tools/lib/bpf/libbpf_internal.h | 2 ++
4 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 5846de364209..01dd8a126ef6 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -315,11 +315,12 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
attr.fd_array = ptr_to_u64(OPTS_GET(opts, fd_array, NULL));
attr.fd_array_cnt = OPTS_GET(opts, fd_array_cnt, 0);
- if (log_level) {
+ /* Pass log_buf/log_size independently so log_level=0 loads can collect warnings. */
+ if (log_buf) {
attr.log_buf = ptr_to_u64(log_buf);
attr.log_size = log_size;
- attr.log_level = log_level;
}
+ attr.log_level = log_level;
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
OPTS_SET(opts, log_true_size, attr.log_true_size);
diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c
index 4f19a0d79b0c..a9091c66ed32 100644
--- a/tools/lib/bpf/features.c
+++ b/tools/lib/bpf/features.c
@@ -208,6 +208,59 @@ static int probe_kern_btf_type_tag(int token_fd)
strs, sizeof(strs), token_fd));
}
+static bool btf_type_has_enum_value(const struct btf *btf, const struct btf_type *t,
+ const char *value_name)
+{
+ int i, vlen = btf_vlen(t);
+
+ if (btf_is_enum(t)) {
+ const struct btf_enum *e = btf_enum(t);
+
+ for (i = 0; i < vlen; i++, e++) {
+ if (strcmp(btf__name_by_offset(btf, e->name_off), value_name) == 0)
+ return true;
+ }
+ } else if (btf_is_enum64(t)) {
+ const struct btf_enum64 *e = btf_enum64(t);
+
+ for (i = 0; i < vlen; i++, e++) {
+ if (strcmp(btf__name_by_offset(btf, e->name_off), value_name) == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int probe_kern_verifier_warnings(int token_fd)
+{
+ const struct btf_type *t;
+ struct btf *btf;
+ bool found = false;
+ __s32 type_id;
+
+ (void)token_fd;
+
+ btf = btf__load_vmlinux_btf();
+ if (libbpf_get_error(btf))
+ return 0;
+
+ type_id = btf__find_by_name_kind(btf, "bpf_features", BTF_KIND_ENUM);
+ if (type_id < 0)
+ type_id = btf__find_by_name_kind(btf, "bpf_features", BTF_KIND_ENUM64);
+ if (type_id < 0) {
+ btf__free(btf);
+ return 0;
+ }
+
+ t = btf__type_by_id(btf, type_id);
+ if (t)
+ found = btf_type_has_enum_value(btf, t, "BPF_FEAT_VERIFIER_WARNINGS");
+
+ btf__free(btf);
+ return found;
+}
+
static int probe_kern_array_mmap(int token_fd)
{
LIBBPF_OPTS(bpf_map_create_opts, opts,
@@ -669,6 +722,9 @@ static struct kern_feature_desc {
[FEAT_BTF_TYPE_TAG] = {
"BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag,
},
+ [FEAT_VERIFIER_WARNINGS] = {
+ "success-path verifier warnings", probe_kern_verifier_warnings,
+ },
[FEAT_MEMCG_ACCOUNT] = {
"memcg-based memory accounting", probe_memcg_account,
},
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 42bdba4efd0c..ea8ac67fcb3f 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -7832,10 +7832,13 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
{
LIBBPF_OPTS(bpf_prog_load_opts, load_attr);
const char *prog_name = NULL;
+ const size_t warn_log_buf_size = 4096;
size_t log_buf_size = 0;
char *log_buf = NULL, *tmp;
bool own_log_buf = true;
__u32 log_level = prog->log_level;
+ bool want_verifier_warnings = log_level == 0 &&
+ kernel_supports(obj, FEAT_VERIFIER_WARNINGS);
int ret, err;
/* Be more helpful by rejecting programs that can't be validated early
@@ -7912,12 +7915,11 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
}
retry_load:
- /* if log_level is zero, we don't request logs initially even if
- * custom log_buf is specified; if the program load fails, then we'll
- * bump log_level to 1 and use either custom log_buf or we'll allocate
- * our own and retry the load to get details on what failed
+ /* If supported, pass a buffer with log_level=0 so the kernel can report
+ * success-path warnings. If the program load fails, retry with
+ * log_level=1 to get details on what failed.
*/
- if (log_level) {
+ if (log_level || want_verifier_warnings) {
if (prog->log_buf) {
log_buf = prog->log_buf;
log_buf_size = prog->log_size;
@@ -7927,7 +7929,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
log_buf_size = obj->log_size;
own_log_buf = false;
} else {
- log_buf_size = max((size_t)BPF_LOG_BUF_SIZE, log_buf_size * 2);
+ log_buf_size = max(log_level ? (size_t)BPF_LOG_BUF_SIZE : warn_log_buf_size,
+ log_buf_size * 2);
tmp = realloc(log_buf, log_buf_size);
if (!tmp) {
ret = -ENOMEM;
@@ -7945,7 +7948,10 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
ret = bpf_prog_load(prog->type, prog_name, license, insns, insns_cnt, &load_attr);
if (ret >= 0) {
- if (log_level && own_log_buf) {
+ if (want_verifier_warnings && log_level == 0 && load_attr.log_true_size) {
+ pr_warn("prog '%s': -- BEGIN PROG LOAD WARNINGS --\n%s-- END PROG LOAD WARNINGS --\n",
+ prog->name, log_buf);
+ } else if (log_level && own_log_buf) {
pr_debug("prog '%s': -- BEGIN PROG LOAD LOG --\n%s-- END PROG LOAD LOG --\n",
prog->name, log_buf);
}
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index cabdaef79098..7c72ade7a179 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -378,6 +378,8 @@ enum kern_feature_id {
FEAT_BTF_DECL_TAG,
/* BTF_KIND_TYPE_TAG support */
FEAT_BTF_TYPE_TAG,
+ /* Kernel supports success-path verifier warnings */
+ FEAT_VERIFIER_WARNINGS,
/* memcg-based accounting for BPF maps and progs */
FEAT_MEMCG_ACCOUNT,
/* BPF cookie (bpf_get_attach_cookie() BPF helper) support */
--
2.52.0
next prev parent reply other threads:[~2026-04-08 2:14 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-08 2:13 [PATCH bpf-next v2 0/6] Add support to emit verifier warnings Kumar Kartikeya Dwivedi
2026-04-08 2:13 ` [PATCH bpf-next v2 1/6] bpf: Add support for verifier warning messages Kumar Kartikeya Dwivedi
2026-04-08 8:46 ` sun jian
2026-04-08 2:13 ` [PATCH bpf-next v2 2/6] bpf: Extract bpf_get_linfo_file_line Kumar Kartikeya Dwivedi
2026-04-08 2:13 ` [PATCH bpf-next v2 3/6] bpf: Make find_linfo widely available Kumar Kartikeya Dwivedi
2026-04-08 2:13 ` [PATCH bpf-next v2 4/6] bpf: Use KF_DEPRECATED to emit verifier warnings Kumar Kartikeya Dwivedi
2026-04-08 2:13 ` [PATCH bpf-next v2 5/6] bpf: Add __bpf_kfunc_replacement() annotation Kumar Kartikeya Dwivedi
2026-04-08 2:13 ` Kumar Kartikeya Dwivedi [this message]
2026-04-08 2:21 ` [PATCH bpf-next v2 6/6] libbpf: Flush verifier warning messages by default Kumar Kartikeya Dwivedi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260408021359.3786905-7-memxor@gmail.com \
--to=memxor@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=kernel-team@meta.com \
--cc=kkd@meta.com \
--cc=martin.lau@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox