Re: [PATCH bpf-next v3 03/12] bpf: Prepare linked scalars for relations narrower than 64 bits

From: bot+bpf-ci

Date: Tue Oct 20 2026 - 13:18:48 EST


> bpf: Prepare linked scalars for relations narrower than 64 bits

TL;DR: Commit message only: regs_exact() now also rejects states whose linked
scalars share a base id in old but not in cur, a stricter infinite-loop check
the changelog doesn't mention.

> bpf: Prepare linked scalars for relations narrower than 64 bits
>
> Two scalars sharing an ->id are always related by full 64-bit equality
> today: reg == base + delta over all 64 bits (this is true for
> BPF_ADD_CONST32 as well, which implies upper bits to be all zero).
> Sign-extension needs a genuinely low32 equal only relationship kind
> with bit 31 supplying upper 32-bits.
>
> Today the following 2 relationships exist
>
> #define BPF_ADD_CONST64 (1U << 31)
> #define BPF_ADD_CONST32 (1U << 30)
>
> Model them differently as
>
> enum bpf_reg_link_kind { BPF_REG_LINK_NONE, BPF_REG_LINK_FULL,
> BPF_REG_LINK_ZEXT, BPF_REG_LINK_SEXT };
>
> So BPF_ADD_CONST64 becomes BPF_REG_LINK_FULL and BPF_ADD_CONST32 becomes
> BPF_REG_LINK_ZEXT with the exact same semantics as today. But this paves
> the way for a future BPF_REG_LINK_SEXT in the same framework.
>
> The implementation needs to change as well. Today the above 2 bits are
> shoe-horned into ->id, needing masking and OR'ing to get ->id and kind
> bits: with more types and bits needed, move them out into an enum
> bitfield of its own. To avoid growing the storage (and stay within the
> 1K allocator bucket), borrow 2 bits out of ->map_uid, 31 -> 29, which is
> still far more ids than a program can generate.
>
> ->id becomes a plain identifier, so check_scalar_ids() loses its "compare
> the compound id, then the base id" dance in favour of one check_ids().
>
> With the kind out of ->id it also leaves the idmap key, so regs_exact()
> and regsafe()'s explore_alu_limits arm have to compare it explicitly.
>
> One case changes behaviour -- old {r2.id=A+delta32} against
> cur {r2.id=B+delta64} was accepted and is now rejected, correctly, since
> alu32 and alu64 deltas diverge in sync_linked_regs().
>
> Clearing a link is no longer just ->id = 0: any stale ->link_kind needs
> to be cleared out as well. And given this needs to be done in the newly
> added kernel/bpf/scev.c, it is moved into bpf_verifier.h as
> bpf_clear_scalar_id().
>
> The helper also zeroes ->delta, which the open-coded clear left behind.
> Unlike ->id that field is inside the memcmp() prefix state comparison
> uses, so a leftover value could keep two otherwise-identical states
> apart; clearing it can only help pruning.
>
> Suggested-by: Eduard Zingerman <eddyz87@xxxxxxxxx>
> Signed-off-by: Vineet Gupta <vineet.gupta@xxxxxxxxx>

The changelog lists only the delta32/delta64 mismatch as a case that changes
behaviour. Is that the only one?

regs_exact() also changes. It used to run check_ids() on the compound id,
so old {r2.id=A, r3.id=A|BPF_ADD_CONST64} against cur {r2.id=B,
r3.id=C|BPF_ADD_CONST64} built two independent idmap entries (A->B and
A|flag->C|flag) and was accepted as exact.

With the kind moved out of ->id, the same pair now maps A->B and then A->C,
and check_ids() rejects it:

return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 &&
rold->link_kind == rcur->link_kind &&
check_ids(rold->id, rcur->id, idmap) && ...

regs_exact() is reached through regsafe(..., EXACT) from the infinite loop
check in bpf_is_state_visited():

states_equal(env, &sl->state, cur, EXACT)

so this is a stricter comparison than before.

Could the changelog also say that regs_exact() now enforces base-id
consistency for linked scalars, which the old compound-id idmap key did not?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/39458500836