| From e572ff80f05c33cd0cb4860f864f5c9c044280b6 Mon Sep 17 00:00:00 2001 |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| Date: Wed, 15 Dec 2021 22:28:48 +0000 |
| Subject: bpf: Make 32->64 bounds propagation slightly more robust |
| |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| |
| commit e572ff80f05c33cd0cb4860f864f5c9c044280b6 upstream. |
| |
| Make the bounds propagation in __reg_assign_32_into_64() slightly more |
| robust and readable by aligning it similarly as we did back in the |
| __reg_combine_64_into_32() counterpart. Meaning, only propagate or |
| pessimize them as a smin/smax pair. |
| |
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> |
| Reviewed-by: John Fastabend <john.fastabend@gmail.com> |
| Acked-by: Alexei Starovoitov <ast@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| kernel/bpf/verifier.c | 24 +++++++++++++++--------- |
| 1 file changed, 15 insertions(+), 9 deletions(-) |
| |
| --- a/kernel/bpf/verifier.c |
| +++ b/kernel/bpf/verifier.c |
| @@ -1249,22 +1249,28 @@ static void __reg_bound_offset(struct bp |
| reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off); |
| } |
| |
| +static bool __reg32_bound_s64(s32 a) |
| +{ |
| + return a >= 0 && a <= S32_MAX; |
| +} |
| + |
| static void __reg_assign_32_into_64(struct bpf_reg_state *reg) |
| { |
| reg->umin_value = reg->u32_min_value; |
| reg->umax_value = reg->u32_max_value; |
| - /* Attempt to pull 32-bit signed bounds into 64-bit bounds |
| - * but must be positive otherwise set to worse case bounds |
| - * and refine later from tnum. |
| + |
| + /* Attempt to pull 32-bit signed bounds into 64-bit bounds but must |
| + * be positive otherwise set to worse case bounds and refine later |
| + * from tnum. |
| */ |
| - if (reg->s32_min_value >= 0 && reg->s32_max_value >= 0) |
| - reg->smax_value = reg->s32_max_value; |
| - else |
| - reg->smax_value = U32_MAX; |
| - if (reg->s32_min_value >= 0) |
| + if (__reg32_bound_s64(reg->s32_min_value) && |
| + __reg32_bound_s64(reg->s32_max_value)) { |
| reg->smin_value = reg->s32_min_value; |
| - else |
| + reg->smax_value = reg->s32_max_value; |
| + } else { |
| reg->smin_value = 0; |
| + reg->smax_value = U32_MAX; |
| + } |
| } |
| |
| static void __reg_combine_32_into_64(struct bpf_reg_state *reg) |