summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-03-06 18:11:03 -0800
committerAlexei Starovoitov <ast@kernel.org>2026-03-06 18:16:17 -0800
commit6895e1d7c3171dc29097393749a6f4ebfb316860 (patch)
treea84f2b19739d91fe7d3d1430076a53af28a8a307 /kernel
parent56145d237385ca0e7ca9ff7b226aaf2eb8ef368b (diff)
parentd87c9305a8841b312b14ca0c360a563ef60b2a5b (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.c24
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);
+ }
}
}