Commit 14a627fe authored by Yonghong Song's avatar Yonghong Song Committed by Alexei Starovoitov
Browse files

selftests/bpf: Add some tests related to 'may_goto 0' insns



Add both asm-based and C-based tests which have 'may_goto 0' insns.

For the following code in C-based test,
   int i, tmp[3];
   for (i = 0; i < 3 && can_loop; i++)
       tmp[i] = 0;

The clang compiler (clang 19 and 20) generates
   may_goto 2
   may_goto 1
   may_goto 0
   r1 = 0
   r2 = 0
   r3 = 0

The above asm codes are due to llvm pass SROAPass. This ensures the
successful verification since tmp[0-2] are initialized.  Otherwise,
the code without SROAPass like
   may_goto 5
   r1 = 0
   may_goto 3
   r2 = 0
   may_goto 1
   r3 = 0
will have verification failure.

Although from the source code C-based test should have verification
failure, clang compiler optimization generates code with successful
verification. If gcc generates different asm codes than clang, the
following code can be used for gcc:
   int i, tmp[3];
   for (i = 0; i < 3; i++)
       tmp[i] = 0;

Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Signed-off-by: default avatarYonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20250118192034.2124952-1-yonghong.song@linux.dev


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 0c35ca25
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@
#include "verifier_map_ptr_mixing.skel.h"
#include "verifier_map_ret_val.skel.h"
#include "verifier_masking.skel.h"
#include "verifier_may_goto_1.skel.h"
#include "verifier_may_goto_2.skel.h"
#include "verifier_meta_access.skel.h"
#include "verifier_movsx.skel.h"
#include "verifier_mtu.skel.h"
@@ -182,6 +184,8 @@ void test_verifier_map_ptr(void) { RUN(verifier_map_ptr); }
void test_verifier_map_ptr_mixing(void)       { RUN(verifier_map_ptr_mixing); }
void test_verifier_map_ret_val(void)          { RUN(verifier_map_ret_val); }
void test_verifier_masking(void)              { RUN(verifier_masking); }
void test_verifier_may_goto_1(void)           { RUN(verifier_may_goto_1); }
void test_verifier_may_goto_2(void)           { RUN(verifier_may_goto_2); }
void test_verifier_meta_access(void)          { RUN(verifier_meta_access); }
void test_verifier_movsx(void)                 { RUN(verifier_movsx); }
void test_verifier_netfilter_ctx(void)        { RUN(verifier_netfilter_ctx); }
+97 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "../../../include/linux/filter.h"
#include "bpf_misc.h"

SEC("raw_tp")
__description("may_goto 0")
__arch_x86_64
__xlated("0: r0 = 1")
__xlated("1: exit")
__success
__naked void may_goto_simple(void)
{
	asm volatile (
	".8byte %[may_goto];"
	"r0 = 1;"
	".8byte %[may_goto];"
	"exit;"
	:
	: __imm_insn(may_goto, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0 /* offset */, 0))
	: __clobber_all);
}

SEC("raw_tp")
__description("batch 2 of may_goto 0")
__arch_x86_64
__xlated("0: r0 = 1")
__xlated("1: exit")
__success
__naked void may_goto_batch_0(void)
{
	asm volatile (
	".8byte %[may_goto1];"
	".8byte %[may_goto1];"
	"r0 = 1;"
	".8byte %[may_goto1];"
	".8byte %[may_goto1];"
	"exit;"
	:
	: __imm_insn(may_goto1, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0 /* offset */, 0))
	: __clobber_all);
}

SEC("raw_tp")
__description("may_goto batch with offsets 2/1/0")
__arch_x86_64
__xlated("0: r0 = 1")
__xlated("1: exit")
__success
__naked void may_goto_batch_1(void)
{
	asm volatile (
	".8byte %[may_goto1];"
	".8byte %[may_goto2];"
	".8byte %[may_goto3];"
	"r0 = 1;"
	".8byte %[may_goto1];"
	".8byte %[may_goto2];"
	".8byte %[may_goto3];"
	"exit;"
	:
	: __imm_insn(may_goto1, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 2 /* offset */, 0)),
	  __imm_insn(may_goto2, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 1 /* offset */, 0)),
	  __imm_insn(may_goto3, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0 /* offset */, 0))
	: __clobber_all);
}

SEC("raw_tp")
__description("may_goto batch with offsets 2/0")
__arch_x86_64
__xlated("0: *(u64 *)(r10 -8) = 8388608")
__xlated("1: r11 = *(u64 *)(r10 -8)")
__xlated("2: if r11 == 0x0 goto pc+3")
__xlated("3: r11 -= 1")
__xlated("4: *(u64 *)(r10 -8) = r11")
__xlated("5: r0 = 1")
__xlated("6: r0 = 2")
__xlated("7: exit")
__success
__naked void may_goto_batch_2(void)
{
	asm volatile (
	".8byte %[may_goto1];"
	".8byte %[may_goto3];"
	"r0 = 1;"
	"r0 = 2;"
	"exit;"
	:
	: __imm_insn(may_goto1, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 2 /* offset */, 0)),
	  __imm_insn(may_goto3, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0 /* offset */, 0))
	: __clobber_all);
}

char _license[] SEC("license") = "GPL";
+28 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */

#include "bpf_misc.h"
#include "bpf_experimental.h"

int gvar;

SEC("raw_tp")
__description("C code with may_goto 0")
__success
int may_goto_c_code(void)
{
	int i, tmp[3];

	for (i = 0; i < 3 && can_loop; i++)
		tmp[i] = 0;

	for (i = 0; i < 3 && can_loop; i++)
		tmp[i] = gvar - i;

	for (i = 0; i < 3 && can_loop; i++)
		gvar += tmp[i];

	return 0;
}

char _license[] SEC("license") = "GPL";