From: Anton Protopopov <aspsk@isovalent.com>
To: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Jiri Olsa <jolsa@kernel.org>,
Martin KaFai Lau <martin.lau@linux.dev>,
Stanislav Fomichev <sdf@google.com>,
Yonghong Song <yonghong.song@linux.dev>,
Eduard Zingerman <eddyz87@gmail.com>,
Quentin Monnet <quentin@isovalent.com>,
bpf@vger.kernel.org
Cc: Anton Protopopov <aspsk@isovalent.com>
Subject: [PATCH v1 bpf-next 6/9] bpf: add support for an extended JA instruction
Date: Fri, 2 Feb 2024 16:28:10 +0000 [thread overview]
Message-ID: <20240202162813.4184616-7-aspsk@isovalent.com> (raw)
In-Reply-To: <20240202162813.4184616-1-aspsk@isovalent.com>
Add support for a new version of JA instruction, a static branch JA. Such
instructions may either jump to the specified offset or act as nops. To
distinguish such instructions from normal JA the BPF_STATIC_BRANCH_JA flag
should be set for the SRC register.
By default on program load such instructions are jitted as a normal JA.
However, if the BPF_STATIC_BRANCH_NOP flag is set in the SRC register,
then the instruction is jitted to a NOP.
In order to generate BPF_STATIC_BRANCH_JA instructions using llvm two new
instructions were added:
asm volatile goto ("nop_or_gotol %l[label]" :::: label);
will generate the BPF_STATIC_BRANCH_JA|BPF_STATIC_BRANCH_NOP instuction and
asm volatile goto ("gotol_or_nop %l[label]" :::: label);
will generate a BPF_STATIC_BRANCH_JA instruction, without an extra bit set.
The reason for adding two instructions is that both are required to implement
static keys functionality for BPF.
The verifier logic is extended to check both possible paths: jump and nop.
Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
---
arch/x86/net/bpf_jit_comp.c | 19 +++++++++++++--
include/uapi/linux/bpf.h | 10 ++++++++
kernel/bpf/verifier.c | 43 +++++++++++++++++++++++++++-------
tools/include/uapi/linux/bpf.h | 10 ++++++++
4 files changed, 71 insertions(+), 11 deletions(-)
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index a80b8c1e7afe..b291b5c79d26 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1131,6 +1131,15 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op)
*pprog = prog;
}
+static bool is_static_ja_nop(const struct bpf_insn *insn)
+{
+ u8 code = insn->code;
+
+ return (code == (BPF_JMP | BPF_JA) || code == (BPF_JMP32 | BPF_JA)) &&
+ (insn->src_reg & BPF_STATIC_BRANCH_JA) &&
+ (insn->src_reg & BPF_STATIC_BRANCH_NOP);
+}
+
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
@@ -2016,9 +2025,15 @@ st: if (is_imm8(insn->off))
}
emit_nops(&prog, INSN_SZ_DIFF - 2);
}
- EMIT2(0xEB, jmp_offset);
+ if (is_static_ja_nop(insn))
+ emit_nops(&prog, 2);
+ else
+ EMIT2(0xEB, jmp_offset);
} else if (is_simm32(jmp_offset)) {
- EMIT1_off32(0xE9, jmp_offset);
+ if (is_static_ja_nop(insn))
+ emit_nops(&prog, 5);
+ else
+ EMIT1_off32(0xE9, jmp_offset);
} else {
pr_err("jmp gen bug %llx\n", jmp_offset);
return -EFAULT;
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index c874f354c290..aca5ed065731 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1412,6 +1412,16 @@ struct bpf_stack_build_id {
};
};
+/* Flags for JA insn, passed in SRC_REG */
+enum {
+ BPF_STATIC_BRANCH_JA = 1 << 0,
+ BPF_STATIC_BRANCH_NOP = 1 << 1,
+};
+
+#define BPF_STATIC_BRANCH_MASK (BPF_STATIC_BRANCH_JA | \
+ BPF_STATIC_BRANCH_NOP)
+
+
#define BPF_OBJ_NAME_LEN 16U
union bpf_attr {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 270dc0a26d03..003b54fbc6d9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -15630,14 +15630,24 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
else
off = insn->imm;
- /* unconditional jump with single edge */
- ret = push_insn(t, t + off + 1, FALLTHROUGH, env);
- if (ret)
- return ret;
+ if (insn->src_reg & BPF_STATIC_BRANCH_JA) {
+ /* static branch - jump with two edges */
+ mark_prune_point(env, t);
+
+ ret = push_insn(t, t + 1, FALLTHROUGH, env);
+ if (ret)
+ return ret;
- mark_prune_point(env, t + off + 1);
- mark_jmp_point(env, t + off + 1);
+ ret = push_insn(t, t + off + 1, BRANCH, env);
+ } else {
+ /* unconditional jump with single edge */
+ ret = push_insn(t, t + off + 1, FALLTHROUGH, env);
+ if (ret)
+ return ret;
+ mark_prune_point(env, t + off + 1);
+ mark_jmp_point(env, t + off + 1);
+ }
return ret;
default:
@@ -17607,8 +17617,11 @@ static int do_check(struct bpf_verifier_env *env)
mark_reg_scratched(env, BPF_REG_0);
} else if (opcode == BPF_JA) {
+ struct bpf_verifier_state *other_branch;
+ u32 jmp_offset;
+
if (BPF_SRC(insn->code) != BPF_K ||
- insn->src_reg != BPF_REG_0 ||
+ (insn->src_reg & ~BPF_STATIC_BRANCH_MASK) ||
insn->dst_reg != BPF_REG_0 ||
(class == BPF_JMP && insn->imm != 0) ||
(class == BPF_JMP32 && insn->off != 0)) {
@@ -17617,9 +17630,21 @@ static int do_check(struct bpf_verifier_env *env)
}
if (class == BPF_JMP)
- env->insn_idx += insn->off + 1;
+ jmp_offset = insn->off + 1;
else
- env->insn_idx += insn->imm + 1;
+ jmp_offset = insn->imm + 1;
+
+ /* Staic branch can either jump to +off or +0 */
+ if (insn->src_reg & BPF_STATIC_BRANCH_JA) {
+ other_branch = push_stack(env, env->insn_idx + jmp_offset,
+ env->insn_idx, false);
+ if (!other_branch)
+ return -EFAULT;
+
+ jmp_offset = 1;
+ }
+
+ env->insn_idx += jmp_offset;
continue;
} else if (opcode == BPF_EXIT) {
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index c874f354c290..aca5ed065731 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1412,6 +1412,16 @@ struct bpf_stack_build_id {
};
};
+/* Flags for JA insn, passed in SRC_REG */
+enum {
+ BPF_STATIC_BRANCH_JA = 1 << 0,
+ BPF_STATIC_BRANCH_NOP = 1 << 1,
+};
+
+#define BPF_STATIC_BRANCH_MASK (BPF_STATIC_BRANCH_JA | \
+ BPF_STATIC_BRANCH_NOP)
+
+
#define BPF_OBJ_NAME_LEN 16U
union bpf_attr {
--
2.34.1
next prev parent reply other threads:[~2024-02-02 16:34 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-02 16:28 [PATCH v1 bpf-next 0/9] BPF static branches Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 1/9] bpf: fix potential error return Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 2/9] bpf: keep track of and expose xlated insn offsets Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 3/9] bpf: expose how xlated insns map to jitted insns Anton Protopopov
2024-02-06 1:09 ` Alexei Starovoitov
2024-02-06 10:02 ` Anton Protopopov
2024-02-07 2:26 ` Alexei Starovoitov
2024-02-08 11:05 ` Anton Protopopov
2024-02-15 6:48 ` Alexei Starovoitov
2024-02-16 13:57 ` Anton Protopopov
2024-02-21 1:09 ` Alexei Starovoitov
2024-03-06 10:44 ` Anton Protopopov
2024-03-14 1:56 ` Alexei Starovoitov
2024-03-14 9:03 ` Anton Protopopov
2024-03-14 17:07 ` Alexei Starovoitov
2024-03-14 20:06 ` Andrii Nakryiko
2024-03-14 21:41 ` Alexei Starovoitov
2024-03-15 13:11 ` Anton Protopopov
2024-03-15 16:32 ` Andrii Nakryiko
2024-03-15 17:22 ` Alexei Starovoitov
2024-03-15 17:29 ` Andrii Nakryiko
2024-03-28 16:37 ` Anton Protopopov
2024-03-29 22:44 ` Andrii Nakryiko
2024-04-01 9:47 ` Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 4/9] selftests/bpf: Add tests for instructions mappings Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 5/9] bpftool: dump new fields of bpf prog info Anton Protopopov
2024-02-02 16:28 ` Anton Protopopov [this message]
2024-02-02 16:28 ` [PATCH v1 bpf-next 7/9] bpf: Add kernel/bpftool asm support for new instructions Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 8/9] bpf: add BPF_STATIC_BRANCH_UPDATE syscall Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 9/9] selftests/bpf: Add tests for new ja* instructions Anton Protopopov
2024-02-02 22:39 ` [PATCH v1 bpf-next 0/9] BPF static branches Andrii Nakryiko
2024-02-04 16:05 ` Anton Protopopov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240202162813.4184616-7-aspsk@isovalent.com \
--to=aspsk@isovalent.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=jolsa@kernel.org \
--cc=martin.lau@linux.dev \
--cc=quentin@isovalent.com \
--cc=sdf@google.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox