mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 06:23:42 -04:00
selftests/bpf: Cover stack reads from zero spills
Add verifier_var_off coverage for variable-offset stack reads from spilled scalar constant zero values. Cover single-slot and cross-slot spilled zero reads, a sub-8-byte spill with neighbouring STACK_ZERO bytes, and a sub-8-byte spill with neighbouring STACK_MISC bytes that must not be treated as zero. Add verifier_spill_fill coverage for a fixed-offset stack read spanning both STACK_ZERO bytes and scalar const-zero STACK_SPILL bytes. Use verifier log assertions to check both the zero result and the precision backtracking trail. Assisted-by: opencode:gpt-5.5 Signed-off-by: Woojin Ji <random6.xyz@gmail.com> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20260625-bpf-stack-var-off-zero-v1-v3-2-a068210a761b@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
committed by
Alexei Starovoitov
parent
69fdbe63e1
commit
e693da913d
@@ -634,6 +634,32 @@ __naked void partial_stack_load_preserves_partial_zeros(void)
|
||||
: __clobber_common);
|
||||
}
|
||||
|
||||
SEC("raw_tp")
|
||||
__log_level(2)
|
||||
__success
|
||||
__msg("mark_precise: frame0: regs= stack=-8")
|
||||
__msg("R2=0")
|
||||
__naked void stack_load_preserves_mixed_zero_and_zero_spill(void)
|
||||
{
|
||||
asm volatile (
|
||||
/* fp-8 has scalar const-zero spill bytes and STACK_ZERO bytes. */
|
||||
".8byte %[fp4_st_zero];" /* LLVM-18+: *(u32 *)(r10 -4) = 0; */
|
||||
"r0 = 0;"
|
||||
"*(u32 *)(r10 -8) = r0;"
|
||||
|
||||
"r1 = %[single_byte_buf];"
|
||||
"r2 = *(u64 *)(r10 -8);"
|
||||
"r1 += r2;"
|
||||
"*(u8 *)(r1 + 0) = r2;" /* this should be fine */
|
||||
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
:
|
||||
: __imm_ptr(single_byte_buf),
|
||||
__imm_insn(fp4_st_zero, BPF_ST_MEM(BPF_W, BPF_REG_FP, -4, 0))
|
||||
: __clobber_common);
|
||||
}
|
||||
|
||||
char two_byte_buf[2] SEC(".data.two_byte_buf");
|
||||
|
||||
SEC("raw_tp")
|
||||
|
||||
@@ -59,6 +59,116 @@ __naked void stack_read_priv_vs_unpriv(void)
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("cgroup/skb")
|
||||
__description("variable-offset stack read preserves spilled zero")
|
||||
__success
|
||||
__log_level(2)
|
||||
__msg("mark_precise: frame0: regs= stack=-8")
|
||||
__msg("R3=0")
|
||||
__retval(0)
|
||||
__naked void stack_read_var_off_preserves_spilled_zero(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
*(u64*)(r10 - 8) = r0; \
|
||||
r2 = *(u32*)(r1 + 0); \
|
||||
r2 &= 7; \
|
||||
r2 -= 8; \
|
||||
r2 += r10; \
|
||||
r3 = *(u8*)(r2 + 0); \
|
||||
r1 = r10; \
|
||||
r1 += -1; \
|
||||
r1 += r3; \
|
||||
*(u8*)(r1 + 0) = r3; \
|
||||
r0 = 0; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("cgroup/skb")
|
||||
__description("variable-offset stack read preserves spilled zero across slots")
|
||||
__success
|
||||
__log_level(2)
|
||||
__msg("mark_precise: frame0: regs= stack=-8,-16")
|
||||
__msg("R3=0")
|
||||
__retval(0)
|
||||
__naked void stack_read_var_off_preserves_spilled_zero_across_slots(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
*(u64*)(r10 - 8) = r0; \
|
||||
*(u64*)(r10 - 16) = r0; \
|
||||
r2 = *(u32*)(r1 + 0); \
|
||||
r2 &= 15; \
|
||||
r2 -= 16; \
|
||||
r2 += r10; \
|
||||
r3 = *(u8*)(r2 + 0); \
|
||||
r1 = r10; \
|
||||
r1 += -1; \
|
||||
r1 += r3; \
|
||||
*(u8*)(r1 + 0) = r3; \
|
||||
r0 = 0; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("cgroup/skb")
|
||||
__description("variable-offset stack read preserves partial spilled zero")
|
||||
__success
|
||||
__log_level(2)
|
||||
__msg("mark_precise: frame0: regs= stack=-8")
|
||||
__msg("R3=0")
|
||||
__retval(0)
|
||||
__naked void stack_read_var_off_preserves_partial_spilled_zero(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
*(u8*)(r10 - 9) = r0; \
|
||||
*(u8*)(r10 - 10) = r0; \
|
||||
*(u8*)(r10 - 11) = r0; \
|
||||
*(u8*)(r10 - 12) = r0; \
|
||||
*(u8*)(r10 - 13) = r0; \
|
||||
*(u8*)(r10 - 14) = r0; \
|
||||
*(u8*)(r10 - 15) = r0; \
|
||||
*(u32*)(r10 - 8) = r0; \
|
||||
r2 = *(u32*)(r1 + 0); \
|
||||
r2 &= 15; \
|
||||
if r2 > 10 goto l0_%=; \
|
||||
r2 -= 15; \
|
||||
r2 += r10; \
|
||||
r3 = *(u8*)(r2 + 0); \
|
||||
r1 = r10; \
|
||||
r1 += -1; \
|
||||
r1 += r3; \
|
||||
*(u8*)(r1 + 0) = r3; \
|
||||
l0_%=: r0 = 0; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("cgroup/skb")
|
||||
__description("variable-offset stack read partial spill with misc data")
|
||||
__failure
|
||||
__msg("invalid variable-offset write to stack R1")
|
||||
__naked void stack_read_var_off_partial_spill_with_misc_data(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
*(u32*)(r10 - 8) = r0; \
|
||||
r2 = *(u32*)(r1 + 0); \
|
||||
r2 &= 7; \
|
||||
r2 -= 8; \
|
||||
r2 += r10; \
|
||||
r3 = *(u8*)(r2 + 0); \
|
||||
r1 = r10; \
|
||||
r1 += -1; \
|
||||
r1 += r3; \
|
||||
*(u8*)(r1 + 0) = 0; \
|
||||
r0 = 0; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("cgroup/skb")
|
||||
__description("variable-offset stack read, uninitialized")
|
||||
__success
|
||||
|
||||
Reference in New Issue
Block a user