Skip to content

Commit b2a0aa3

Browse files
puranjaymohanAlexei Starovoitov
authored andcommitted
bpf: Clear singular ids for scalars in is_state_visited()
The verifier assigns ids to scalar registers/stack slots when they are linked through a mov or stack spill/fill instruction. These ids are later used to propagate newly found bounds from one register to all registers that share the same id. The verifier also compares the ids of these registers in current state and cached state when making pruning decisions. When an ID becomes singular (i.e., only a single register or stack slot has that ID), it can no longer participate in bounds propagation. During comparisons between current and cached states for pruning decisions, however, such stale IDs can prevent pruning of otherwise equivalent states. Find and clear all singular ids before caching a state in is_state_visited(). struct bpf_idset which is currently unused has been repurposed for this use case. Acked-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Puranjay Mohan <puranjay@kernel.org> Link: https://lore.kernel.org/r/20260203165102.2302462-3-puranjay@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 3cd5c89 commit b2a0aa3

2 files changed

Lines changed: 73 additions & 2 deletions

File tree

include/linux/bpf_verifier.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,8 +697,11 @@ struct bpf_idmap {
697697
};
698698

699699
struct bpf_idset {
700-
u32 count;
701-
u32 ids[BPF_ID_MAP_SIZE];
700+
u32 num_ids;
701+
struct {
702+
u32 id;
703+
u32 cnt;
704+
} entries[BPF_ID_MAP_SIZE];
702705
};
703706

704707
/* see verifier.c:compute_scc_callchain() */

kernel/bpf/verifier.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19461,6 +19461,72 @@ static void clean_verifier_state(struct bpf_verifier_env *env,
1946119461
* doesn't meant that the states are DONE. The verifier has to compare
1946219462
* the callsites
1946319463
*/
19464+
19465+
/* Find id in idset and increment its count, or add new entry */
19466+
static void idset_cnt_inc(struct bpf_idset *idset, u32 id)
19467+
{
19468+
u32 i;
19469+
19470+
for (i = 0; i < idset->num_ids; i++) {
19471+
if (idset->entries[i].id == id) {
19472+
idset->entries[i].cnt++;
19473+
return;
19474+
}
19475+
}
19476+
/* New id */
19477+
if (idset->num_ids < BPF_ID_MAP_SIZE) {
19478+
idset->entries[idset->num_ids].id = id;
19479+
idset->entries[idset->num_ids].cnt = 1;
19480+
idset->num_ids++;
19481+
}
19482+
}
19483+
19484+
/* Find id in idset and return its count, or 0 if not found */
19485+
static u32 idset_cnt_get(struct bpf_idset *idset, u32 id)
19486+
{
19487+
u32 i;
19488+
19489+
for (i = 0; i < idset->num_ids; i++) {
19490+
if (idset->entries[i].id == id)
19491+
return idset->entries[i].cnt;
19492+
}
19493+
return 0;
19494+
}
19495+
19496+
/*
19497+
* Clear singular scalar ids in a state.
19498+
* A register with a non-zero id is called singular if no other register shares
19499+
* the same base id. Such registers can be treated as independent (id=0).
19500+
*/
19501+
static void clear_singular_ids(struct bpf_verifier_env *env,
19502+
struct bpf_verifier_state *st)
19503+
{
19504+
struct bpf_idset *idset = &env->idset_scratch;
19505+
struct bpf_func_state *func;
19506+
struct bpf_reg_state *reg;
19507+
19508+
idset->num_ids = 0;
19509+
19510+
bpf_for_each_reg_in_vstate(st, func, reg, ({
19511+
if (reg->type != SCALAR_VALUE)
19512+
continue;
19513+
if (!reg->id)
19514+
continue;
19515+
idset_cnt_inc(idset, reg->id & ~BPF_ADD_CONST);
19516+
}));
19517+
19518+
bpf_for_each_reg_in_vstate(st, func, reg, ({
19519+
if (reg->type != SCALAR_VALUE)
19520+
continue;
19521+
if (!reg->id)
19522+
continue;
19523+
if (idset_cnt_get(idset, reg->id & ~BPF_ADD_CONST) == 1) {
19524+
reg->id = 0;
19525+
reg->off = 0;
19526+
}
19527+
}));
19528+
}
19529+
1946419530
static void clean_live_states(struct bpf_verifier_env *env, int insn,
1946519531
struct bpf_verifier_state *cur)
1946619532
{
@@ -20459,6 +20525,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
2045920525
if (env->bpf_capable)
2046020526
mark_all_scalars_imprecise(env, cur);
2046120527

20528+
clear_singular_ids(env, cur);
20529+
2046220530
/* add new state to the head of linked list */
2046320531
new = &new_sl->state;
2046420532
err = copy_verifier_state(new, cur);

0 commit comments

Comments
 (0)