The liveness masks of a function instance are as wide as the deepest half-slot the instance was seen to access. When the same instance is analyzed again through another call site, the new pass may have settled on a different width, and merge_instances() has to widen the original before combining the two. Add a test where the first pass of a callee reads through a pointer 264 bytes into the main frame and the second one through a pointer of unknown offset, a whole-frame read at the maximum width, and check that the merged result keeps the whole-frame read. Signed-off-by: Kumar Kartikeya Dwivedi --- .../selftests/bpf/progs/verifier_live_stack.c | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_live_stack.c b/tools/testing/selftests/bpf/progs/verifier_live_stack.c index f8758eb62dac..a94365decd5f 100644 --- a/tools/testing/selftests/bpf/progs/verifier_live_stack.c +++ b/tools/testing/selftests/bpf/progs/verifier_live_stack.c @@ -2861,3 +2861,52 @@ __naked void narrow_store_defines_nothing(void) "exit;" ::: __clobber_all); } + +/* + * The same callee instance is analyzed twice: the call sites are visited in + * postorder, so the second one goes first with a precise pointer 264 bytes + * into the main frame, and the first one then passes a pointer of unknown + * offset, which reads the whole frame. The masks of the two passes differ in + * width; merging the second into the first must keep the whole-frame read. + */ +SEC("socket") +__log_level(2) +__msg("stack use/def subprog#{{[0-9]+}} merge_read_all_callee (d2,cs{{[0-9]+}}):") +__msg("(79) r0 = *(u64 *)(r1 +0){{.*}}; use: fp0-8..-512") +__naked void merge_keeps_whole_frame_read(void) +{ + asm volatile ( + "r1 = 0;" + "*(u64 *)(r10 - 8) = r1;" + "*(u64 *)(r10 - 16) = r1;" + "*(u64 *)(r10 - 264) = r1;" + "call %[bpf_get_prandom_u32];" + "r0 &= 8;" + "r1 = r10;" + "r1 += -16;" + "r1 += r0;" + "call merge_read_all_mid;" + "r1 = r10;" + "r1 += -264;" + "call merge_read_all_mid;" + "r0 = 0;" + "exit;" + :: __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +static __used __naked void merge_read_all_mid(void) +{ + asm volatile ( + "call merge_read_all_callee;" + "exit;" + ::: __clobber_all); +} + +static __used __naked void merge_read_all_callee(void) +{ + asm volatile ( + "r0 = *(u64 *)(r1 + 0);" + "exit;" + ::: __clobber_all); +} -- 2.53.0