From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next 2/2] bpf: Keep one basic block in the level 1 log and print the way to it
Date: Sun, 08 Nov 2026 06:02:45 +0000 [thread overview]
Message-ID: <sashiko-outbox-203594@kernel.org> (raw)
In-Reply-To: <20261108053937.4134138-3-alexei.starovoitov@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] bpf: preserve flow->from across subprogram calls in
bpf_flow_call()
- [Low] bpf: clear env->prev_log_pos when resetting level 1 log in
do_check()
--
commit 436e80edd288c8e9b5661dd9e9cfd3aca7f99381
Author: Alexei Starovoitov <ast@kernel.org>
bpf: Keep one basic block in the level 1 log and print the way to it
This commit rewinds the level 1 verifier log before each basic block and
reconstructs and prints the path of basic blocks leading to a rejected block
on verification failure.
> diff --git a/kernel/bpf/flow.c b/kernel/bpf/flow.c
> index e6d1817ffa57d..c9458b3ad114a 100644
> --- a/kernel/bpf/flow.c
> +++ b/kernel/bpf/flow.c
[ ... ]
> @@ -2883,6 +2886,7 @@ static struct flow_state *flow_new_state(struct bpf_verifier_env *env, int prev_
> return NULL;
> s->prev_insn_idx = prev_insn_idx;
> s->seq = ++flow->seq;
> + s->from = flow->from;
> env->total_states++;
> flow->live_states++;
> env->peak_states = max(env->peak_states, flow->live_states);
> @@ -3308,8 +3312,11 @@ int bpf_flow_next(struct bpf_verifier_env *env, int *prev_insn_idx)
>
> env->insn_idx = s->st.insn_idx;
> *prev_insn_idx = s->prev_insn_idx;
> - if (test_bit(s->st.insn_idx, flow->keep))
> + if (test_bit(s->st.insn_idx, flow->keep)) {
> + flow->from = s->seq;
> return bpf_copy_verifier_state(env->cur_state, &s->st);
> + }
> + flow->from = s->from;
> *env->cur_state = s->st;
> memset(&s->st, 0, sizeof(s->st));
> s->st.insn_idx = env->insn_idx;
> @@ -3317,3 +3324,89 @@ int bpf_flow_next(struct bpf_verifier_env *env, int *prev_insn_idx)
> flow_free_state(env, s);
> return 0;
> }
> +
> +/* A basic block on the way to the block that is rejected, up to the insn that leads on */
> +struct flow_step {
> + const struct flow_state *s; /* the state at its head, if one is kept */
> + int head, last;
> +};
> +
> +/*
> + * The state at @head with that @seq. If it is gone a state that came later took its place:
> + * the last one then.
> + */
> +static const struct flow_state *flow_find_state(const struct bpf_flow *flow, int head, u32 seq)
> +{
> + const struct list_head *list = &flow->states[head].list;
> + const struct flow_state *s;
> +
> + if (!test_bit(head, flow->keep))
> + return NULL;
> + list_for_each_entry(s, list, node)
> + if (s->seq == seq)
> + return s;
> + return list_empty(list) ? NULL : list_last_entry(list, struct flow_state, node);
> +}
[Severity: Medium]
Does flow_find_state() look up the caller's basic block with a callee sequence
number after a call to a static subprogram that is verified on its own?
When bpf_flow_call() parks the waiting caller state w, it does not save
w->from = flow->from. Verifying the callee then overwrites flow->from with
the callee's kept state sequence numbers, and flow_apply_exit() creates the
resumed caller state at call_idx + 1 (or call_idx) via flow_new_state() using
that overwritten flow->from:
kernel/bpf/flow.c:flow_apply_exit() {
...
if (!err)
err = bpf_flow_deliver(env, &st, call_idx + 1, call_idx);
bpf_free_verifier_state(&st, false);
if (err != 1)
return err;
...
s = flow_new_state(env, w->st.last_insn_idx);
...
}
If verification later fails in the caller, bpf_flow_print_way() steps back to
call_idx carrying the callee's seq in from. When multiple states were kept at
the caller's basic block, s->seq == seq never matches in flow_find_state(),
so it falls back to list_last_entry() and prints the wrong state and incoming
edge for the caller. Saving flow->from in w->from in bpf_flow_call() and
restoring flow->from = w->from in flow_apply_exit() would preserve the
caller's sequence number across the call.
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index fd333b1063c3d..20b1b9ff574c7 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -22049,7 +22057,15 @@ static int do_check(struct bpf_verifier_env *env)
> break;
> /* What is known about how the state came to be is not kept with it. */
> bpf_diag_event_log_restore(env, 0);
> + /* Neither is the text: the level 1 log has one basic block at a time. */
> + if (level1) {
> + bpf_vlog_reset(&env->log, log_pos);
> + env->prev_linfo = NULL;
> + }
[Severity: Low]
Should this also reset env->prev_log_pos = 0 when rewinding env->log?
When a previous function verification pass leaves a small env->prev_log_pos
that happens to match log_pos after do_check_common() prints the "Validating
<func>() func#<n>..." header line for a global subprogram, print_insn_state()
on the first instruction of the basic block sees
env->prev_log_pos == env->log.end_pos:
kernel/bpf/log.c:print_insn_state() {
if (env->prev_log_pos && env->prev_log_pos == env->log.end_pos) {
/* remove new line character */
bpf_vlog_reset(&env->log, env->prev_log_pos - 1);
verbose(env, "%*c;", bpf_vlog_alignment(env->prev_insn_print_pos), ' ');
} else {
verbose(env, "%d:", env->insn_idx);
}
...
}
That strips the trailing newline from the "Validating ..." header line and
appends the initial state inline with a semicolon instead of printing
"<insn_idx>:".
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261108053937.4134138-1-alexei.starovoitov@gmail.com?part=2
next prev parent reply other threads:[~2026-11-08 6:02 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-08 5:39 [PATCH bpf-next 0/2] bpf: One basic block and the way to it in the level 1 log Alexei Starovoitov
2026-11-08 5:39 ` [PATCH bpf-next 1/2] bpf: Take the end of the verifier log out and append it later Alexei Starovoitov
2026-11-08 6:03 ` sashiko-bot
2026-11-08 16:08 ` Alexei Starovoitov
2026-11-08 5:39 ` [PATCH bpf-next 2/2] bpf: Keep one basic block in the level 1 log and print the way to it Alexei Starovoitov
2026-11-08 6:02 ` sashiko-bot [this message]
2026-11-08 16:08 ` Alexei Starovoitov
2026-11-08 16:20 ` [PATCH bpf-next 0/2] bpf: One basic block and the way to it in the level 1 log patchwork-bot+netdevbpf
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=sashiko-outbox-203594@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=alexei.starovoitov@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.