From: Eduard Zingerman <eddyz87@gmail.com>
To: kernel test robot <lkp@intel.com>, bpf@vger.kernel.org, ast@kernel.org
Cc: oe-kbuild-all@lists.linux.dev, andrii@kernel.org,
daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com,
yonghong.song@linux.dev
Subject: Re: [PATCH bpf-next v1 3/4] bpf: use SCC info instead of loop_entry
Date: Sat, 26 Apr 2025 12:51:04 -0700 [thread overview]
Message-ID: <39942ee3ccbc7aba2017ee2d31add0cc1b538b22.camel@gmail.com> (raw)
In-Reply-To: <202504262235.h5B7vJiB-lkp@intel.com>
On Sat, 2025-04-26 at 22:45 +0800, kernel test robot wrote:
> Hi Eduard,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on bpf-next/master]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Eduard-Zingerman/bpf-compute-SCCs-in-program-control-flow-graph/20250426-184824
> base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
> patch link: https://lore.kernel.org/r/20250426104634.744077-4-eddyz87%40gmail.com
> patch subject: [PATCH bpf-next v1 3/4] bpf: use SCC info instead of loop_entry
> config: riscv-randconfig-001-20250426 (https://download.01.org/0day-ci/archive/20250426/202504262235.h5B7vJiB-lkp@intel.com/config)
> compiler: riscv64-linux-gcc (GCC) 14.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250426/202504262235.h5B7vJiB-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> > Reported-by: kernel test robot <lkp@intel.com>
> > Closes: https://lore.kernel.org/oe-kbuild-all/202504262235.h5B7vJiB-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
> kernel/bpf/verifier.c: In function 'mark_all_regs_read_and_precise':
> > > kernel/bpf/verifier.c:18238:13: warning: variable 'insn_idx' set but not used [-Wunused-but-set-variable]
> 18238 | u32 insn_idx;
> | ^~~~~~~~
> At top level:
> cc1: note: unrecognized command-line option '-Wno-unterminated-string-initialization' may have been intended to silence earlier diagnostics
I messed up when extracting frame_insn_idx().
The function needs to be updated as:
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ae642459f342..06c2b3806666 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18240,7 +18240,7 @@ static void mark_all_regs_read_and_precise(struct bpf_verifier_env *env,
for (i = 0; i <= st->curframe; i++) {
insn_idx = frame_insn_idx(st, i);
- live_regs = env->insn_aux_data[st->insn_idx].live_regs_before;
+ live_regs = env->insn_aux_data[insn_idx].live_regs_before;
func = st->frame[i];
for (j = 0; j < BPF_REG_FP; j++) {
reg = &func->regs[j];
I'll try to figure out a test case failing w/o above hunk.
Also, patch #3 probably worth splitting in two:
- one adding new logic;
- one removing old logic.
Will wait a few days before sending v2.
> vim +/insn_idx +18238 kernel/bpf/verifier.c
>
> 18154
> 18155 /* Open coded iterators introduce loops in the verifier state graph.
> 18156 * State graph loops can result in incomplete read and precision marks
> 18157 * on individual states. E.g. consider the following states graph:
> 18158 *
> 18159 * .-> A --. Assume the states are visited in the order A, B, C.
> 18160 * | | | Assume that state B reaches a state equivalent to state A.
> 18161 * | v v At this point, state C has not been processed yet,
> 18162 * '-- B C so state A does not have any read or precision marks from C yet.
> 18163 * As a result, these marks won't be propagated to B.
> 18164 *
> 18165 * If the marks on B are incomplete, it would be unsafe to use it in
> 18166 * states_equal() checks.
> 18167 *
> 18168 * To avoid this safety issue, and since states with incomplete read
> 18169 * marks can only occur within control flow graph loops, the verifier
> 18170 * assumes that any state with bpf_verifier_state->insn_idx residing
> 18171 * in a strongly connected component (SCC) has read and precision
> 18172 * marks for all registers. This assumption is enforced by the
> 18173 * function mark_all_regs_read_and_precise(), which assigns
> 18174 * corresponding marks.
> 18175 *
> 18176 * An intuitive point to call mark_all_regs_read_and_precise() would
> 18177 * be when a new state is created in is_state_visited().
> 18178 * However, doing so would interfere with widen_imprecise_scalars(),
> 18179 * which widens scalars in the current state after checking registers in a
> 18180 * parent state. Registers are not widened if they are marked as precise
> 18181 * in the parent state.
> 18182 *
> 18183 * To avoid interfering with widening logic,
> 18184 * a call to mark_all_regs_read_and_precise() for state is postponed
> 18185 * until no widening is possible in any descendant of state S.
> 18186 *
> 18187 * Another intuitive spot to call mark_all_regs_read_and_precise()
> 18188 * would be in update_branch_counts() when S's branches counter
> 18189 * reaches 0. However, this falls short in the following case:
> 18190 *
> 18191 * sum = 0
> 18192 * bpf_repeat(10) { // a
> 18193 * if (unlikely(bpf_get_prandom_u32())) // b
> 18194 * sum += 1;
> 18195 * if (bpf_get_prandom_u32()) // c
> 18196 * asm volatile ("");
> 18197 * asm volatile ("goto +0;"); // d
> 18198 * }
> 18199 *
> 18200 * Here a checkpoint is created at (d) with {sum=0} and the branch counter
> 18201 * for (d) reaches 0, so 'sum' would be marked precise.
> 18202 * When second branch of (c) reaches (d), checkpoint would be hit,
> 18203 * and the precision mark for 'sum' propagated to (a).
> 18204 * When the second branch of (b) reaches (a), the state would be {sum=1},
> 18205 * no widening would occur, causing verification to continue forever.
> 18206 *
> 18207 * To avoid such premature precision markings, the verifier postpones
> 18208 * the call to mark_all_regs_read_and_precise() for state S even further.
> 18209 * Suppose state P is a [grand]parent of state S and is the first state
> 18210 * in the current state chain with state->insn_idx within current SCC.
> 18211 * mark_all_regs_read_and_precise() for state S is only called once P
> 18212 * is fully explored.
> 18213 *
> 18214 * The struct 'bpf_scc_info' is used to track this condition:
> 18215 * - bpf_scc_info->branches counts how many states currently
> 18216 * in env->cur_state or env->head originate from this SCC;
> 18217 * - bpf_scc_info->scc_epoch counts how many times 'branches'
> 18218 * has reached zero;
> 18219 * - bpf_verifier_state->scc_epoch records the epoch of the SCC
> 18220 * corresponding to bpf_verifier_state->insn_idx at the moment
> 18221 * of state creation.
> 18222 *
> 18223 * Functions parent_scc_enter() and parent_scc_exit() maintain the
> 18224 * bpf_scc_info->{branches,scc_epoch} counters.
> 18225 *
> 18226 * bpf_scc_info->branches reaching zero indicates that state P is
> 18227 * fully explored. Its descendants residing in the same SCC have
> 18228 * state->scc_epoch == scc_info->scc_epoch. parent_scc_exit()
> 18229 * increments scc_info->scc_epoch, allowing clean_live_states() to
> 18230 * detect these states and apply mark_all_regs_read_and_precise().
> 18231 */
> 18232 static void mark_all_regs_read_and_precise(struct bpf_verifier_env *env,
> 18233 struct bpf_verifier_state *st)
> 18234 {
> 18235 struct bpf_func_state *func;
> 18236 struct bpf_reg_state *reg;
> 18237 u16 live_regs;
> 18238 u32 insn_idx;
> 18239 int i, j;
> 18240
> 18241 for (i = 0; i <= st->curframe; i++) {
> 18242 insn_idx = frame_insn_idx(st, i);
> 18243 live_regs = env->insn_aux_data[st->insn_idx].live_regs_before;
> 18244 func = st->frame[i];
> 18245 for (j = 0; j < BPF_REG_FP; j++) {
> 18246 reg = &func->regs[j];
> 18247 if (!(BIT(j) & live_regs) || reg->type == NOT_INIT)
> 18248 continue;
> 18249 reg->live |= REG_LIVE_READ64;
> 18250 if (reg->type == SCALAR_VALUE && !is_reg_unbounded(reg))
> 18251 reg->precise = true;
> 18252 }
> 18253 for (j = 0; j < func->allocated_stack / BPF_REG_SIZE; j++) {
> 18254 reg = &func->stack[j].spilled_ptr;
> 18255 reg->live |= REG_LIVE_READ64;
> 18256 if (is_spilled_reg(&func->stack[j]) &&
> 18257 reg->type == SCALAR_VALUE && !is_reg_unbounded(reg))
> 18258 reg->precise = true;
> 18259 }
> 18260 }
> 18261 }
> 18262
>
next prev parent reply other threads:[~2025-04-26 19:51 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-26 10:46 [PATCH bpf-next v1 0/4] bpf: compute SCC for BPF program control flow graph Eduard Zingerman
2025-04-26 10:46 ` [PATCH bpf-next v1 1/4] bpf: compute SCCs in " Eduard Zingerman
2025-04-26 10:46 ` [PATCH bpf-next v1 2/4] bpf: frame_insn_idx() utility function Eduard Zingerman
2025-04-26 10:46 ` [PATCH bpf-next v1 3/4] bpf: use SCC info instead of loop_entry Eduard Zingerman
2025-04-26 14:45 ` kernel test robot
2025-04-26 19:51 ` Eduard Zingerman [this message]
2025-04-28 17:31 ` Alexei Starovoitov
2025-04-28 19:26 ` Eduard Zingerman
2025-04-28 20:25 ` Alexei Starovoitov
2025-04-28 21:00 ` Eduard Zingerman
2025-04-26 10:46 ` [PATCH bpf-next v1 4/4] selftests/bpf: tests with a loop state missing read/precision mark Eduard Zingerman
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=39942ee3ccbc7aba2017ee2d31add0cc1b538b22.camel@gmail.com \
--to=eddyz87@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=lkp@intel.com \
--cc=martin.lau@linux.dev \
--cc=oe-kbuild-all@lists.linux.dev \
--cc=yonghong.song@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.