]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: derive smin32/smax32 from umin32/umax32 bounds
authorAndrii Nakryiko <andrii@kernel.org>
Thu, 2 Nov 2023 03:37:46 +0000 (20:37 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 10 Nov 2023 02:58:39 +0000 (18:58 -0800)
All the logic that applies to u64 vs s64, equally applies for u32 vs s32
relationships (just taken in a smaller 32-bit numeric space). So do the
same deduction of smin32/smax32 from umin32/umax32, if we can.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20231102033759.2541186-5-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 1a5c389b951a164a152b0b80a5111766d007ab8c..b53ee72a7d72cae3e74e06d917c64ec4a5cc83d0 100644 (file)
@@ -2324,6 +2324,13 @@ static void __update_reg_bounds(struct bpf_reg_state *reg)
 /* Uses signed min/max values to inform unsigned, and vice-versa */
 static void __reg32_deduce_bounds(struct bpf_reg_state *reg)
 {
+       /* if u32 range forms a valid s32 range (due to matching sign bit),
+        * try to learn from that
+        */
+       if ((s32)reg->u32_min_value <= (s32)reg->u32_max_value) {
+               reg->s32_min_value = max_t(s32, reg->s32_min_value, reg->u32_min_value);
+               reg->s32_max_value = min_t(s32, reg->s32_max_value, reg->u32_max_value);
+       }
        /* Learn sign from signed bounds.
         * If we cannot cross the sign boundary, then signed and unsigned bounds
         * are the same, so combine.  This works even in the negative case, e.g.