Skip to content

Commit a41b382

Browse files
eddyz87borkmann
authored andcommitted
selftests/bpf: Verify that sync_linked_regs preserves subreg_def
This test was added because of a bug in verifier.c:sync_linked_regs(), upon range propagation it destroyed subreg_def marks for registers. The test is written in a way to return an upper half of a register that is affected by range propagation and must have it's subreg_def preserved. This gives a return value of 0 and leads to undefined return value if subreg_def mark is not preserved. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20240924210844.1758441-2-eddyz87@gmail.com
1 parent e9bd9c4 commit a41b382

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

tools/testing/selftests/bpf/progs/verifier_scalar_ids.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,4 +760,71 @@ __naked void two_old_ids_one_cur_id(void)
760760
: __clobber_all);
761761
}
762762

763+
SEC("socket")
764+
/* Note the flag, see verifier.c:opt_subreg_zext_lo32_rnd_hi32() */
765+
__flag(BPF_F_TEST_RND_HI32)
766+
__success
767+
/* This test was added because of a bug in verifier.c:sync_linked_regs(),
768+
* upon range propagation it destroyed subreg_def marks for registers.
769+
* The subreg_def mark is used to decide whether zero extension instructions
770+
* are needed when register is read. When BPF_F_TEST_RND_HI32 is set it
771+
* also causes generation of statements to randomize upper halves of
772+
* read registers.
773+
*
774+
* The test is written in a way to return an upper half of a register
775+
* that is affected by range propagation and must have it's subreg_def
776+
* preserved. This gives a return value of 0 and leads to undefined
777+
* return value if subreg_def mark is not preserved.
778+
*/
779+
__retval(0)
780+
/* Check that verifier believes r1/r0 are zero at exit */
781+
__log_level(2)
782+
__msg("4: (77) r1 >>= 32 ; R1_w=0")
783+
__msg("5: (bf) r0 = r1 ; R0_w=0 R1_w=0")
784+
__msg("6: (95) exit")
785+
__msg("from 3 to 4")
786+
__msg("4: (77) r1 >>= 32 ; R1_w=0")
787+
__msg("5: (bf) r0 = r1 ; R0_w=0 R1_w=0")
788+
__msg("6: (95) exit")
789+
/* Verify that statements to randomize upper half of r1 had not been
790+
* generated.
791+
*/
792+
__xlated("call unknown")
793+
__xlated("r0 &= 2147483647")
794+
__xlated("w1 = w0")
795+
/* This is how disasm.c prints BPF_ZEXT_REG at the moment, x86 and arm
796+
* are the only CI archs that do not need zero extension for subregs.
797+
*/
798+
#if !defined(__TARGET_ARCH_x86) && !defined(__TARGET_ARCH_arm64)
799+
__xlated("w1 = w1")
800+
#endif
801+
__xlated("if w0 < 0xa goto pc+0")
802+
__xlated("r1 >>= 32")
803+
__xlated("r0 = r1")
804+
__xlated("exit")
805+
__naked void linked_regs_and_subreg_def(void)
806+
{
807+
asm volatile (
808+
"call %[bpf_ktime_get_ns];"
809+
/* make sure r0 is in 32-bit range, otherwise w1 = w0 won't
810+
* assign same IDs to registers.
811+
*/
812+
"r0 &= 0x7fffffff;"
813+
/* link w1 and w0 via ID */
814+
"w1 = w0;"
815+
/* 'if' statement propagates range info from w0 to w1,
816+
* but should not affect w1->subreg_def property.
817+
*/
818+
"if w0 < 10 goto +0;"
819+
/* r1 is read here, on archs that require subreg zero
820+
* extension this would cause zext patch generation.
821+
*/
822+
"r1 >>= 32;"
823+
"r0 = r1;"
824+
"exit;"
825+
:
826+
: __imm(bpf_ktime_get_ns)
827+
: __clobber_all);
828+
}
829+
763830
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)