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

Merge branch 'bpf-fix-missed-var_off-related-to-movsx-in-verifier'

Yonghong Song says:

====================
bpf: Fix missed var_off related to movsx in verifier

Zac reported a verification issue ([1]) where verification unexpectedly succeeded.
This is due to missing proper var_off setting in verifier related to
movsx insn. I found another similar issue as well. This patch set fixed
both problems and added three inline asm tests to test these fixes.

  [1] https://lore.kernel.org/bpf/CAADnVQLPU0Shz7dWV4bn2BgtGdxN3uFHPeobGBA72tpg5Xoykw@mail.gmail.com/


====================

Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20240615174621.3994321-1-yonghong.song@linux.dev


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 143492fc a62293c3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -6236,6 +6236,7 @@ static void set_sext32_default_val(struct bpf_reg_state *reg, int size)
	}
	reg->u32_min_value = 0;
	reg->u32_max_value = U32_MAX;
	reg->var_off = tnum_subreg(tnum_unknown);
}
static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size)
@@ -6280,6 +6281,7 @@ static void coerce_subreg_to_size_sx(struct bpf_reg_state *reg, int size)
		reg->s32_max_value = s32_max;
		reg->u32_min_value = (u32)s32_min;
		reg->u32_max_value = (u32)s32_max;
		reg->var_off = tnum_subreg(tnum_range(s32_min, s32_max));
		return;
	}
+63 −0
Original line number Diff line number Diff line
@@ -224,6 +224,69 @@ l0_%=: \
	: __clobber_all);
}

SEC("socket")
__description("MOV32SX, S8, var_off u32_max")
__failure __msg("infinite loop detected")
__failure_unpriv __msg_unpriv("back-edge from insn 2 to 0")
__naked void mov64sx_s32_varoff_1(void)
{
	asm volatile ("					\
l0_%=:							\
	r3 = *(u8 *)(r10 -387);				\
	w7 = (s8)w3;					\
	if w7 >= 0x2533823b goto l0_%=;			\
	w0 = 0;						\
	exit;						\
"	:
	:
	: __clobber_all);
}

SEC("socket")
__description("MOV32SX, S8, var_off not u32_max, positive after s8 extension")
__success __retval(0)
__failure_unpriv __msg_unpriv("frame pointer is read only")
__naked void mov64sx_s32_varoff_2(void)
{
	asm volatile ("					\
	call %[bpf_get_prandom_u32];			\
	r3 = r0;					\
	r3 &= 0xf;					\
	w7 = (s8)w3;					\
	if w7 s>= 16 goto l0_%=;			\
	w0 = 0;						\
	exit;						\
l0_%=:							\
	r10 = 1;					\
	exit;						\
"	:
	: __imm(bpf_get_prandom_u32)
	: __clobber_all);
}

SEC("socket")
__description("MOV32SX, S8, var_off not u32_max, negative after s8 extension")
__success __retval(0)
__failure_unpriv __msg_unpriv("frame pointer is read only")
__naked void mov64sx_s32_varoff_3(void)
{
	asm volatile ("					\
	call %[bpf_get_prandom_u32];			\
	r3 = r0;					\
	r3 &= 0xf;					\
	r3 |= 0x80;					\
	w7 = (s8)w3;					\
	if w7 s>= -5 goto l0_%=;			\
	w0 = 0;						\
	exit;						\
l0_%=:							\
	r10 = 1;					\
	exit;						\
"	:
	: __imm(bpf_get_prandom_u32)
	: __clobber_all);
}

#else

SEC("socket")