Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bpf: verifier: Make sync_linked_regs() scratch registers

sync_linked_regs() is called after a conditional jump to propagate new
bounds of a register to all its liked registers. But the verifier log
only prints the state of the register that is part of the conditional
jump.

Make sync_linked_regs() scratch the registers whose bounds have been
updated by propagation from a known register.

Before:

0: (85) call bpf_get_prandom_u32#7 ; R0=scalar()
1: (57) r0 &= 255 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
2: (bf) r1 = r0 ; R0=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R1=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
3: (07) r1 += 4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=4,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff))
4: (a5) if r1 < 0xa goto pc+2 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=10,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff))
5: (35) if r0 >= 0x6 goto pc+1

After:

0: (85) call bpf_get_prandom_u32#7 ; R0=scalar()
1: (57) r0 &= 255 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
2: (bf) r1 = r0 ; R0=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R1=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
3: (07) r1 += 4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=4,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff))
4: (a5) if r1 < 0xa goto pc+2 ; R0=scalar(id=1+0,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) R1=scalar(id=1+4,smin=umin=smin32=umin32=10,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff))
5: (35) if r0 >= 0x6 goto pc+1

The conditional jump in 4 updates the bound of R1 and the new bounds are
propogated to R0 as it is linked with the same id, before this change,
verifier only printed the state for R1 but after it prints for both R0
and R1.

Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/bpf/20260116141436.3715322-1-puranjay@kernel.org

authored by

Puranjay Mohan and committed by
Andrii Nakryiko
ef7d4e42 efad162f

+12 -6
+12 -6
kernel/bpf/verifier.c
··· 16846 16846 /* For all R in linked_regs, copy known_reg range into R 16847 16847 * if R->id == known_reg->id. 16848 16848 */ 16849 - static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_state *known_reg, 16850 - struct linked_regs *linked_regs) 16849 + static void sync_linked_regs(struct bpf_verifier_env *env, struct bpf_verifier_state *vstate, 16850 + struct bpf_reg_state *known_reg, struct linked_regs *linked_regs) 16851 16851 { 16852 16852 struct bpf_reg_state fake_reg; 16853 16853 struct bpf_reg_state *reg; ··· 16890 16890 scalar_min_max_add(reg, &fake_reg); 16891 16891 reg->var_off = tnum_add(reg->var_off, fake_reg.var_off); 16892 16892 } 16893 + if (e->is_reg) 16894 + mark_reg_scratched(env, e->regno); 16895 + else 16896 + mark_stack_slot_scratched(env, e->spi); 16893 16897 } 16894 16898 } 16895 16899 ··· 17080 17076 if (BPF_SRC(insn->code) == BPF_X && 17081 17077 src_reg->type == SCALAR_VALUE && src_reg->id && 17082 17078 !WARN_ON_ONCE(src_reg->id != other_branch_regs[insn->src_reg].id)) { 17083 - sync_linked_regs(this_branch, src_reg, &linked_regs); 17084 - sync_linked_regs(other_branch, &other_branch_regs[insn->src_reg], &linked_regs); 17079 + sync_linked_regs(env, this_branch, src_reg, &linked_regs); 17080 + sync_linked_regs(env, other_branch, &other_branch_regs[insn->src_reg], 17081 + &linked_regs); 17085 17082 } 17086 17083 if (dst_reg->type == SCALAR_VALUE && dst_reg->id && 17087 17084 !WARN_ON_ONCE(dst_reg->id != other_branch_regs[insn->dst_reg].id)) { 17088 - sync_linked_regs(this_branch, dst_reg, &linked_regs); 17089 - sync_linked_regs(other_branch, &other_branch_regs[insn->dst_reg], &linked_regs); 17085 + sync_linked_regs(env, this_branch, dst_reg, &linked_regs); 17086 + sync_linked_regs(env, other_branch, &other_branch_regs[insn->dst_reg], 17087 + &linked_regs); 17090 17088 } 17091 17089 17092 17090 /* if one pointer register is compared to another pointer