diff mbox series

[v2,bpf-next,05/10] bpf: enforce precise retval range on program exit

Message ID 20231129003620.1049610-6-andrii@kernel.org (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series BPF verifier retval logic fixes | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for bpf-next
netdev/apply fail Patch does not apply to bpf-next
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-3 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-15 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-16 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-llvm-16 / build / build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-llvm-16 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-llvm-16 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-llvm-16 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-16 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-16 / veristat

Commit Message

Andrii Nakryiko Nov. 29, 2023, 12:36 a.m. UTC
Similarly to subprog/callback logic, enforce return value of BPF program
using more precise umin/umax range.

We need to adjust a bunch of tests due to a changed format of an error
message.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 kernel/bpf/verifier.c                         | 63 +++++++++----------
 .../selftests/bpf/progs/exceptions_assert.c   |  2 +-
 .../selftests/bpf/progs/exceptions_fail.c     |  2 +-
 .../selftests/bpf/progs/test_global_func15.c  |  2 +-
 .../selftests/bpf/progs/timer_failure.c       |  2 +-
 .../selftests/bpf/progs/user_ringbuf_fail.c   |  2 +-
 .../bpf/progs/verifier_cgroup_inv_retcode.c   |  8 +--
 .../bpf/progs/verifier_netfilter_retcode.c    |  2 +-
 .../bpf/progs/verifier_subprog_precision.c    |  2 +-
 9 files changed, 40 insertions(+), 45 deletions(-)

Comments

Shung-Hsi Yu Nov. 29, 2023, 11:23 a.m. UTC | #1
On Tue, Nov 28, 2023 at 04:36:15PM -0800, Andrii Nakryiko wrote:
> Similarly to subprog/callback logic, enforce return value of BPF program
> using more precise umin/umax range.
> 
> We need to adjust a bunch of tests due to a changed format of an error
> message.
> 
> Acked-by: Eduard Zingerman <eddyz87@gmail.com>
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

...

Q: should the missing register name and values be added?

I know relatively little about selftest, but scrolling through it looks
as though the expect verifier message is incomplete. (Admittedly lots of
them are like this even before this patch, and this patch improves the
situation already)

e.g.

> --- a/tools/testing/selftests/bpf/progs/test_global_func15.c
> +++ b/tools/testing/selftests/bpf/progs/test_global_func15.c
> @@ -13,7 +13,7 @@ __noinline int foo(unsigned int *v)
>  }
>  
>  SEC("cgroup_skb/ingress")
> -__failure __msg("At program exit the register R0 has value")
> +__failure __msg("At program exit the register R0 has ")
>  int global_func15(struct __sk_buff *skb)
>  {
>  	unsigned int v = 1;

looks like it is missing umin/umax=1

...

> diff --git a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> index d6c4a7f3f790..4655f01b24aa 100644
> --- a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> +++ b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> @@ -7,7 +7,7 @@
>  
>  SEC("cgroup/sock")
>  __description("bpf_exit with invalid return code. test1")
> -__failure __msg("R0 has value (0x0; 0xffffffff)")
> +__failure __msg("umax=4294967295 should have been in [0, 1]")
>  __naked void with_invalid_return_code_test1(void)
>  {
>  	asm volatile ("					\

looks like it is missing mention of R0, etc.
Andrii Nakryiko Nov. 29, 2023, 4:23 p.m. UTC | #2
On Wed, Nov 29, 2023 at 3:24 AM Shung-Hsi Yu <shung-hsi.yu@suse.com> wrote:
>
> On Tue, Nov 28, 2023 at 04:36:15PM -0800, Andrii Nakryiko wrote:
> > Similarly to subprog/callback logic, enforce return value of BPF program
> > using more precise umin/umax range.
> >
> > We need to adjust a bunch of tests due to a changed format of an error
> > message.
> >
> > Acked-by: Eduard Zingerman <eddyz87@gmail.com>
> > Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
>
> ...
>
> Q: should the missing register name and values be added?
>

Probably not, it makes future refactoring a bit less painful. If the
important part is to check that there *was* a message about invalid
return result, rather *what exact format* of that message was, then
matching for a substring is enough and makes the test a bit more
robust to future slight refactorings.

> I know relatively little about selftest, but scrolling through it looks
> as though the expect verifier message is incomplete. (Admittedly lots of
> them are like this even before this patch, and this patch improves the
> situation already)
>

Often times it's actually a mistake to expect exact format, it makes
for painful refactoring and improvements. I feel it every time I touch
verifier log formatting logic :( So I don't want to add to that pain.


> e.g.
>
> > --- a/tools/testing/selftests/bpf/progs/test_global_func15.c
> > +++ b/tools/testing/selftests/bpf/progs/test_global_func15.c
> > @@ -13,7 +13,7 @@ __noinline int foo(unsigned int *v)
> >  }
> >
> >  SEC("cgroup_skb/ingress")
> > -__failure __msg("At program exit the register R0 has value")
> > +__failure __msg("At program exit the register R0 has ")
> >  int global_func15(struct __sk_buff *skb)
> >  {
> >       unsigned int v = 1;
>
> looks like it is missing umin/umax=1
>
> ...
>
> > diff --git a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> > index d6c4a7f3f790..4655f01b24aa 100644
> > --- a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> > +++ b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> > @@ -7,7 +7,7 @@
> >
> >  SEC("cgroup/sock")
> >  __description("bpf_exit with invalid return code. test1")
> > -__failure __msg("R0 has value (0x0; 0xffffffff)")
> > +__failure __msg("umax=4294967295 should have been in [0, 1]")
> >  __naked void with_invalid_return_code_test1(void)
> >  {
> >       asm volatile ("                                 \
>
> looks like it is missing mention of R0, etc.
Shung-Hsi Yu Nov. 30, 2023, 5:29 a.m. UTC | #3
On Wed, Nov 29, 2023 at 08:23:41AM -0800, Andrii Nakryiko wrote:
> On Wed, Nov 29, 2023 at 3:24 AM Shung-Hsi Yu <shung-hsi.yu@suse.com> wrote:
> >
> > On Tue, Nov 28, 2023 at 04:36:15PM -0800, Andrii Nakryiko wrote:
> > > Similarly to subprog/callback logic, enforce return value of BPF program
> > > using more precise umin/umax range.
> > >
> > > We need to adjust a bunch of tests due to a changed format of an error
> > > message.
> > >
> > > Acked-by: Eduard Zingerman <eddyz87@gmail.com>
> > > Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> >
> > ...
> >
> > Q: should the missing register name and values be added?
> 
> Probably not, it makes future refactoring a bit less painful. If the
> important part is to check that there *was* a message about invalid
> return result, rather *what exact format* of that message was, then
> matching for a substring is enough and makes the test a bit more
> robust to future slight refactorings.
> 
> > I know relatively little about selftest, but scrolling through it looks
> > as though the expect verifier message is incomplete. (Admittedly lots of
> > them are like this even before this patch, and this patch improves the
> > situation already)
> 
> Often times it's actually a mistake to expect exact format, it makes
> for painful refactoring and improvements. I feel it every time I touch
> verifier log formatting logic :( So I don't want to add to that pain.

Understood. Thanks for going through the reasoning!

> > e.g.
> >
> > > --- a/tools/testing/selftests/bpf/progs/test_global_func15.c
> > > +++ b/tools/testing/selftests/bpf/progs/test_global_func15.c
> > > @@ -13,7 +13,7 @@ __noinline int foo(unsigned int *v)
> > >  }
> > >
> > >  SEC("cgroup_skb/ingress")
> > > -__failure __msg("At program exit the register R0 has value")
> > > +__failure __msg("At program exit the register R0 has ")
> > >  int global_func15(struct __sk_buff *skb)
> > >  {
> > >       unsigned int v = 1;
> >
> > looks like it is missing umin/umax=1
> >
> > ...
> >
> > > diff --git a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> > > index d6c4a7f3f790..4655f01b24aa 100644
> > > --- a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> > > +++ b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
> > > @@ -7,7 +7,7 @@
> > >
> > >  SEC("cgroup/sock")
> > >  __description("bpf_exit with invalid return code. test1")
> > > -__failure __msg("R0 has value (0x0; 0xffffffff)")
> > > +__failure __msg("umax=4294967295 should have been in [0, 1]")
> > >  __naked void with_invalid_return_code_test1(void)
> > >  {
> > >       asm volatile ("                                 \
> >
> > looks like it is missing mention of R0, etc.
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 845f46f40e6b..0df8e53f2ecb 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -362,20 +362,23 @@  __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...)
 
 static void verbose_invalid_scalar(struct bpf_verifier_env *env,
 				   struct bpf_reg_state *reg,
-				   struct tnum *range, const char *ctx,
+				   struct bpf_retval_range range, const char *ctx,
 				   const char *reg_name)
 {
-	char tn_buf[48];
+	bool unknown = true;
 
-	verbose(env, "At %s the register %s ", ctx, reg_name);
-	if (!tnum_is_unknown(reg->var_off)) {
-		tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-		verbose(env, "has value %s", tn_buf);
-	} else {
-		verbose(env, "has unknown scalar value");
+	verbose(env, "At %s the register %s has", ctx, reg_name);
+	if (reg->umin_value > 0) {
+		verbose(env, " umin=%llu", reg->umin_value);
+		unknown = false;
 	}
-	tnum_strn(tn_buf, sizeof(tn_buf), *range);
-	verbose(env, " should have been in %s\n", tn_buf);
+	if (reg->umax_value < U64_MAX) {
+		verbose(env, " umax=%llu", reg->umax_value);
+		unknown = false;
+	}
+	if (unknown)
+		verbose(env, " unknown scalar value");
+	verbose(env, " should have been in [%u, %u]\n", range.minval, range.maxval);
 }
 
 static bool type_may_be_null(u32 type)
@@ -9570,14 +9573,6 @@  static bool retval_range_within(struct bpf_retval_range range, const struct bpf_
 	return range.minval <= reg->umin_value && reg->umax_value <= range.maxval;
 }
 
-static struct tnum retval_range_as_tnum(struct bpf_retval_range range)
-{
-	if (range.minval == range.maxval)
-		return tnum_const(range.minval);
-	else
-		return tnum_range(range.minval, range.maxval);
-}
-
 static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
 {
 	struct bpf_verifier_state *state = env->cur_state, *prev_st;
@@ -9614,9 +9609,8 @@  static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
 
 		/* enforce R0 return value range */
 		if (!retval_range_within(callee->callback_ret_range, r0)) {
-			struct tnum range = retval_range_as_tnum(callee->callback_ret_range);
-
-			verbose_invalid_scalar(env, r0, &range, "callback return", "R0");
+			verbose_invalid_scalar(env, r0, callee->callback_ret_range,
+					       "callback return", "R0");
 			return -EINVAL;
 		}
 		if (!calls_callback(env, callee->callsite)) {
@@ -15002,7 +14996,8 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 	struct tnum enforce_attach_type_range = tnum_unknown;
 	const struct bpf_prog *prog = env->prog;
 	struct bpf_reg_state *reg;
-	struct tnum range = tnum_range(0, 1), const_0 = tnum_const(0);
+	struct bpf_retval_range range = retval_range(0, 1);
+	struct bpf_retval_range const_0 = retval_range(0, 0);
 	enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
 	int err;
 	struct bpf_func_state *frame = env->cur_state->frame[0];
@@ -15050,8 +15045,8 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 			return -EINVAL;
 		}
 
-		if (!tnum_in(const_0, reg->var_off)) {
-			verbose_invalid_scalar(env, reg, &const_0, "async callback", reg_name);
+		if (!retval_range_within(const_0, reg)) {
+			verbose_invalid_scalar(env, reg, const_0, "async callback", reg_name);
 			return -EINVAL;
 		}
 		return 0;
@@ -15077,14 +15072,14 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 		    env->prog->expected_attach_type == BPF_CGROUP_INET4_GETSOCKNAME ||
 		    env->prog->expected_attach_type == BPF_CGROUP_INET6_GETSOCKNAME ||
 		    env->prog->expected_attach_type == BPF_CGROUP_UNIX_GETSOCKNAME)
-			range = tnum_range(1, 1);
+			range = retval_range(1, 1);
 		if (env->prog->expected_attach_type == BPF_CGROUP_INET4_BIND ||
 		    env->prog->expected_attach_type == BPF_CGROUP_INET6_BIND)
-			range = tnum_range(0, 3);
+			range = retval_range(0, 3);
 		break;
 	case BPF_PROG_TYPE_CGROUP_SKB:
 		if (env->prog->expected_attach_type == BPF_CGROUP_INET_EGRESS) {
-			range = tnum_range(0, 3);
+			range = retval_range(0, 3);
 			enforce_attach_type_range = tnum_range(2, 3);
 		}
 		break;
@@ -15097,13 +15092,13 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
 		if (!env->prog->aux->attach_btf_id)
 			return 0;
-		range = tnum_const(0);
+		range = retval_range(0, 0);
 		break;
 	case BPF_PROG_TYPE_TRACING:
 		switch (env->prog->expected_attach_type) {
 		case BPF_TRACE_FENTRY:
 		case BPF_TRACE_FEXIT:
-			range = tnum_const(0);
+			range = retval_range(0, 0);
 			break;
 		case BPF_TRACE_RAW_TP:
 		case BPF_MODIFY_RETURN:
@@ -15115,7 +15110,7 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 		}
 		break;
 	case BPF_PROG_TYPE_SK_LOOKUP:
-		range = tnum_range(SK_DROP, SK_PASS);
+		range = retval_range(SK_DROP, SK_PASS);
 		break;
 
 	case BPF_PROG_TYPE_LSM:
@@ -15129,12 +15124,12 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 			/* Make sure programs that attach to void
 			 * hooks don't try to modify return value.
 			 */
-			range = tnum_range(1, 1);
+			range = retval_range(1, 1);
 		}
 		break;
 
 	case BPF_PROG_TYPE_NETFILTER:
-		range = tnum_range(NF_DROP, NF_ACCEPT);
+		range = retval_range(NF_DROP, NF_ACCEPT);
 		break;
 	case BPF_PROG_TYPE_EXT:
 		/* freplace program can return anything as its return value
@@ -15150,8 +15145,8 @@  static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 		return -EINVAL;
 	}
 
-	if (!tnum_in(range, reg->var_off)) {
-		verbose_invalid_scalar(env, reg, &range, "program exit", reg_name);
+	if (!retval_range_within(range, reg)) {
+		verbose_invalid_scalar(env, reg, range, "program exit", reg_name);
 		if (prog->expected_attach_type == BPF_LSM_CGROUP &&
 		    prog_type == BPF_PROG_TYPE_LSM &&
 		    !prog->aux->attach_func_proto->type)
diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c
index 575e7dd719c4..3d85d5695aba 100644
--- a/tools/testing/selftests/bpf/progs/exceptions_assert.c
+++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c
@@ -125,7 +125,7 @@  int check_assert_generic(struct __sk_buff *ctx)
 }
 
 SEC("?fentry/bpf_check")
-__failure __msg("At program exit the register R1 has value (0x40; 0x0)")
+__failure __msg("At program exit the register R1 has umin=64 umax=64")
 int check_assert_with_return(void *ctx)
 {
 	bpf_assert_with(!ctx, 64);
diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c
index 81ead7512ba2..114119cf9099 100644
--- a/tools/testing/selftests/bpf/progs/exceptions_fail.c
+++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c
@@ -308,7 +308,7 @@  int reject_set_exception_cb_bad_ret1(void *ctx)
 }
 
 SEC("?fentry/bpf_check")
-__failure __msg("At program exit the register R1 has value (0x40; 0x0) should")
+__failure __msg("At program exit the register R1 has umin=64 umax=64 should")
 int reject_set_exception_cb_bad_ret2(void *ctx)
 {
 	bpf_throw(64);
diff --git a/tools/testing/selftests/bpf/progs/test_global_func15.c b/tools/testing/selftests/bpf/progs/test_global_func15.c
index b512d6a6c75e..f80207480e8a 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func15.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func15.c
@@ -13,7 +13,7 @@  __noinline int foo(unsigned int *v)
 }
 
 SEC("cgroup_skb/ingress")
-__failure __msg("At program exit the register R0 has value")
+__failure __msg("At program exit the register R0 has ")
 int global_func15(struct __sk_buff *skb)
 {
 	unsigned int v = 1;
diff --git a/tools/testing/selftests/bpf/progs/timer_failure.c b/tools/testing/selftests/bpf/progs/timer_failure.c
index 226d33b5a05c..9000da1e2120 100644
--- a/tools/testing/selftests/bpf/progs/timer_failure.c
+++ b/tools/testing/selftests/bpf/progs/timer_failure.c
@@ -30,7 +30,7 @@  static int timer_cb_ret1(void *map, int *key, struct bpf_timer *timer)
 }
 
 SEC("fentry/bpf_fentry_test1")
-__failure __msg("should have been in (0x0; 0x0)")
+__failure __msg("should have been in [0, 0]")
 int BPF_PROG2(test_ret_1, int, a)
 {
 	int key = 0;
diff --git a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c
index 03ee946c6bf7..11ab25c42c36 100644
--- a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c
+++ b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c
@@ -184,7 +184,7 @@  invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context)
  * not be able to write to that pointer.
  */
 SEC("?raw_tp")
-__failure __msg("At callback return the register R0 has value")
+__failure __msg("At callback return the register R0 has ")
 int user_ringbuf_callback_invalid_return(void *ctx)
 {
 	bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0);
diff --git a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
index d6c4a7f3f790..4655f01b24aa 100644
--- a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
+++ b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c
@@ -7,7 +7,7 @@ 
 
 SEC("cgroup/sock")
 __description("bpf_exit with invalid return code. test1")
-__failure __msg("R0 has value (0x0; 0xffffffff)")
+__failure __msg("umax=4294967295 should have been in [0, 1]")
 __naked void with_invalid_return_code_test1(void)
 {
 	asm volatile ("					\
@@ -30,7 +30,7 @@  __naked void with_invalid_return_code_test2(void)
 
 SEC("cgroup/sock")
 __description("bpf_exit with invalid return code. test3")
-__failure __msg("R0 has value (0x0; 0x3)")
+__failure __msg("umax=3 should have been in [0, 1]")
 __naked void with_invalid_return_code_test3(void)
 {
 	asm volatile ("					\
@@ -53,7 +53,7 @@  __naked void with_invalid_return_code_test4(void)
 
 SEC("cgroup/sock")
 __description("bpf_exit with invalid return code. test5")
-__failure __msg("R0 has value (0x2; 0x0)")
+__failure __msg("umin=2 umax=2 should have been in [0, 1]")
 __naked void with_invalid_return_code_test5(void)
 {
 	asm volatile ("					\
@@ -75,7 +75,7 @@  __naked void with_invalid_return_code_test6(void)
 
 SEC("cgroup/sock")
 __description("bpf_exit with invalid return code. test7")
-__failure __msg("R0 has unknown scalar value")
+__failure __msg("R0 has unknown scalar value should have been in [0, 1]")
 __naked void with_invalid_return_code_test7(void)
 {
 	asm volatile ("					\
diff --git a/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c b/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c
index 353ae6da00e1..d8da9b749128 100644
--- a/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c
+++ b/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c
@@ -39,7 +39,7 @@  __naked void with_valid_return_code_test3(void)
 
 SEC("netfilter")
 __description("bpf_exit with invalid return code. test4")
-__failure __msg("R0 has value (0x2; 0x0)")
+__failure __msg("R0 has umin=2 umax=2 should have been in [0, 1]")
 __naked void with_invalid_return_code_test4(void)
 {
 	asm volatile ("					\
diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
index f0aa44bd3eb4..2e69d9c108fe 100644
--- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
+++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
@@ -148,7 +148,7 @@  __msg("mark_precise: frame1: regs=r0 stack= before 11: (b7) r0 = 0")
 __msg("from 10 to 12: frame1: R0=scalar(umin=1001) R10=fp0 cb")
 /* check that branch code path marks r0 as precise, before failing */
 __msg("mark_precise: frame1: regs=r0 stack= before 9: (85) call bpf_get_prandom_u32#7")
-__msg("At callback return the register R0 has unknown scalar value should have been in (0x0; 0x1)")
+__msg("At callback return the register R0 has umin=1001 should have been in [0, 1]")
 __naked int callback_precise_return_fail(void)
 {
 	asm volatile (