mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
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
This commit is contained in:
parent
e9bd9c498c
commit
a41b3828ec
@ -760,4 +760,71 @@ __naked void two_old_ids_one_cur_id(void)
|
||||
: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
/* Note the flag, see verifier.c:opt_subreg_zext_lo32_rnd_hi32() */
|
||||
__flag(BPF_F_TEST_RND_HI32)
|
||||
__success
|
||||
/* 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 subreg_def mark is used to decide whether zero extension instructions
|
||||
* are needed when register is read. When BPF_F_TEST_RND_HI32 is set it
|
||||
* also causes generation of statements to randomize upper halves of
|
||||
* read 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.
|
||||
*/
|
||||
__retval(0)
|
||||
/* Check that verifier believes r1/r0 are zero at exit */
|
||||
__log_level(2)
|
||||
__msg("4: (77) r1 >>= 32 ; R1_w=0")
|
||||
__msg("5: (bf) r0 = r1 ; R0_w=0 R1_w=0")
|
||||
__msg("6: (95) exit")
|
||||
__msg("from 3 to 4")
|
||||
__msg("4: (77) r1 >>= 32 ; R1_w=0")
|
||||
__msg("5: (bf) r0 = r1 ; R0_w=0 R1_w=0")
|
||||
__msg("6: (95) exit")
|
||||
/* Verify that statements to randomize upper half of r1 had not been
|
||||
* generated.
|
||||
*/
|
||||
__xlated("call unknown")
|
||||
__xlated("r0 &= 2147483647")
|
||||
__xlated("w1 = w0")
|
||||
/* This is how disasm.c prints BPF_ZEXT_REG at the moment, x86 and arm
|
||||
* are the only CI archs that do not need zero extension for subregs.
|
||||
*/
|
||||
#if !defined(__TARGET_ARCH_x86) && !defined(__TARGET_ARCH_arm64)
|
||||
__xlated("w1 = w1")
|
||||
#endif
|
||||
__xlated("if w0 < 0xa goto pc+0")
|
||||
__xlated("r1 >>= 32")
|
||||
__xlated("r0 = r1")
|
||||
__xlated("exit")
|
||||
__naked void linked_regs_and_subreg_def(void)
|
||||
{
|
||||
asm volatile (
|
||||
"call %[bpf_ktime_get_ns];"
|
||||
/* make sure r0 is in 32-bit range, otherwise w1 = w0 won't
|
||||
* assign same IDs to registers.
|
||||
*/
|
||||
"r0 &= 0x7fffffff;"
|
||||
/* link w1 and w0 via ID */
|
||||
"w1 = w0;"
|
||||
/* 'if' statement propagates range info from w0 to w1,
|
||||
* but should not affect w1->subreg_def property.
|
||||
*/
|
||||
"if w0 < 10 goto +0;"
|
||||
/* r1 is read here, on archs that require subreg zero
|
||||
* extension this would cause zext patch generation.
|
||||
*/
|
||||
"r1 >>= 32;"
|
||||
"r0 = r1;"
|
||||
"exit;"
|
||||
:
|
||||
: __imm(bpf_ktime_get_ns)
|
||||
: __clobber_all);
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
Loading…
Reference in New Issue
Block a user