diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2026-03-06 18:11:03 -0800 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-03-06 18:16:17 -0800 |
| commit | 6895e1d7c3171dc29097393749a6f4ebfb316860 (patch) | |
| tree | a84f2b19739d91fe7d3d1430076a53af28a8a307 /kernel | |
| parent | 56145d237385ca0e7ca9ff7b226aaf2eb8ef368b (diff) | |
| parent | d87c9305a8841b312b14ca0c360a563ef60b2a5b (diff) | |
Merge branch 'bpf-fix-u32-s32-bounds-when-ranges-cross-min-max-boundary'
Eduard Zingerman says:
====================
bpf: Fix u32/s32 bounds when ranges cross min/max boundary
Cover the following cases in range refinement logic for 32-bit ranges:
- s32 range crosses U32_MAX/0 boundary, positive part of the s32 range
overlaps with u32 range.
- s32 range crosses U32_MAX/0 boundary, negative part of the s32 range
overlaps with u32 range.
These cases are already handled for 64-bit range refinement.
Without the fix the test in patch 2 is rejected by the verifier.
The test was reduced from sched-ext program.
Changelog:
- v2 -> v3:
- Reverted da653de268d3 (Paul)
- Removed !BPF_F_TEST_REG_INVARIANTS flag from
crossing_32_bit_signed_boundary_2() (Paul)
- v1 -> v2:
- Extended commit message and comments (Emil)
- Targeting 'bpf' tree instead of bpf-next (Alexei)
v1: https://lore.kernel.org/bpf/9a23fbacdc6d33ec8fcb3f6988395b5129f75369.camel@gmail.com/T
v2: https://lore.kernel.org/bpf/20260305-bpf-32-bit-range-overflow-v2-0-7169206a3041@gmail.com/
---
====================
Link: https://patch.msgid.link/20260306-bpf-32-bit-range-overflow-v3-0-f7f67e060a6b@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/verifier.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 401d6c4960ec..f960b382fdb3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -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); + } } } |
