Commit b42eb55f authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

selftests/bpf: update existing tests due to liveness changes



The verifier cleans all dead registers and stack slots in the current
state. Adjust expected output in tests or insert dummy stack/register
reads. Also update verifier_live_stack tests to adhere to new logging
scheme.

Signed-off-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260410-patch-set-v4-11-5d4eecb343db@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 2c167d91
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ check_assert(s64, >=, ge_neg, INT_MIN);

SEC("?tc")
__log_level(2) __failure
__msg(": R0=0 R1=ctx() R2=scalar(smin=0xffffffff80000002,smax=smax32=0x7ffffffd,smin32=0x80000002) R10=fp0")
__msg(": R1=ctx() R2=scalar(smin=0xffffffff80000002,smax=smax32=0x7ffffffd,smin32=0x80000002) R10=fp0")
int check_assert_range_s64(struct __sk_buff *ctx)
{
	struct bpf_sock *sk = ctx->sk;
@@ -86,7 +86,7 @@ int check_assert_range_u64(struct __sk_buff *ctx)

SEC("?tc")
__log_level(2) __failure
__msg(": R0=0 R1=ctx() R2=4096 R10=fp0")
__msg(": R1=ctx() R2=4096 R10=fp0")
int check_assert_single_range_s64(struct __sk_buff *ctx)
{
	struct bpf_sock *sk = ctx->sk;
@@ -114,7 +114,7 @@ int check_assert_single_range_u64(struct __sk_buff *ctx)

SEC("?tc")
__log_level(2) __failure
__msg(": R1=pkt(r=64,imm=64) R2=pkt_end() R6=pkt(r=64) R10=fp0")
__msg(": R6=pkt(r=64) R10=fp0")
int check_assert_generic(struct __sk_buff *ctx)
{
	u8 *data_end = (void *)(long)ctx->data_end;
+1 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ __naked int helper_uninit_to_misc(void *ctx)
		 * thus showing the stack state, matched by __msg().		\
		 */					\
		call %[dummy];				\
		r1 = *(u64*)(r10 - 104);		\
		r0 = 0;					\
		exit;					\
"
+5 −5
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ LBL ":" \
SEC("tc")
__success __log_level(2)
__flag(BPF_F_ANY_ALIGNMENT)
__msg("6: R0=pkt(r=8,imm=8)")
__msg("6: {{.*}} R2=pkt(r=8)")
__msg("6: {{.*}} R3={{[^)]*}}var_off=(0x0; 0xff)")
__msg("7: {{.*}} R3={{[^)]*}}var_off=(0x0; 0x1fe)")
__msg("8: {{.*}} R3={{[^)]*}}var_off=(0x0; 0x3fc)")
@@ -205,7 +205,7 @@ __success __log_level(2)
__msg("2: {{.*}} R5=pkt(r=0)")
__msg("4: {{.*}} R5=pkt(r=0,imm=14)")
__msg("5: {{.*}} R4=pkt(r=0,imm=14)")
__msg("9: {{.*}} R2=pkt(r=18)")
__msg("9: {{.*}} R5=pkt(r=18,imm=14)")
__msg("10: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff){{.*}} R5=pkt(r=18,imm=14)")
__msg("13: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xffff)")
__msg("14: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xffff)")
@@ -254,7 +254,7 @@ __msg("11: {{.*}} R5=pkt(id=1,{{[^)]*}},var_off=(0x2; 0x7fc)")
 * offset is considered using reg->aux_off_align which
 * is 4 and meets the load's requirements.
 */
__msg("15: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc){{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
__msg("15: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
/* Variable offset is added to R5 packet pointer,
 * resulting in auxiliary alignment of 4. To avoid BPF
 * verifier's precision backtracking logging
@@ -273,7 +273,7 @@ __msg("19: {{.*}} R5=pkt(id=2,{{[^)]*}}var_off=(0x2; 0x7fc)")
 * aligned, so the total offset is 4-byte aligned and
 * meets the load's requirements.
 */
__msg("24: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc){{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
__msg("24: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
/* Constant offset is added to R5 packet pointer,
 * resulting in reg->off value of 14.
 */
@@ -296,7 +296,7 @@ __msg("31: {{.*}} R4={{[^)]*}}var_off=(0x2; 0xffc){{.*}} R5={{[^)]*}}var_off=(0x
 * the total offset is 4-byte aligned and meets the
 * load's requirements.
 */
__msg("35: {{.*}} R4={{[^)]*}}var_off=(0x2; 0xffc){{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
__msg("35: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
__naked void packet_variable_offset(void)
{
	asm volatile ("					\
+10 −8
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ l0_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("UDIV32, zero divisor")
__success __retval(0) __log_level(2)
__msg("w1 /= w2 {{.*}}; R1=0 R2=0")
__msg("w1 /= w2 {{.*}}; R1=0")
__naked void udiv32_zero_divisor(void)
{
	asm volatile ("					\
@@ -81,7 +81,7 @@ l0_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("UDIV64, zero divisor")
__success __retval(0) __log_level(2)
__msg("r1 /= r2 {{.*}}; R1=0 R2=0")
__msg("r1 /= r2 {{.*}}; R1=0")
__naked void udiv64_zero_divisor(void)
{
	asm volatile ("					\
@@ -242,7 +242,7 @@ l1_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("SDIV32, zero divisor")
__success __retval(0) __log_level(2)
__msg("w1 s/= w2 {{.*}}; R1=0 R2=0")
__msg("w1 s/= w2 {{.*}}; R1=0")
__naked void sdiv32_zero_divisor(void)
{
	asm volatile ("					\
@@ -275,6 +275,7 @@ __naked void sdiv32_overflow_1(void)
	w2 += 10;					\
	if w1 s> w2 goto l0_%=;				\
	w1 s/= -1;					\
	r2 = r1;					\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
@@ -443,7 +444,7 @@ l1_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("SDIV64, zero divisor")
__success __retval(0) __log_level(2)
__msg("r1 s/= r2 {{.*}}; R1=0 R2=0")
__msg("r1 s/= r2 {{.*}}; R1=0")
__naked void sdiv64_zero_divisor(void)
{
	asm volatile ("					\
@@ -476,6 +477,7 @@ __naked void sdiv64_overflow_1(void)
	r2 += 10;					\
	if r1 s> r2 goto l0_%=;				\
	r1 s/= -1;					\
	r2 = r1;					\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
@@ -553,7 +555,7 @@ l0_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("UMOD32, zero divisor")
__success __retval(0) __log_level(2)
__msg("w1 %= w2 {{.*}}; R1=scalar(smin=umin=smin32=umin32=1,smax=umax=smax32=umax32=9,var_off=(0x1; 0x8)) R2=0")
__msg("w1 %= w2 {{.*}}; R1=scalar(smin=umin=smin32=umin32=1,smax=umax=smax32=umax32=9,var_off=(0x1; 0x8))")
__naked void umod32_zero_divisor(void)
{
	asm volatile ("					\
@@ -624,7 +626,7 @@ l0_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("UMOD64, zero divisor")
__success __retval(0) __log_level(2)
__msg("r1 %= r2 {{.*}}; R1=scalar(smin=umin=smin32=umin32=1,smax=umax=smax32=umax32=9,var_off=(0x1; 0x8)) R2=0")
__msg("r1 %= r2 {{.*}}; R1=scalar(smin=umin=smin32=umin32=1,smax=umax=smax32=umax32=9,var_off=(0x1; 0x8))")
__naked void umod64_zero_divisor(void)
{
	asm volatile ("					\
@@ -833,7 +835,7 @@ l1_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("SMOD32, zero divisor")
__success __retval(0) __log_level(2)
__msg("w1 s%= w2 {{.*}}; R1=scalar(smin=0,smax=umax=0xffffffff,smin32=-8,smax32=10,var_off=(0x0; 0xffffffff)) R2=0")
__msg("w1 s%= w2 {{.*}}; R1=scalar(smin=0,smax=umax=0xffffffff,smin32=-8,smax32=10,var_off=(0x0; 0xffffffff))")
__naked void smod32_zero_divisor(void)
{
	asm volatile ("					\
@@ -1084,7 +1086,7 @@ l1_%=: r0 = *(u64 *)(r1 + 0); \
SEC("socket")
__description("SMOD64, zero divisor")
__success __retval(0) __log_level(2)
__msg("r1 s%= r2 {{.*}}; R1=scalar(smin=smin32=-8,smax=smax32=10) R2=0")
__msg("r1 s%= r2 {{.*}}; R1=scalar(smin=smin32=-8,smax=smax32=10)")
__naked void smod64_zero_divisor(void)
{
	asm volatile ("					\
+35 −53
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"

char _license[] SEC("license") = "GPL";
struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(max_entries, 1);
@@ -14,12 +15,9 @@ struct {

SEC("socket")
__log_level(2)
__msg("(0) frame 0 insn 2 +written -8")
__msg("(0) frame 0 insn 1 +live -24")
__msg("(0) frame 0 insn 1 +written -8")
__msg("(0) frame 0 insn 0 +live -8,-24")
__msg("(0) frame 0 insn 0 +written -8")
__msg("(0) live stack update done in 2 iterations")
__msg("0: (79) r1 = *(u64 *)(r10 -8)        ; use: fp0-8")
__msg("1: (79) r2 = *(u64 *)(r10 -24)       ; use: fp0-24")
__msg("2: (7b) *(u64 *)(r10 -8) = r1        ; def: fp0-8")
__naked void simple_read_simple_write(void)
{
	asm volatile (
@@ -33,12 +31,8 @@ __naked void simple_read_simple_write(void)

SEC("socket")
__log_level(2)
__msg("(0) frame 0 insn 1 +live -8")
__not_msg("(0) frame 0 insn 1 +written")
__msg("(0) live stack update done in 2 iterations")
__msg("(0) frame 0 insn 1 +live -16")
__msg("(0) frame 0 insn 1 +written -32")
__msg("(0) live stack update done in 2 iterations")
__msg("2: (79) r0 = *(u64 *)(r10 -8)        ; use: fp0-8")
__msg("6: (79) r0 = *(u64 *)(r10 -16)       ; use: fp0-16")
__naked void read_write_join(void)
{
	asm volatile (
@@ -58,13 +52,9 @@ __naked void read_write_join(void)

SEC("socket")
__log_level(2)
__msg("2: (25) if r0 > 0x2a goto pc+1")
__msg("7: (95) exit")
__msg("(0) frame 0 insn 2 +written -16")
__msg("(0) live stack update done in 2 iterations")
__msg("7: (95) exit")
__not_msg("(0) frame 0 insn 2")
__msg("(0) live stack update done in 1 iterations")
__msg("stack use/def subprog#0 must_write_not_same_slot (d0,cs0):")
__msg("6: (7b) *(u64 *)(r2 +0) = r0{{$}}")
__msg("Live regs before insn:")
__naked void must_write_not_same_slot(void)
{
	asm volatile (
@@ -83,10 +73,8 @@ __naked void must_write_not_same_slot(void)

SEC("socket")
__log_level(2)
__msg("(0) frame 0 insn 0 +written -8,-16")
__msg("(0) live stack update done in 2 iterations")
__msg("(0) frame 0 insn 0 +written -8")
__msg("(0) live stack update done in 2 iterations")
__msg("0: (7a) *(u64 *)(r10 -8) = 0         ; def: fp0-8")
__msg("5: (85) call bpf_map_lookup_elem#1   ; use: fp0-8h")
__naked void must_write_not_same_type(void)
{
	asm volatile (
@@ -110,10 +98,11 @@ __naked void must_write_not_same_type(void)

SEC("socket")
__log_level(2)
__msg("(2,4) frame 0 insn 4 +written -8")
__msg("(2,4) live stack update done in 2 iterations")
__msg("(0) frame 0 insn 2 +written -8")
__msg("(0) live stack update done in 2 iterations")
/* Callee writes fp[0]-8: stack_use at call site has slots 0,1 live */
__msg("stack use/def subprog#0 caller_stack_write (d0,cs0):")
__msg("2: (85) call pc+1{{$}}")
__msg("stack use/def subprog#1 write_first_param (d1,cs2):")
__msg("4: (7a) *(u64 *)(r1 +0) = 7          ; def: fp0-8")
__naked void caller_stack_write(void)
{
	asm volatile (
@@ -135,23 +124,15 @@ static __used __naked void write_first_param(void)

SEC("socket")
__log_level(2)
/* caller_stack_read() function */
__msg("2: .12345.... (85) call pc+4")
__msg("5: .12345.... (85) call pc+1")
__msg("6: 0......... (95) exit")
/* read_first_param() function */
__msg("7: .1........ (79) r0 = *(u64 *)(r1 +0)")
__msg("8: 0......... (95) exit")
/* update for callsite at (2) */
__msg("(2,7) frame 0 insn 7 +live -8")
__msg("(2,7) live stack update done in 2 iterations")
__msg("(0) frame 0 insn 2 +live -8")
__msg("(0) live stack update done in 2 iterations")
/* update for callsite at (5) */
__msg("(5,7) frame 0 insn 7 +live -16")
__msg("(5,7) live stack update done in 2 iterations")
__msg("(0) frame 0 insn 5 +live -16")
__msg("(0) live stack update done in 2 iterations")
__msg("stack use/def subprog#0 caller_stack_read (d0,cs0):")
__msg("2: (85) call pc+{{.*}}                   ; use: fp0-8{{$}}")
__msg("5: (85) call pc+{{.*}}                   ; use: fp0-16{{$}}")
__msg("stack use/def subprog#1 read_first_param (d1,cs2):")
__msg("7: (79) r0 = *(u64 *)(r1 +0)         ; use: fp0-8{{$}}")
__msg("8: (95) exit")
__msg("stack use/def subprog#1 read_first_param (d1,cs5):")
__msg("7: (79) r0 = *(u64 *)(r1 +0)         ; use: fp0-16{{$}}")
__msg("8: (95) exit")
__naked void caller_stack_read(void)
{
	asm volatile (
@@ -176,18 +157,19 @@ static __used __naked void read_first_param(void)
SEC("socket")
__flag(BPF_F_TEST_STATE_FREQ)
__log_level(2)
/* read_first_param2() function */
__msg(" 9: .1........ (79) r0 = *(u64 *)(r1 +0)")
__msg("10: .......... (b7) r0 = 0")
__msg("11: 0......... (05) goto pc+0")
__msg("12: 0......... (95) exit")
/* fp0-8 consumed at insn 9, dead by insn 11. stack_def at insn 4 kills slots 0,1. */
__msg("4: (7b) *(u64 *)(r10 -8) = r0        ; def: fp0-8")
/* stack_use at call site: callee reads fp0-8, slots 0,1 live */
__msg("7: (85) call pc+{{.*}}               ; use: fp0-8")
/* read_first_param2: no caller stack live inside callee after first read */
__msg("9: (79) r0 = *(u64 *)(r1 +0)         ; use: fp0-8")
__msg("10: (b7) r0 = 0{{$}}")
__msg("11: (05) goto pc+0{{$}}")
__msg("12: (95) exit")
/*
 * The purpose of the test is to check that checkpoint in
 * read_first_param2() stops path traversal. This will only happen if
 * verifier understands that fp[0]-8 at insn (12) is not alive.
 * Checkpoint at goto +0 fires because fp0-8 is dead → state pruning.
 */
__msg("12: safe")
__msg("processed 20 insns")
__naked void caller_stack_pruning(void)
{
	asm volatile (
Loading