--- /dev/null
+From b02709587ea3d699a608568ee8157d8db4fd8cae Mon Sep 17 00:00:00 2001
+From: Alexei Starovoitov <ast@kernel.org>
+Date: Tue, 8 Dec 2020 19:01:51 +0100
+Subject: bpf: Fix propagation of 32-bit signed bounds from 64-bit bounds.
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+commit b02709587ea3d699a608568ee8157d8db4fd8cae upstream.
+
+The 64-bit signed bounds should not affect 32-bit signed bounds unless the
+verifier knows that upper 32-bits are either all 1s or all 0s. For example the
+register with smin_value==1 doesn't mean that s32_min_value is also equal to 1,
+since smax_value could be larger than 32-bit subregister can hold.
+The verifier refines the smax/s32_max return value from certain helpers in
+do_refine_retval_range(). Teach the verifier to recognize that smin/s32_min
+value is also bounded. When both smin and smax bounds fit into 32-bit
+subregister the verifier can propagate those bounds.
+
+Fixes: 3f50f132d840 ("bpf: Verifier, do explicit ALU32 bounds tracking")
+Reported-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
+Acked-by: John Fastabend <john.fastabend@gmail.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/bpf/verifier.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1273,9 +1273,7 @@ static void __reg_combine_32_into_64(str
+
+ static bool __reg64_bound_s32(s64 a)
+ {
+- if (a > S32_MIN && a < S32_MAX)
+- return true;
+- return false;
++ return a > S32_MIN && a < S32_MAX;
+ }
+
+ static bool __reg64_bound_u32(u64 a)
+@@ -1289,10 +1287,10 @@ static void __reg_combine_64_into_32(str
+ {
+ __mark_reg32_unbounded(reg);
+
+- if (__reg64_bound_s32(reg->smin_value))
++ if (__reg64_bound_s32(reg->smin_value) && __reg64_bound_s32(reg->smax_value)) {
+ reg->s32_min_value = (s32)reg->smin_value;
+- if (__reg64_bound_s32(reg->smax_value))
+ reg->s32_max_value = (s32)reg->smax_value;
++ }
+ if (__reg64_bound_u32(reg->umin_value))
+ reg->u32_min_value = (u32)reg->umin_value;
+ if (__reg64_bound_u32(reg->umax_value))
+@@ -4676,6 +4674,8 @@ static void do_refine_retval_range(struc
+
+ ret_reg->smax_value = meta->msize_max_value;
+ ret_reg->s32_max_value = meta->msize_max_value;
++ ret_reg->smin_value = -MAX_ERRNO;
++ ret_reg->s32_min_value = -MAX_ERRNO;
+ __reg_deduce_bounds(ret_reg);
+ __reg_bound_offset(ret_reg);
+ __update_reg_bounds(ret_reg);