Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpf: Allow 'may_goto 0' instruction #8366

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -15972,9 +15972,8 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,

if (insn->code != (BPF_JMP | BPF_JCOND) ||
insn->src_reg != BPF_MAY_GOTO ||
insn->dst_reg || insn->imm || insn->off == 0) {
verbose(env, "invalid may_goto off %d imm %d\n",
insn->off, insn->imm);
insn->dst_reg || insn->imm) {
verbose(env, "invalid may_goto imm %d\n", insn->imm);
return -EINVAL;
}
prev_st = find_prev_entry(env, cur_st->parent, idx);
Expand Down Expand Up @@ -20188,20 +20187,25 @@ static const struct bpf_insn NOP = BPF_JMP_IMM(BPF_JA, 0, 0, 0);

static int opt_remove_nops(struct bpf_verifier_env *env)
{
const struct bpf_insn may_goto_0 = BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0, 0);
const struct bpf_insn ja = NOP;
struct bpf_insn *insn = env->prog->insnsi;
int insn_cnt = env->prog->len;
bool is_may_goto_0, is_ja;
int i, err;

for (i = 0; i < insn_cnt; i++) {
if (memcmp(&insn[i], &ja, sizeof(ja)))
is_may_goto_0 = !memcmp(&insn[i], &may_goto_0, sizeof(may_goto_0));
is_ja = !memcmp(&insn[i], &ja, sizeof(ja));

if (!is_may_goto_0 && !is_ja)
continue;

err = verifier_remove_insns(env, i, 1);
if (err)
return err;
insn_cnt--;
i--;
i -= (is_may_goto_0 && i > 0) ? 2 : 1;
}

return 0;
Expand Down
4 changes: 4 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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); }
Expand Down
97 changes: 97 additions & 0 deletions tools/testing/selftests/bpf/progs/verifier_may_goto_1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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 changes: 28 additions & 0 deletions tools/testing/selftests/bpf/progs/verifier_may_goto_2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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";
Loading