Re: [PATCH bpf-next v3 03/12] bpf: Prepare linked scalars for relations narrower than 64 bits
From: Vineet Gupta
Date: Mon Oct 26 2026 - 18:52:42 EST
On 10/20/26 10:08 AM, bot+bpf-ci@xxxxxxxxxx wrote:
bpf: Prepare linked scalars for relations narrower than 64 bitsTL;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 bitsThe changelog lists only the delta32/delta64 mismatch as a case that changes
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>
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?
Right. The example you mention is new.
Basically v2 had a patch of its own on this topic and it listed two cases
old {r1.id=A, r2.id=A+delta} vs cur {r1.id=B, r2.id=B}
old {r2.id=A+delta32} vs cur {r2.id=B+delta64}
Both were same category: one register whose kind differs between old and cur, caught by the new
rold->link_kind == rcur->link_kind line.
What you mention here is a different scenario:
old {r2.id=A, r3.id=A|BPF_ADD_CONST64}
cur {r2.id=B, r3.id=C|BPF_ADD_CONST64}
kinds match but it is still rejected, by check_ids().
v4 mentions both mechanisms.
Thx,
-Vineet
--
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