mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
bpf: Fix u32/s32 bounds when ranges cross min/max boundary
Same as in __reg64_deduce_bounds(), refine s32/u32 ranges in __reg32_deduce_bounds() in the following situations: - s32 range crosses U32_MAX/0 boundary, positive part of the s32 range overlaps with u32 range: 0 U32_MAX | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | |----------------------------|----------------------------| |xxxxx s32 range xxxxxxxxx] [xxxxxxx| 0 S32_MAX S32_MIN -1 - s32 range crosses U32_MAX/0 boundary, negative part of the s32 range overlaps with u32 range: 0 U32_MAX | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | |----------------------------|----------------------------| |xxxxxxxxx] [xxxxxxxxxxxx s32 range | 0 S32_MAX S32_MIN -1 - No refinement if ranges overlap in two intervals. This helps for e.g. consider the following program: call %[bpf_get_prandom_u32]; w0 &= 0xffffffff; if w0 < 0x3 goto 1f; // on fall-through u32 range [3..U32_MAX] if w0 s> 0x1 goto 1f; // on fall-through s32 range [S32_MIN..1] if w0 s< 0x0 goto 1f; // range can be narrowed to [S32_MIN..-1] r10 = 0; 1: ...; The reg_bounds.c selftest is updated to incorporate identical logic, refinement based on non-overflowing range halves: ((x ∩ [0, smax]) ∩ (y ∩ [0, smax])) ∪ ((x ∩ [smin,-1]) ∩ (y ∩ [smin,-1])) Reported-by: Andrea Righi <arighi@nvidia.com> Reported-by: Emil Tsalapatis <emil@etsalapatis.com> Closes: https://lore.kernel.org/bpf/aakqucg4vcujVwif@gpd4/T/ Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20260306-bpf-32-bit-range-overflow-v3-1-f7f67e060a6b@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
56145d2373
commit
fbc7aef517
2 changed files with 82 additions and 4 deletions
|
|
@ -2511,6 +2511,30 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg)
|
|||
if ((u32)reg->s32_min_value <= (u32)reg->s32_max_value) {
|
||||
reg->u32_min_value = max_t(u32, reg->s32_min_value, reg->u32_min_value);
|
||||
reg->u32_max_value = min_t(u32, reg->s32_max_value, reg->u32_max_value);
|
||||
} else {
|
||||
if (reg->u32_max_value < (u32)reg->s32_min_value) {
|
||||
/* See __reg64_deduce_bounds() for detailed explanation.
|
||||
* Refine ranges in the following situation:
|
||||
*
|
||||
* 0 U32_MAX
|
||||
* | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] |
|
||||
* |----------------------------|----------------------------|
|
||||
* |xxxxx s32 range xxxxxxxxx] [xxxxxxx|
|
||||
* 0 S32_MAX S32_MIN -1
|
||||
*/
|
||||
reg->s32_min_value = (s32)reg->u32_min_value;
|
||||
reg->u32_max_value = min_t(u32, reg->u32_max_value, reg->s32_max_value);
|
||||
} else if ((u32)reg->s32_max_value < reg->u32_min_value) {
|
||||
/*
|
||||
* 0 U32_MAX
|
||||
* | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] |
|
||||
* |----------------------------|----------------------------|
|
||||
* |xxxxxxxxx] [xxxxxxxxxxxx s32 range |
|
||||
* 0 S32_MAX S32_MIN -1
|
||||
*/
|
||||
reg->s32_max_value = (s32)reg->u32_max_value;
|
||||
reg->u32_min_value = max_t(u32, reg->u32_min_value, reg->s32_min_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue