1

Merge branch 'fix-truncation-bug-in-coerce_reg_to_size_sx-and-extend-selftests'

Dimitar Kanaliev says:

====================
Fix truncation bug in coerce_reg_to_size_sx and extend selftests.

This patch series addresses a truncation bug in the eBPF verifier function
coerce_reg_to_size_sx(). The issue was caused by the incorrect ordering
of assignments between 32-bit and 64-bit min/max values, leading to
improper truncation when updating the register state. This issue has been
reported previously by Zac Ecob[1] , but was not followed up on.

The first patch fixes the assignment order in coerce_reg_to_size_sx()
to ensure correct truncation. The subsequent patches add selftests for
coerce_{reg,subreg}_to_size_sx.

Changelog:
	v1 -> v2:
	 - Moved selftests inside the conditional check for cpuv4

[1] (https://lore.kernel.org/bpf/h3qKLDEO6m9nhif0eAQX4fVrqdO0D_OPb0y5HfMK9jBePEKK33wQ3K-bqSVnr0hiZdFZtSJOsbNkcEQGpv_yJk61PAAiO8fUkgMRSO-lB50=@protonmail.com/)
====================

Link: https://lore.kernel.org/r/20241014121155.92887-1-dimitar.kanaliev@siteground.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2024-10-15 11:16:25 -07:00
commit ee230090f6
2 changed files with 44 additions and 4 deletions

View File

@ -6339,10 +6339,10 @@ static void coerce_reg_to_size_sx(struct bpf_reg_state *reg, int size)
/* both of s64_max/s64_min positive or negative */
if ((s64_max >= 0) == (s64_min >= 0)) {
reg->smin_value = reg->s32_min_value = s64_min;
reg->smax_value = reg->s32_max_value = s64_max;
reg->umin_value = reg->u32_min_value = s64_min;
reg->umax_value = reg->u32_max_value = s64_max;
reg->s32_min_value = reg->smin_value = s64_min;
reg->s32_max_value = reg->smax_value = s64_max;
reg->u32_min_value = reg->umin_value = s64_min;
reg->u32_max_value = reg->umax_value = s64_max;
reg->var_off = tnum_range(s64_min, s64_max);
return;
}

View File

@ -287,6 +287,46 @@ l0_%=: \
: __clobber_all);
}
SEC("socket")
__description("MOV64SX, S8, unsigned range_check")
__success __retval(0)
__naked void mov64sx_s8_range_check(void)
{
asm volatile (" \
call %[bpf_get_prandom_u32]; \
r0 &= 0x1; \
r0 += 0xfe; \
r0 = (s8)r0; \
if r0 < 0xfffffffffffffffe goto label_%=; \
r0 = 0; \
exit; \
label_%=: \
exit; \
" :
: __imm(bpf_get_prandom_u32)
: __clobber_all);
}
SEC("socket")
__description("MOV32SX, S8, unsigned range_check")
__success __retval(0)
__naked void mov32sx_s8_range_check(void)
{
asm volatile (" \
call %[bpf_get_prandom_u32]; \
w0 &= 0x1; \
w0 += 0xfe; \
w0 = (s8)w0; \
if w0 < 0xfffffffe goto label_%=; \
r0 = 0; \
exit; \
label_%=: \
exit; \
" :
: __imm(bpf_get_prandom_u32)
: __clobber_all);
}
#else
SEC("socket")