Skip to content

Commit

Permalink
selftests/bpf: add selftest validating callback result is enforced
Browse files Browse the repository at this point in the history
BPF verifier expects callback subprogs to return values from specified
range (typically [0, 1]). This requires that r0 at exit is both precise
(because we rely on specific value range) and is marked as read
(otherwise state comparison will ignore such register as unimportant).

Add a simple test that validates that all these conditions are enforced.

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/20231202175705.885270-6-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Andrii Nakryiko authored and Alexei Starovoitov committed Dec 2, 2023
1 parent 8fa4ecd commit 60a6b2c
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,56 @@ __naked int global_subprog_result_precise(void)
);
}

__naked __noinline __used
static unsigned long loop_callback_bad()
{
/* bpf_loop() callback that can return values outside of [0, 1] range */
asm volatile (
"call %[bpf_get_prandom_u32];"
"if r0 s> 1000 goto 1f;"
"r0 = 0;"
"1:"
"goto +0;" /* checkpoint */
/* bpf_loop() expects [0, 1] values, so branch above skipping
* r0 = 0; should lead to a failure, but if exit instruction
* doesn't enforce r0's precision, this callback will be
* successfully verified
*/
"exit;"
:
: __imm(bpf_get_prandom_u32)
: __clobber_common
);
}

SEC("?raw_tp")
__failure __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)
/* check that fallthrough code path marks r0 as precise */
__msg("mark_precise: frame1: regs=r0 stack= before 11: (b7) r0 = 0")
/* check that we have branch code path doing its own validation */
__msg("from 10 to 12: frame1: R0=scalar(smin=umin=1001")
/* 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 value (0x0; 0x7fffffffffffffff) should have been in (0x0; 0x1)")
__naked int callback_precise_return_fail(void)
{
asm volatile (
"r1 = 1;" /* nr_loops */
"r2 = %[loop_callback_bad];" /* callback_fn */
"r3 = 0;" /* callback_ctx */
"r4 = 0;" /* flags */
"call %[bpf_loop];"

"r0 = 0;"
"exit;"
:
: __imm_ptr(loop_callback_bad),
__imm(bpf_loop)
: __clobber_common
);
}

SEC("?raw_tp")
__success __log_level(2)
/* First simulated path does not include callback body,
Expand Down

0 comments on commit 60a6b2c

Please sign in to comment.