* [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets
@ 2026-03-06 10:23 Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier Xu Kuohai
` (4 more replies)
0 siblings, 5 replies; 18+ messages in thread
From: Xu Kuohai @ 2026-03-06 10:23 UTC (permalink / raw)
To: bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Shahab Vahedi, Russell King, Tiezhu Yang,
Hengqi Chen, Johan Almbladh, Paul Burton, Hari Bathini,
Christophe Leroy, Naveen N Rao, Luke Nelson, Xi Wang,
Björn Töpel, Pu Lehui, Ilya Leoshkevich, Heiko Carstens,
Vasily Gorbik, David S . Miller, Wang YanQing
From: Xu Kuohai <xukuohai@huawei.com>
On architectures with CFI protection enabled that require landing pad
instructions at indirect jump targets, such as x86 with CET/IBT eanbled
and arm64 with BTI enabled, kernel panics when an indirect jump lands on
a target witout landing pad. Therefore, the JIT must emit landing pad
instructions for indirect jump targets.
The verifier already recognizes which instructions are indirect jump
targets during the verification phase. So we can stores this information
in env->insn_aux_data and pass it to the JIT as new parameter, so the JIT
knows which instructions are indirect jump targets.
During JIT, constants blinding is performed. It rewrites the private copy
of instructions for the JITed program, but it does not adjust the global
env->insn_aux_data array. As a result, after constants blinding, the
instruction indexes used by JIT may no longer match the indexes in
env->insn_aux_data, so the JIT cant not lookup env->insn_aux_data directly.
To avoid this mistach, and considering that all existing arch-specific JITs
already implement constants blinding with largely duplicated code, move
constants blinding from JIT to generic code, before copying instructions
for each subprog.
v6:
- Move constants blinding from JIT to verifier
- Move call to bpf_prog_select_runtime from bpf_prog_load to verifier
v5: https://lore.kernel.org/bpf/20260302102726.1126019-1-xukuohai@huaweicloud.com/
- Switch to pass env to JIT directly to get rid of coping private insn_aux_data for
each prog
v4: https://lore.kernel.org/all/20260114093914.2403982-1-xukuohai@huaweicloud.com/
- Switch to the approach proposed by Eduard, using insn_aux_data to indentify indirect
jump targets, and emit ENDBR on x86
v3: https://lore.kernel.org/bpf/20251227081033.240336-1-xukuohai@huaweicloud.com/
- Get rid of unnecessary enum definition (Yonghong Song, Anton Protopopov)
v2: https://lore.kernel.org/bpf/20251223085447.139301-1-xukuohai@huaweicloud.com/
- Exclude instruction arrays not used for indirect jumps (Anton Protopopov)
v1: https://lore.kernel.org/bpf/20251127140318.3944249-1-xukuohai@huaweicloud.com/
Xu Kuohai (5):
bpf: Move constants blinding from JIT to verifier
bpf: Pass bpf_verifier_env to jit
bpf: Add helper to detect indirect jump targets
bpf, x86: Emit ENDBR for indirect jump targets
bpf, arm64: Emit BTI for indirect jump target
arch/arc/net/bpf_jit_core.c | 37 ++--
arch/arm/net/bpf_jit_32.c | 43 +----
arch/arm64/net/bpf_jit_comp.c | 74 +++-----
arch/loongarch/net/bpf_jit.c | 52 ++----
arch/mips/net/bpf_jit_comp.c | 22 +--
arch/parisc/net/bpf_jit_core.c | 40 +----
arch/powerpc/net/bpf_jit_comp.c | 47 ++---
arch/riscv/net/bpf_jit_core.c | 47 ++---
arch/s390/net/bpf_jit_comp.c | 43 +----
arch/sparc/net/bpf_jit_comp_64.c | 43 +----
arch/x86/net/bpf_jit_comp.c | 65 +++----
arch/x86/net/bpf_jit_comp32.c | 35 +---
include/linux/bpf.h | 2 +
include/linux/bpf_verifier.h | 9 +-
include/linux/filter.h | 7 +-
kernel/bpf/core.c | 300 +++----------------------------
kernel/bpf/syscall.c | 4 -
kernel/bpf/verifier.c | 230 ++++++++++++++++++++++--
18 files changed, 380 insertions(+), 720 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 18+ messages in thread
* [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier
2026-03-06 10:23 [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets Xu Kuohai
@ 2026-03-06 10:23 ` Xu Kuohai
2026-03-06 10:38 ` bot+bpf-ci
2026-03-06 18:30 ` Alexei Starovoitov
2026-03-06 10:23 ` [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit Xu Kuohai
` (3 subsequent siblings)
4 siblings, 2 replies; 18+ messages in thread
From: Xu Kuohai @ 2026-03-06 10:23 UTC (permalink / raw)
To: bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Shahab Vahedi, Russell King, Tiezhu Yang,
Hengqi Chen, Johan Almbladh, Paul Burton, Hari Bathini,
Christophe Leroy, Naveen N Rao, Luke Nelson, Xi Wang,
Björn Töpel, Pu Lehui, Ilya Leoshkevich, Heiko Carstens,
Vasily Gorbik, David S . Miller, Wang YanQing
From: Xu Kuohai <xukuohai@huawei.com>
During the JIT stage, constants blinding rewrites instructions but only
rewrites the private instruction copy of the JITed subprog, leaving the
global instructions and insn_aux_data unchanged. This causes a mismatch
between subprog instructions and the global state, making it difficult
to look up the global insn_aux_data in the JIT.
To avoid this mismatch, and given that all arch-specific JITs already
support constants blinding, move it to the generic verifier code, and
switch to rewrite the global env->insnsi with the global states
adjusted, as other rewrites in the verifier do.
This removes the constant blinding calls in each JIT, which are largely
duplicated code across architectures.
And the prog clone functions and insn_array adjustment for the JIT
constant blinding are no longer needed, remove them too.
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
arch/arc/net/bpf_jit_core.c | 20 +--
arch/arm/net/bpf_jit_32.c | 41 +----
arch/arm64/net/bpf_jit_comp.c | 59 ++-----
arch/loongarch/net/bpf_jit.c | 50 ++----
arch/mips/net/bpf_jit_comp.c | 20 +--
arch/parisc/net/bpf_jit_core.c | 38 +----
arch/powerpc/net/bpf_jit_comp.c | 45 ++----
arch/riscv/net/bpf_jit_core.c | 45 ++----
arch/s390/net/bpf_jit_comp.c | 41 +----
arch/sparc/net/bpf_jit_comp_64.c | 41 +----
arch/x86/net/bpf_jit_comp.c | 40 +----
arch/x86/net/bpf_jit_comp32.c | 33 +---
include/linux/filter.h | 3 -
kernel/bpf/core.c | 263 -------------------------------
kernel/bpf/verifier.c | 215 +++++++++++++++++++++++--
15 files changed, 288 insertions(+), 666 deletions(-)
diff --git a/arch/arc/net/bpf_jit_core.c b/arch/arc/net/bpf_jit_core.c
index 1421eeced0f5..12facf5750da 100644
--- a/arch/arc/net/bpf_jit_core.c
+++ b/arch/arc/net/bpf_jit_core.c
@@ -79,7 +79,6 @@ struct arc_jit_data {
* The JIT pertinent context that is used by different functions.
*
* prog: The current eBPF program being handled.
- * orig_prog: The original eBPF program before any possible change.
* jit: The JIT buffer and its length.
* bpf_header: The JITed program header. "jit.buf" points inside it.
* emit: If set, opcodes are written to memory; else, a dry-run.
@@ -94,12 +93,10 @@ struct arc_jit_data {
* need_extra_pass: A forecast if an "extra_pass" will occur.
* is_extra_pass: Indicates if the current pass is an extra pass.
* user_bpf_prog: True, if VM opcodes come from a real program.
- * blinded: True if "constant blinding" step returned a new "prog".
* success: Indicates if the whole JIT went OK.
*/
struct jit_context {
struct bpf_prog *prog;
- struct bpf_prog *orig_prog;
struct jit_buffer jit;
struct bpf_binary_header *bpf_header;
bool emit;
@@ -114,7 +111,6 @@ struct jit_context {
bool need_extra_pass;
bool is_extra_pass;
bool user_bpf_prog;
- bool blinded;
bool success;
};
@@ -161,13 +157,7 @@ static int jit_ctx_init(struct jit_context *ctx, struct bpf_prog *prog)
{
memset(ctx, 0, sizeof(*ctx));
- ctx->orig_prog = prog;
-
- /* If constant blinding was requested but failed, scram. */
- ctx->prog = bpf_jit_blind_constants(prog);
- if (IS_ERR(ctx->prog))
- return PTR_ERR(ctx->prog);
- ctx->blinded = (ctx->prog != ctx->orig_prog);
+ ctx->prog = prog;
/* If the verifier doesn't zero-extend, then we have to do it. */
ctx->do_zext = !ctx->prog->aux->verifier_zext;
@@ -214,14 +204,6 @@ static inline void maybe_free(struct jit_context *ctx, void **mem)
*/
static void jit_ctx_cleanup(struct jit_context *ctx)
{
- if (ctx->blinded) {
- /* if all went well, release the orig_prog. */
- if (ctx->success)
- bpf_jit_prog_release_other(ctx->prog, ctx->orig_prog);
- else
- bpf_jit_prog_release_other(ctx->orig_prog, ctx->prog);
- }
-
maybe_free(ctx, (void **)&ctx->bpf2insn);
maybe_free(ctx, (void **)&ctx->jit_data);
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index deeb8f292454..e6b1bb2de627 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -2144,9 +2144,7 @@ bool bpf_jit_needs_zext(void)
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
- struct bpf_prog *tmp, *orig_prog = prog;
struct bpf_binary_header *header;
- bool tmp_blinded = false;
struct jit_ctx ctx;
unsigned int tmp_idx;
unsigned int image_size;
@@ -2156,20 +2154,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
* the interpreter.
*/
if (!prog->jit_requested)
- return orig_prog;
-
- /* If constant blinding was enabled and we failed during blinding
- * then we must fall back to the interpreter. Otherwise, we save
- * the new JITed code.
- */
- tmp = bpf_jit_blind_constants(prog);
-
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
memset(&ctx, 0, sizeof(ctx));
ctx.prog = prog;
@@ -2179,10 +2164,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
* we must fall back to the interpreter
*/
ctx.offsets = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
- if (ctx.offsets == NULL) {
- prog = orig_prog;
- goto out;
- }
+ if (ctx.offsets == NULL)
+ return prog;
/* 1) fake pass to find in the length of the JITed code,
* to compute ctx->offsets and other context variables
@@ -2194,10 +2177,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
* being successful in the second pass, so just fall back
* to the interpreter.
*/
- if (build_body(&ctx)) {
- prog = orig_prog;
+ if (build_body(&ctx))
goto out_off;
- }
tmp_idx = ctx.idx;
build_prologue(&ctx);
@@ -2213,10 +2194,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx.idx += ctx.imm_count;
if (ctx.imm_count) {
ctx.imms = kcalloc(ctx.imm_count, sizeof(u32), GFP_KERNEL);
- if (ctx.imms == NULL) {
- prog = orig_prog;
+ if (ctx.imms == NULL)
goto out_off;
- }
}
#else
/* there's nothing about the epilogue on ARMv7 */
@@ -2238,10 +2217,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
/* Not able to allocate memory for the structure then
* we must fall back to the interpretation
*/
- if (header == NULL) {
- prog = orig_prog;
+ if (header == NULL)
goto out_imms;
- }
/* 2.) Actual pass to generate final JIT code */
ctx.target = (u32 *) image_ptr;
@@ -2278,16 +2255,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
#endif
out_off:
kfree(ctx.offsets);
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
+
return prog;
out_free:
image_ptr = NULL;
bpf_jit_binary_free(header);
- prog = orig_prog;
goto out_imms;
}
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index adf84962d579..c5ed9d84c3ae 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -2009,14 +2009,12 @@ struct arm64_jit_data {
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
int image_size, prog_size, extable_size, extable_align, extable_offset;
- struct bpf_prog *tmp, *orig_prog = prog;
struct bpf_binary_header *header;
struct bpf_binary_header *ro_header = NULL;
struct arm64_jit_data *jit_data;
void __percpu *priv_stack_ptr = NULL;
bool was_classic = bpf_prog_was_classic(prog);
int priv_stack_alloc_sz;
- bool tmp_blinded = false;
bool extra_pass = false;
struct jit_ctx ctx;
u8 *image_ptr;
@@ -2025,26 +2023,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
int exentry_idx;
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- /* If blinding was requested and we failed during blinding,
- * we must fall back to the interpreter.
- */
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
jit_data = prog->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- prog = orig_prog;
- goto out;
- }
+ if (!jit_data)
+ return prog;
prog->aux->jit_data = jit_data;
}
priv_stack_ptr = prog->aux->priv_stack_ptr;
@@ -2056,10 +2041,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 16) +
2 * PRIV_STACK_GUARD_SZ;
priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 16, GFP_KERNEL);
- if (!priv_stack_ptr) {
- prog = orig_prog;
+ if (!priv_stack_ptr)
goto out_priv_stack;
- }
priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
prog->aux->priv_stack_ptr = priv_stack_ptr;
@@ -2079,10 +2062,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx.prog = prog;
ctx.offset = kvzalloc_objs(int, prog->len + 1);
- if (ctx.offset == NULL) {
- prog = orig_prog;
+ if (ctx.offset == NULL)
goto out_off;
- }
ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
ctx.arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
@@ -2095,15 +2076,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
* BPF line info needs ctx->offset[i] to be the offset of
* instruction[i] in jited image, so build prologue first.
*/
- if (build_prologue(&ctx, was_classic)) {
- prog = orig_prog;
+ if (build_prologue(&ctx, was_classic))
goto out_off;
- }
- if (build_body(&ctx, extra_pass)) {
- prog = orig_prog;
+ if (build_body(&ctx, extra_pass))
goto out_off;
- }
ctx.epilogue_offset = ctx.idx;
build_epilogue(&ctx, was_classic);
@@ -2121,10 +2098,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
sizeof(u64), &header, &image_ptr,
jit_fill_hole);
- if (!ro_header) {
- prog = orig_prog;
+ if (!ro_header)
goto out_off;
- }
/* Pass 2: Determine jited position and result for each instruction */
@@ -2152,10 +2127,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
/* Dont write body instructions to memory for now */
ctx.write = false;
- if (build_body(&ctx, extra_pass)) {
- prog = orig_prog;
+ if (build_body(&ctx, extra_pass))
goto out_free_hdr;
- }
ctx.epilogue_offset = ctx.idx;
ctx.exentry_idx = exentry_idx;
@@ -2164,19 +2137,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
/* Pass 3: Adjust jump offset and write final image */
if (build_body(&ctx, extra_pass) ||
- WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset)) {
- prog = orig_prog;
+ WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset))
goto out_free_hdr;
- }
build_epilogue(&ctx, was_classic);
build_plt(&ctx);
/* Extra pass to validate JITed code. */
- if (validate_ctx(&ctx)) {
- prog = orig_prog;
+ if (validate_ctx(&ctx))
goto out_free_hdr;
- }
/* update the real prog size */
prog_size = sizeof(u32) * ctx.idx;
@@ -2201,7 +2170,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
/* ro_header has been freed */
ro_header = NULL;
- prog = orig_prog;
goto out_off;
}
/*
@@ -2245,10 +2213,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
kfree(jit_data);
prog->aux->jit_data = NULL;
}
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
+
return prog;
out_free_hdr:
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index 3bd89f55960d..3a5cc3e88424 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -1911,43 +1911,26 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
- bool tmp_blinded = false, extra_pass = false;
+ bool extra_pass = false;
u8 *image_ptr, *ro_image_ptr;
int image_size, prog_size, extable_size;
struct jit_ctx ctx;
struct jit_data *jit_data;
struct bpf_binary_header *header;
struct bpf_binary_header *ro_header;
- struct bpf_prog *tmp, *orig_prog = prog;
/*
* If BPF JIT was not enabled then we must fall back to
* the interpreter.
*/
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- /*
- * If blinding was requested and we failed during blinding,
- * we must fall back to the interpreter. Otherwise, we save
- * the new JITed code.
- */
- if (IS_ERR(tmp))
- return orig_prog;
-
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
jit_data = prog->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- prog = orig_prog;
- goto out;
- }
+ if (!jit_data)
+ return prog;
prog->aux->jit_data = jit_data;
}
if (jit_data->ctx.offset) {
@@ -1967,17 +1950,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
ctx.offset = kvcalloc(prog->len + 1, sizeof(u32), GFP_KERNEL);
- if (ctx.offset == NULL) {
- prog = orig_prog;
+ if (ctx.offset == NULL)
goto out_offset;
- }
/* 1. Initial fake pass to compute ctx->idx and set ctx->flags */
build_prologue(&ctx);
- if (build_body(&ctx, extra_pass)) {
- prog = orig_prog;
+ if (build_body(&ctx, extra_pass))
goto out_offset;
- }
ctx.epilogue_offset = ctx.idx;
build_epilogue(&ctx);
@@ -1993,10 +1972,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
/* Now we know the size of the structure to make */
ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
&header, &image_ptr, jit_fill_hole);
- if (!ro_header) {
- prog = orig_prog;
+ if (!ro_header)
goto out_offset;
- }
/* 2. Now, the actual pass to generate final JIT code */
/*
@@ -2016,17 +1993,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx.num_exentries = 0;
build_prologue(&ctx);
- if (build_body(&ctx, extra_pass)) {
- prog = orig_prog;
+ if (build_body(&ctx, extra_pass))
goto out_free;
- }
build_epilogue(&ctx);
/* 3. Extra pass to validate JITed code */
- if (validate_ctx(&ctx)) {
- prog = orig_prog;
+ if (validate_ctx(&ctx))
goto out_free;
- }
/* And we're done */
if (bpf_jit_enable > 1)
@@ -2041,7 +2014,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
/* ro_header has been freed */
ro_header = NULL;
- prog = orig_prog;
goto out_free;
}
/*
@@ -2073,10 +2045,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
prog->aux->jit_data = NULL;
}
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ? tmp : orig_prog);
-
return prog;
out_free:
diff --git a/arch/mips/net/bpf_jit_comp.c b/arch/mips/net/bpf_jit_comp.c
index e355dfca4400..d2b6c955f18e 100644
--- a/arch/mips/net/bpf_jit_comp.c
+++ b/arch/mips/net/bpf_jit_comp.c
@@ -911,10 +911,8 @@ bool bpf_jit_needs_zext(void)
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
- struct bpf_prog *tmp, *orig_prog = prog;
struct bpf_binary_header *header = NULL;
struct jit_context ctx;
- bool tmp_blinded = false;
unsigned int tmp_idx;
unsigned int image_size;
u8 *image_ptr;
@@ -925,19 +923,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
* the interpreter.
*/
if (!prog->jit_requested)
- return orig_prog;
- /*
- * If constant blinding was enabled and we failed during blinding
- * then we must fall back to the interpreter. Otherwise, we save
- * the new JITed code.
- */
- tmp = bpf_jit_blind_constants(prog);
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
memset(&ctx, 0, sizeof(ctx));
ctx.program = prog;
@@ -1025,14 +1011,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
prog->jited_len = image_size;
out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
kfree(ctx.descriptors);
return prog;
out_err:
- prog = orig_prog;
if (header)
bpf_jit_binary_free(header);
goto out;
diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c
index a5eb6b51e27a..4d339636a34a 100644
--- a/arch/parisc/net/bpf_jit_core.c
+++ b/arch/parisc/net/bpf_jit_core.c
@@ -44,30 +44,19 @@ bool bpf_jit_needs_zext(void)
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
unsigned int prog_size = 0, extable_size = 0;
- bool tmp_blinded = false, extra_pass = false;
- struct bpf_prog *tmp, *orig_prog = prog;
+ bool extra_pass = false;
int pass = 0, prev_ninsns = 0, prologue_len, i;
struct hppa_jit_data *jit_data;
struct hppa_jit_context *ctx;
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
jit_data = prog->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- prog = orig_prog;
- goto out;
- }
+ if (!jit_data)
+ return prog;
prog->aux->jit_data = jit_data;
}
@@ -81,10 +70,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx->prog = prog;
ctx->offset = kzalloc_objs(int, prog->len);
- if (!ctx->offset) {
- prog = orig_prog;
+ if (!ctx->offset)
goto out_offset;
- }
for (i = 0; i < prog->len; i++) {
prev_ninsns += 20;
ctx->offset[i] = prev_ninsns;
@@ -93,10 +80,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
for (i = 0; i < NR_JIT_ITERATIONS; i++) {
pass++;
ctx->ninsns = 0;
- if (build_body(ctx, extra_pass, ctx->offset)) {
- prog = orig_prog;
+ if (build_body(ctx, extra_pass, ctx->offset))
goto out_offset;
- }
ctx->body_len = ctx->ninsns;
bpf_jit_build_prologue(ctx);
ctx->prologue_len = ctx->ninsns - ctx->body_len;
@@ -116,10 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
&jit_data->image,
sizeof(long),
bpf_fill_ill_insns);
- if (!jit_data->header) {
- prog = orig_prog;
+ if (!jit_data->header)
goto out_offset;
- }
ctx->insns = (u32 *)jit_data->image;
/*
@@ -134,7 +117,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
if (jit_data->header)
bpf_jit_binary_free(jit_data->header);
- prog = orig_prog;
goto out_offset;
}
@@ -148,7 +130,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
bpf_jit_build_prologue(ctx);
if (build_body(ctx, extra_pass, NULL)) {
bpf_jit_binary_free(jit_data->header);
- prog = orig_prog;
goto out_offset;
}
bpf_jit_build_epilogue(ctx);
@@ -183,13 +164,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
kfree(jit_data);
prog->aux->jit_data = NULL;
}
-out:
+
if (HPPA_JIT_REBOOT)
{ extern int machine_restart(char *); machine_restart(""); }
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
return prog;
}
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 52162e4a7f84..7a7c49640a2f 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -142,9 +142,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
int flen;
struct bpf_binary_header *fhdr = NULL;
struct bpf_binary_header *hdr = NULL;
- struct bpf_prog *org_fp = fp;
- struct bpf_prog *tmp_fp;
- bool bpf_blinded = false;
bool extra_pass = false;
u8 *fimage = NULL;
u32 *fcode_base;
@@ -152,24 +149,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
u32 fixup_len;
if (!fp->jit_requested)
- return org_fp;
-
- tmp_fp = bpf_jit_blind_constants(org_fp);
- if (IS_ERR(tmp_fp))
- return org_fp;
-
- if (tmp_fp != org_fp) {
- bpf_blinded = true;
- fp = tmp_fp;
- }
+ return fp;
jit_data = fp->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- fp = org_fp;
- goto out;
- }
+ if (!jit_data)
+ return fp;
fp->aux->jit_data = jit_data;
}
@@ -194,10 +180,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
}
addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL);
- if (addrs == NULL) {
- fp = org_fp;
+ if (addrs == NULL)
goto out_addrs;
- }
memset(&cgctx, 0, sizeof(struct codegen_context));
bpf_jit_init_reg_mapping(&cgctx);
@@ -211,11 +195,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
cgctx.exception_cb = fp->aux->exception_cb;
/* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
+ if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
/* We hit something illegal or unsupported. */
- fp = org_fp;
goto out_addrs;
- }
/*
* If we have seen a tail call, we need a second pass.
@@ -226,10 +208,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
*/
if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
cgctx.idx = 0;
- if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
- fp = org_fp;
+ if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
goto out_addrs;
- }
}
bpf_jit_realloc_regs(&cgctx);
@@ -250,10 +230,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
bpf_jit_fill_ill_insns);
- if (!fhdr) {
- fp = org_fp;
+ if (!fhdr)
goto out_addrs;
- }
if (extable_len)
fp->aux->extable = (void *)fimage + FUNCTION_DESCR_SIZE + proglen + fixup_len;
@@ -272,7 +250,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
extra_pass)) {
bpf_arch_text_copy(&fhdr->size, &hdr->size, sizeof(hdr->size));
bpf_jit_binary_pack_free(fhdr, hdr);
- fp = org_fp;
goto out_addrs;
}
bpf_jit_build_epilogue(code_base, &cgctx);
@@ -301,7 +278,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
if (!fp->is_func || extra_pass) {
if (bpf_jit_binary_pack_finalize(fhdr, hdr)) {
- fp = org_fp;
+ fp->bpf_func = NULL;
+ fp->jited = 0;
+ fp->jited_len = 0;
goto out_addrs;
}
bpf_prog_fill_jited_linfo(fp, addrs);
@@ -318,10 +297,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
jit_data->hdr = hdr;
}
-out:
- if (bpf_blinded)
- bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp);
-
return fp;
}
diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
index b3581e926436..c77e8aba14d3 100644
--- a/arch/riscv/net/bpf_jit_core.c
+++ b/arch/riscv/net/bpf_jit_core.c
@@ -44,29 +44,19 @@ bool bpf_jit_needs_zext(void)
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
unsigned int prog_size = 0, extable_size = 0;
- bool tmp_blinded = false, extra_pass = false;
- struct bpf_prog *tmp, *orig_prog = prog;
+ bool extra_pass = false;
int pass = 0, prev_ninsns = 0, i;
struct rv_jit_data *jit_data;
struct rv_jit_context *ctx;
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
jit_data = prog->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
if (!jit_data) {
- prog = orig_prog;
- goto out;
+ return prog;
}
prog->aux->jit_data = jit_data;
}
@@ -83,15 +73,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
ctx->prog = prog;
ctx->offset = kzalloc_objs(int, prog->len);
- if (!ctx->offset) {
- prog = orig_prog;
+ if (!ctx->offset)
goto out_offset;
- }
- if (build_body(ctx, extra_pass, NULL)) {
- prog = orig_prog;
+ if (build_body(ctx, extra_pass, NULL))
goto out_offset;
- }
for (i = 0; i < prog->len; i++) {
prev_ninsns += 32;
@@ -105,10 +91,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
ctx->prologue_len = ctx->ninsns;
- if (build_body(ctx, extra_pass, ctx->offset)) {
- prog = orig_prog;
+ if (build_body(ctx, extra_pass, ctx->offset))
goto out_offset;
- }
ctx->epilogue_offset = ctx->ninsns;
bpf_jit_build_epilogue(ctx);
@@ -126,10 +110,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
&jit_data->ro_image, sizeof(u32),
&jit_data->header, &jit_data->image,
bpf_fill_ill_insns);
- if (!jit_data->ro_header) {
- prog = orig_prog;
+ if (!jit_data->ro_header)
goto out_offset;
- }
/*
* Use the image(RW) for writing the JITed instructions. But also save
@@ -150,7 +132,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (i == NR_JIT_ITERATIONS) {
pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
- prog = orig_prog;
goto out_free_hdr;
}
@@ -163,10 +144,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx->nexentries = 0;
bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
- if (build_body(ctx, extra_pass, NULL)) {
- prog = orig_prog;
+ if (build_body(ctx, extra_pass, NULL))
goto out_free_hdr;
- }
bpf_jit_build_epilogue(ctx);
if (bpf_jit_enable > 1)
@@ -180,7 +159,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (WARN_ON(bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header))) {
/* ro_header has been freed */
jit_data->ro_header = NULL;
- prog = orig_prog;
+ prog->bpf_func = NULL;
+ prog->jited = 0;
+ prog->jited_len = 0;
goto out_offset;
}
/*
@@ -198,11 +179,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
kfree(jit_data);
prog->aux->jit_data = NULL;
}
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
return prog;
out_free_hdr:
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 1f9a6b728beb..d6de2abfe4a7 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -2305,36 +2305,20 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
*/
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
{
- struct bpf_prog *tmp, *orig_fp = fp;
struct bpf_binary_header *header;
struct s390_jit_data *jit_data;
- bool tmp_blinded = false;
bool extra_pass = false;
struct bpf_jit jit;
int pass;
if (!fp->jit_requested)
- return orig_fp;
-
- tmp = bpf_jit_blind_constants(fp);
- /*
- * If blinding was requested and we failed during blinding,
- * we must fall back to the interpreter.
- */
- if (IS_ERR(tmp))
- return orig_fp;
- if (tmp != fp) {
- tmp_blinded = true;
- fp = tmp;
- }
+ return fp;
jit_data = fp->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- fp = orig_fp;
- goto out;
- }
+ if (!jit_data)
+ return fp;
fp->aux->jit_data = jit_data;
}
if (jit_data->ctx.addrs) {
@@ -2347,33 +2331,26 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
memset(&jit, 0, sizeof(jit));
jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
- if (jit.addrs == NULL) {
- fp = orig_fp;
+ if (jit.addrs == NULL)
goto free_addrs;
- }
/*
* Three initial passes:
* - 1/2: Determine clobbered registers
* - 3: Calculate program size and addrs array
*/
for (pass = 1; pass <= 3; pass++) {
- if (bpf_jit_prog(&jit, fp, extra_pass)) {
- fp = orig_fp;
+ if (bpf_jit_prog(&jit, fp, extra_pass))
goto free_addrs;
- }
}
/*
* Final pass: Allocate and generate program
*/
header = bpf_jit_alloc(&jit, fp);
- if (!header) {
- fp = orig_fp;
+ if (!header)
goto free_addrs;
- }
skip_init_ctx:
if (bpf_jit_prog(&jit, fp, extra_pass)) {
bpf_jit_binary_free(header);
- fp = orig_fp;
goto free_addrs;
}
if (bpf_jit_enable > 1) {
@@ -2383,7 +2360,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
if (!fp->is_func || extra_pass) {
if (bpf_jit_binary_lock_ro(header)) {
bpf_jit_binary_free(header);
- fp = orig_fp;
goto free_addrs;
}
} else {
@@ -2402,10 +2378,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
kfree(jit_data);
fp->aux->jit_data = NULL;
}
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(fp, fp == orig_fp ?
- tmp : orig_fp);
+
return fp;
}
diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c
index b23d1c645ae5..86abd84d4005 100644
--- a/arch/sparc/net/bpf_jit_comp_64.c
+++ b/arch/sparc/net/bpf_jit_comp_64.c
@@ -1479,37 +1479,22 @@ struct sparc64_jit_data {
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
- struct bpf_prog *tmp, *orig_prog = prog;
struct sparc64_jit_data *jit_data;
struct bpf_binary_header *header;
u32 prev_image_size, image_size;
- bool tmp_blinded = false;
bool extra_pass = false;
struct jit_ctx ctx;
u8 *image_ptr;
int pass, i;
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- /* If blinding was requested and we failed during blinding,
- * we must fall back to the interpreter.
- */
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
jit_data = prog->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- prog = orig_prog;
- goto out;
- }
+ if (!jit_data)
+ return prog;
prog->aux->jit_data = jit_data;
}
if (jit_data->ctx.offset) {
@@ -1527,10 +1512,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx.prog = prog;
ctx.offset = kmalloc_array(prog->len, sizeof(unsigned int), GFP_KERNEL);
- if (ctx.offset == NULL) {
- prog = orig_prog;
+ if (ctx.offset == NULL)
goto out_off;
- }
/* Longest sequence emitted is for bswap32, 12 instructions. Pre-cook
* the offset array so that we converge faster.
@@ -1543,10 +1526,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
ctx.idx = 0;
build_prologue(&ctx);
- if (build_body(&ctx)) {
- prog = orig_prog;
+ if (build_body(&ctx))
goto out_off;
- }
build_epilogue(&ctx);
if (bpf_jit_enable > 1)
@@ -1569,10 +1550,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
image_size = sizeof(u32) * ctx.idx;
header = bpf_jit_binary_alloc(image_size, &image_ptr,
sizeof(u32), jit_fill_hole);
- if (header == NULL) {
- prog = orig_prog;
+ if (header == NULL)
goto out_off;
- }
ctx.image = (u32 *)image_ptr;
skip_init_ctx:
@@ -1582,7 +1561,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (build_body(&ctx)) {
bpf_jit_binary_free(header);
- prog = orig_prog;
goto out_off;
}
@@ -1592,7 +1570,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
pr_err("bpf_jit: Failed to converge, prev_size=%u size=%d\n",
prev_image_size, ctx.idx * 4);
bpf_jit_binary_free(header);
- prog = orig_prog;
goto out_off;
}
@@ -1604,7 +1581,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (!prog->is_func || extra_pass) {
if (bpf_jit_binary_lock_ro(header)) {
bpf_jit_binary_free(header);
- prog = orig_prog;
goto out_off;
}
} else {
@@ -1624,9 +1600,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
kfree(jit_data);
prog->aux->jit_data = NULL;
}
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
+
return prog;
}
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 8f10080e6fe3..bb8e7541d078 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -3726,13 +3726,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
struct bpf_binary_header *rw_header = NULL;
struct bpf_binary_header *header = NULL;
- struct bpf_prog *tmp, *orig_prog = prog;
void __percpu *priv_stack_ptr = NULL;
struct x64_jit_data *jit_data;
int priv_stack_alloc_sz;
int proglen, oldproglen = 0;
struct jit_context ctx = {};
- bool tmp_blinded = false;
bool extra_pass = false;
bool padding = false;
u8 *rw_image = NULL;
@@ -3742,27 +3740,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
int i;
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- /*
- * If blinding was requested and we failed during blinding,
- * we must fall back to the interpreter.
- */
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
jit_data = prog->aux->jit_data;
if (!jit_data) {
jit_data = kzalloc_obj(*jit_data);
- if (!jit_data) {
- prog = orig_prog;
+ if (!jit_data)
goto out;
- }
prog->aux->jit_data = jit_data;
}
priv_stack_ptr = prog->aux->priv_stack_ptr;
@@ -3774,10 +3758,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 8) +
2 * PRIV_STACK_GUARD_SZ;
priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 8, GFP_KERNEL);
- if (!priv_stack_ptr) {
- prog = orig_prog;
+ if (!priv_stack_ptr)
goto out_priv_stack;
- }
priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
prog->aux->priv_stack_ptr = priv_stack_ptr;
@@ -3795,10 +3777,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
goto skip_init_addrs;
}
addrs = kvmalloc_objs(*addrs, prog->len + 1);
- if (!addrs) {
- prog = orig_prog;
+ if (!addrs)
goto out_addrs;
- }
/*
* Before first pass, make a rough estimation of addrs[]
@@ -3829,8 +3809,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
sizeof(rw_header->size));
bpf_jit_binary_pack_free(header, rw_header);
}
- /* Fall back to interpreter mode */
- prog = orig_prog;
if (extra_pass) {
prog->bpf_func = NULL;
prog->jited = 0;
@@ -3861,10 +3839,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
&image, align, &rw_header, &rw_image,
jit_fill_hole);
- if (!header) {
- prog = orig_prog;
+ if (!header)
goto out_addrs;
- }
prog->aux->extable = (void *) image + roundup(proglen, align);
}
oldproglen = proglen;
@@ -3917,8 +3893,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
prog->bpf_func = (void *)image + cfi_get_offset();
prog->jited = 1;
prog->jited_len = proglen - cfi_get_offset();
- } else {
- prog = orig_prog;
}
if (!image || !prog->is_func || extra_pass) {
@@ -3934,10 +3908,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
kfree(jit_data);
prog->aux->jit_data = NULL;
}
+
out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
return prog;
}
diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
index dda423025c3d..5f259577614a 100644
--- a/arch/x86/net/bpf_jit_comp32.c
+++ b/arch/x86/net/bpf_jit_comp32.c
@@ -2521,35 +2521,19 @@ bool bpf_jit_needs_zext(void)
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
{
struct bpf_binary_header *header = NULL;
- struct bpf_prog *tmp, *orig_prog = prog;
int proglen, oldproglen = 0;
struct jit_context ctx = {};
- bool tmp_blinded = false;
u8 *image = NULL;
int *addrs;
int pass;
int i;
if (!prog->jit_requested)
- return orig_prog;
-
- tmp = bpf_jit_blind_constants(prog);
- /*
- * If blinding was requested and we failed during blinding,
- * we must fall back to the interpreter.
- */
- if (IS_ERR(tmp))
- return orig_prog;
- if (tmp != prog) {
- tmp_blinded = true;
- prog = tmp;
- }
+ return prog;
addrs = kmalloc_objs(*addrs, prog->len);
- if (!addrs) {
- prog = orig_prog;
- goto out;
- }
+ if (!addrs)
+ return prog;
/*
* Before first pass, make a rough estimation of addrs[]
@@ -2574,7 +2558,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
image = NULL;
if (header)
bpf_jit_binary_free(header);
- prog = orig_prog;
goto out_addrs;
}
if (image) {
@@ -2588,10 +2571,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
if (proglen == oldproglen) {
header = bpf_jit_binary_alloc(proglen, &image,
1, jit_fill_hole);
- if (!header) {
- prog = orig_prog;
+ if (!header)
goto out_addrs;
- }
}
oldproglen = proglen;
cond_resched();
@@ -2604,16 +2585,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
prog->bpf_func = (void *)image;
prog->jited = 1;
prog->jited_len = proglen;
- } else {
- prog = orig_prog;
}
out_addrs:
kfree(addrs);
-out:
- if (tmp_blinded)
- bpf_jit_prog_release_other(prog, prog == orig_prog ?
- tmp : orig_prog);
return prog;
}
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 44d7ae95ddbc..b69369dc3727 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1310,9 +1310,6 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
const char *bpf_jit_get_prog_name(struct bpf_prog *prog);
-struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp);
-void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other);
-
static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
u32 pass, void *image)
{
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 229c74f3d6ae..93150343ac35 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1290,269 +1290,6 @@ const char *bpf_jit_get_prog_name(struct bpf_prog *prog)
return prog->aux->ksym.name;
return prog->aux->name;
}
-
-static int bpf_jit_blind_insn(const struct bpf_insn *from,
- const struct bpf_insn *aux,
- struct bpf_insn *to_buff,
- bool emit_zext)
-{
- struct bpf_insn *to = to_buff;
- u32 imm_rnd = get_random_u32();
- s16 off;
-
- BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG);
- BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG);
-
- /* Constraints on AX register:
- *
- * AX register is inaccessible from user space. It is mapped in
- * all JITs, and used here for constant blinding rewrites. It is
- * typically "stateless" meaning its contents are only valid within
- * the executed instruction, but not across several instructions.
- * There are a few exceptions however which are further detailed
- * below.
- *
- * Constant blinding is only used by JITs, not in the interpreter.
- * The interpreter uses AX in some occasions as a local temporary
- * register e.g. in DIV or MOD instructions.
- *
- * In restricted circumstances, the verifier can also use the AX
- * register for rewrites as long as they do not interfere with
- * the above cases!
- */
- if (from->dst_reg == BPF_REG_AX || from->src_reg == BPF_REG_AX)
- goto out;
-
- if (from->imm == 0 &&
- (from->code == (BPF_ALU | BPF_MOV | BPF_K) ||
- from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) {
- *to++ = BPF_ALU64_REG(BPF_XOR, from->dst_reg, from->dst_reg);
- goto out;
- }
-
- switch (from->code) {
- case BPF_ALU | BPF_ADD | BPF_K:
- case BPF_ALU | BPF_SUB | BPF_K:
- case BPF_ALU | BPF_AND | BPF_K:
- case BPF_ALU | BPF_OR | BPF_K:
- case BPF_ALU | BPF_XOR | BPF_K:
- case BPF_ALU | BPF_MUL | BPF_K:
- case BPF_ALU | BPF_MOV | BPF_K:
- case BPF_ALU | BPF_DIV | BPF_K:
- case BPF_ALU | BPF_MOD | BPF_K:
- *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
- *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_ALU32_REG_OFF(from->code, from->dst_reg, BPF_REG_AX, from->off);
- break;
-
- case BPF_ALU64 | BPF_ADD | BPF_K:
- case BPF_ALU64 | BPF_SUB | BPF_K:
- case BPF_ALU64 | BPF_AND | BPF_K:
- case BPF_ALU64 | BPF_OR | BPF_K:
- case BPF_ALU64 | BPF_XOR | BPF_K:
- case BPF_ALU64 | BPF_MUL | BPF_K:
- case BPF_ALU64 | BPF_MOV | BPF_K:
- case BPF_ALU64 | BPF_DIV | BPF_K:
- case BPF_ALU64 | BPF_MOD | BPF_K:
- *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
- *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_ALU64_REG_OFF(from->code, from->dst_reg, BPF_REG_AX, from->off);
- break;
-
- case BPF_JMP | BPF_JEQ | BPF_K:
- case BPF_JMP | BPF_JNE | BPF_K:
- case BPF_JMP | BPF_JGT | BPF_K:
- case BPF_JMP | BPF_JLT | BPF_K:
- case BPF_JMP | BPF_JGE | BPF_K:
- case BPF_JMP | BPF_JLE | BPF_K:
- case BPF_JMP | BPF_JSGT | BPF_K:
- case BPF_JMP | BPF_JSLT | BPF_K:
- case BPF_JMP | BPF_JSGE | BPF_K:
- case BPF_JMP | BPF_JSLE | BPF_K:
- case BPF_JMP | BPF_JSET | BPF_K:
- /* Accommodate for extra offset in case of a backjump. */
- off = from->off;
- if (off < 0)
- off -= 2;
- *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
- *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX, off);
- break;
-
- case BPF_JMP32 | BPF_JEQ | BPF_K:
- case BPF_JMP32 | BPF_JNE | BPF_K:
- case BPF_JMP32 | BPF_JGT | BPF_K:
- case BPF_JMP32 | BPF_JLT | BPF_K:
- case BPF_JMP32 | BPF_JGE | BPF_K:
- case BPF_JMP32 | BPF_JLE | BPF_K:
- case BPF_JMP32 | BPF_JSGT | BPF_K:
- case BPF_JMP32 | BPF_JSLT | BPF_K:
- case BPF_JMP32 | BPF_JSGE | BPF_K:
- case BPF_JMP32 | BPF_JSLE | BPF_K:
- case BPF_JMP32 | BPF_JSET | BPF_K:
- /* Accommodate for extra offset in case of a backjump. */
- off = from->off;
- if (off < 0)
- off -= 2;
- *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
- *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_JMP32_REG(from->code, from->dst_reg, BPF_REG_AX,
- off);
- break;
-
- case BPF_LD | BPF_IMM | BPF_DW:
- *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[1].imm);
- *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32);
- *to++ = BPF_ALU64_REG(BPF_MOV, aux[0].dst_reg, BPF_REG_AX);
- break;
- case 0: /* Part 2 of BPF_LD | BPF_IMM | BPF_DW. */
- *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[0].imm);
- *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- if (emit_zext)
- *to++ = BPF_ZEXT_REG(BPF_REG_AX);
- *to++ = BPF_ALU64_REG(BPF_OR, aux[0].dst_reg, BPF_REG_AX);
- break;
-
- case BPF_ST | BPF_MEM | BPF_DW:
- case BPF_ST | BPF_MEM | BPF_W:
- case BPF_ST | BPF_MEM | BPF_H:
- case BPF_ST | BPF_MEM | BPF_B:
- *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
- *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_STX_MEM(from->code, from->dst_reg, BPF_REG_AX, from->off);
- break;
- }
-out:
- return to - to_buff;
-}
-
-static struct bpf_prog *bpf_prog_clone_create(struct bpf_prog *fp_other,
- gfp_t gfp_extra_flags)
-{
- gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO | gfp_extra_flags;
- struct bpf_prog *fp;
-
- fp = __vmalloc(fp_other->pages * PAGE_SIZE, gfp_flags);
- if (fp != NULL) {
- /* aux->prog still points to the fp_other one, so
- * when promoting the clone to the real program,
- * this still needs to be adapted.
- */
- memcpy(fp, fp_other, fp_other->pages * PAGE_SIZE);
- }
-
- return fp;
-}
-
-static void bpf_prog_clone_free(struct bpf_prog *fp)
-{
- /* aux was stolen by the other clone, so we cannot free
- * it from this path! It will be freed eventually by the
- * other program on release.
- *
- * At this point, we don't need a deferred release since
- * clone is guaranteed to not be locked.
- */
- fp->aux = NULL;
- fp->stats = NULL;
- fp->active = NULL;
- __bpf_prog_free(fp);
-}
-
-void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
-{
- /* We have to repoint aux->prog to self, as we don't
- * know whether fp here is the clone or the original.
- */
- fp->aux->prog = fp;
- bpf_prog_clone_free(fp_other);
-}
-
-static void adjust_insn_arrays(struct bpf_prog *prog, u32 off, u32 len)
-{
-#ifdef CONFIG_BPF_SYSCALL
- struct bpf_map *map;
- int i;
-
- if (len <= 1)
- return;
-
- for (i = 0; i < prog->aux->used_map_cnt; i++) {
- map = prog->aux->used_maps[i];
- if (map->map_type == BPF_MAP_TYPE_INSN_ARRAY)
- bpf_insn_array_adjust(map, off, len);
- }
-#endif
-}
-
-struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
-{
- struct bpf_insn insn_buff[16], aux[2];
- struct bpf_prog *clone, *tmp;
- int insn_delta, insn_cnt;
- struct bpf_insn *insn;
- int i, rewritten;
-
- if (!prog->blinding_requested || prog->blinded)
- return prog;
-
- clone = bpf_prog_clone_create(prog, GFP_USER);
- if (!clone)
- return ERR_PTR(-ENOMEM);
-
- insn_cnt = clone->len;
- insn = clone->insnsi;
-
- for (i = 0; i < insn_cnt; i++, insn++) {
- if (bpf_pseudo_func(insn)) {
- /* ld_imm64 with an address of bpf subprog is not
- * a user controlled constant. Don't randomize it,
- * since it will conflict with jit_subprogs() logic.
- */
- insn++;
- i++;
- continue;
- }
-
- /* We temporarily need to hold the original ld64 insn
- * so that we can still access the first part in the
- * second blinding run.
- */
- if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW) &&
- insn[1].code == 0)
- memcpy(aux, insn, sizeof(aux));
-
- rewritten = bpf_jit_blind_insn(insn, aux, insn_buff,
- clone->aux->verifier_zext);
- if (!rewritten)
- continue;
-
- tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
- if (IS_ERR(tmp)) {
- /* Patching may have repointed aux->prog during
- * realloc from the original one, so we need to
- * fix it up here on error.
- */
- bpf_jit_prog_release_other(prog, clone);
- return tmp;
- }
-
- clone = tmp;
- insn_delta = rewritten - 1;
-
- /* Instructions arrays must be updated using absolute xlated offsets */
- adjust_insn_arrays(clone, prog->aux->subprog_start + i, rewritten);
-
- /* Walk new program and skip insns we just inserted. */
- insn = clone->insnsi + i + insn_delta;
- insn_cnt += insn_delta;
- i += insn_delta;
- }
-
- clone->blinded = 1;
- return clone;
-}
#endif /* CONFIG_BPF_JIT */
/* Base function for offset calculation. Needs to go into .text section,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index d92cf2821657..e2fffa08cba0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22815,7 +22815,6 @@ static int jit_subprogs(struct bpf_verifier_env *env)
struct bpf_insn *insn;
void *old_bpf_func;
int err, num_exentries;
- int old_len, subprog_start_adjustment = 0;
if (env->subprog_cnt <= 1)
return 0;
@@ -22887,10 +22886,11 @@ static int jit_subprogs(struct bpf_verifier_env *env)
goto out_free;
func[i]->is_func = 1;
func[i]->sleepable = prog->sleepable;
+ func[i]->blinded = prog->blinded;
func[i]->aux->func_idx = i;
/* Below members will be freed only at prog->aux */
func[i]->aux->btf = prog->aux->btf;
- func[i]->aux->subprog_start = subprog_start + subprog_start_adjustment;
+ func[i]->aux->subprog_start = subprog_start;
func[i]->aux->func_info = prog->aux->func_info;
func[i]->aux->func_info_cnt = prog->aux->func_info_cnt;
func[i]->aux->poke_tab = prog->aux->poke_tab;
@@ -22946,15 +22946,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
func[i]->aux->might_sleep = env->subprog_info[i].might_sleep;
if (!i)
func[i]->aux->exception_boundary = env->seen_exception;
-
- /*
- * To properly pass the absolute subprog start to jit
- * all instruction adjustments should be accumulated
- */
- old_len = func[i]->len;
func[i] = bpf_int_jit_compile(func[i]);
- subprog_start_adjustment += func[i]->len - old_len;
-
if (!func[i]->jited) {
err = -ENOTSUPP;
goto out_free;
@@ -23093,6 +23085,206 @@ static int jit_subprogs(struct bpf_verifier_env *env)
return err;
}
+static int bpf_blind_insn(const struct bpf_insn *from,
+ const struct bpf_insn *aux,
+ struct bpf_insn *to_buff,
+ bool emit_zext)
+{
+ struct bpf_insn *to = to_buff;
+ u32 imm_rnd = get_random_u32();
+ s16 off;
+
+ BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG);
+ BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG);
+
+ /* Constraints on AX register:
+ *
+ * AX register is inaccessible from user space. It is mapped in
+ * all JITs, and used here for constant blinding rewrites. It is
+ * typically "stateless" meaning its contents are only valid within
+ * the executed instruction, but not across several instructions.
+ * There are a few exceptions however which are further detailed
+ * below.
+ *
+ * Constant blinding is only used by JITs, not in the interpreter.
+ * The interpreter uses AX in some occasions as a local temporary
+ * register e.g. in DIV or MOD instructions.
+ *
+ * In restricted circumstances, the verifier can also use the AX
+ * register for rewrites as long as they do not interfere with
+ * the above cases!
+ */
+ if (from->dst_reg == BPF_REG_AX || from->src_reg == BPF_REG_AX)
+ goto out;
+
+ if (from->imm == 0 &&
+ (from->code == (BPF_ALU | BPF_MOV | BPF_K) ||
+ from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) {
+ *to++ = BPF_ALU64_REG(BPF_XOR, from->dst_reg, from->dst_reg);
+ goto out;
+ }
+
+ switch (from->code) {
+ case BPF_ALU | BPF_ADD | BPF_K:
+ case BPF_ALU | BPF_SUB | BPF_K:
+ case BPF_ALU | BPF_AND | BPF_K:
+ case BPF_ALU | BPF_OR | BPF_K:
+ case BPF_ALU | BPF_XOR | BPF_K:
+ case BPF_ALU | BPF_MUL | BPF_K:
+ case BPF_ALU | BPF_MOV | BPF_K:
+ case BPF_ALU | BPF_DIV | BPF_K:
+ case BPF_ALU | BPF_MOD | BPF_K:
+ *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+ *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ *to++ = BPF_ALU32_REG_OFF(from->code, from->dst_reg, BPF_REG_AX, from->off);
+ break;
+
+ case BPF_ALU64 | BPF_ADD | BPF_K:
+ case BPF_ALU64 | BPF_SUB | BPF_K:
+ case BPF_ALU64 | BPF_AND | BPF_K:
+ case BPF_ALU64 | BPF_OR | BPF_K:
+ case BPF_ALU64 | BPF_XOR | BPF_K:
+ case BPF_ALU64 | BPF_MUL | BPF_K:
+ case BPF_ALU64 | BPF_MOV | BPF_K:
+ case BPF_ALU64 | BPF_DIV | BPF_K:
+ case BPF_ALU64 | BPF_MOD | BPF_K:
+ *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+ *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ *to++ = BPF_ALU64_REG_OFF(from->code, from->dst_reg, BPF_REG_AX, from->off);
+ break;
+
+ case BPF_JMP | BPF_JEQ | BPF_K:
+ case BPF_JMP | BPF_JNE | BPF_K:
+ case BPF_JMP | BPF_JGT | BPF_K:
+ case BPF_JMP | BPF_JLT | BPF_K:
+ case BPF_JMP | BPF_JGE | BPF_K:
+ case BPF_JMP | BPF_JLE | BPF_K:
+ case BPF_JMP | BPF_JSGT | BPF_K:
+ case BPF_JMP | BPF_JSLT | BPF_K:
+ case BPF_JMP | BPF_JSGE | BPF_K:
+ case BPF_JMP | BPF_JSLE | BPF_K:
+ case BPF_JMP | BPF_JSET | BPF_K:
+ /* Accommodate for extra offset in case of a backjump. */
+ off = from->off;
+ if (off < 0)
+ off -= 2;
+ *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+ *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ *to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX, off);
+ break;
+
+ case BPF_JMP32 | BPF_JEQ | BPF_K:
+ case BPF_JMP32 | BPF_JNE | BPF_K:
+ case BPF_JMP32 | BPF_JGT | BPF_K:
+ case BPF_JMP32 | BPF_JLT | BPF_K:
+ case BPF_JMP32 | BPF_JGE | BPF_K:
+ case BPF_JMP32 | BPF_JLE | BPF_K:
+ case BPF_JMP32 | BPF_JSGT | BPF_K:
+ case BPF_JMP32 | BPF_JSLT | BPF_K:
+ case BPF_JMP32 | BPF_JSGE | BPF_K:
+ case BPF_JMP32 | BPF_JSLE | BPF_K:
+ case BPF_JMP32 | BPF_JSET | BPF_K:
+ /* Accommodate for extra offset in case of a backjump. */
+ off = from->off;
+ if (off < 0)
+ off -= 2;
+ *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+ *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ *to++ = BPF_JMP32_REG(from->code, from->dst_reg, BPF_REG_AX,
+ off);
+ break;
+
+ case BPF_LD | BPF_IMM | BPF_DW:
+ *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[1].imm);
+ *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ *to++ = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32);
+ *to++ = BPF_ALU64_REG(BPF_MOV, aux[0].dst_reg, BPF_REG_AX);
+ break;
+ case 0: /* Part 2 of BPF_LD | BPF_IMM | BPF_DW. */
+ *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[0].imm);
+ *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ if (emit_zext)
+ *to++ = BPF_ZEXT_REG(BPF_REG_AX);
+ *to++ = BPF_ALU64_REG(BPF_OR, aux[0].dst_reg, BPF_REG_AX);
+ break;
+
+ case BPF_ST | BPF_MEM | BPF_DW:
+ case BPF_ST | BPF_MEM | BPF_W:
+ case BPF_ST | BPF_MEM | BPF_H:
+ case BPF_ST | BPF_MEM | BPF_B:
+ *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
+ *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+ *to++ = BPF_STX_MEM(from->code, from->dst_reg, BPF_REG_AX, from->off);
+ break;
+ }
+out:
+ return to - to_buff;
+}
+
+static int bpf_blind_constants(struct bpf_verifier_env *env)
+{
+ struct bpf_insn insn_buff[16], aux[2];
+ struct bpf_prog *prog = env->prog;
+ int insn_delta, insn_cnt;
+ struct bpf_insn *insn;
+ int i, rewritten;
+
+ if (!prog->blinding_requested || prog->blinded)
+ return 0;
+
+ insn_cnt = prog->len;
+ insn = prog->insnsi;
+
+ for (i = 0; i < insn_cnt; i++, insn++) {
+ if (bpf_pseudo_func(insn)) {
+ /* ld_imm64 with an address of bpf subprog is not
+ * a user controlled constant. Don't randomize it,
+ * since it will conflict with jit_subprogs() logic.
+ */
+ insn++;
+ i++;
+ continue;
+ }
+
+ /* We temporarily need to hold the original ld64 insn
+ * so that we can still access the first part in the
+ * second blinding run.
+ */
+ if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW) &&
+ insn[1].code == 0)
+ memcpy(aux, insn, sizeof(aux));
+
+ rewritten = bpf_blind_insn(insn, aux, insn_buff, prog->aux->verifier_zext);
+ if (!rewritten)
+ continue;
+
+ prog = bpf_patch_insn_data(env, i, insn_buff, rewritten);
+ if (!prog)
+ return -ENOMEM;
+
+ env->prog = prog;
+ insn_delta = rewritten - 1;
+
+ /* Walk new program and skip insns we just inserted. */
+ insn = prog->insnsi + i + insn_delta;
+ insn_cnt += insn_delta;
+ i += insn_delta;
+
+ /* bpf_patch_insn_data() calls adjust_insn_aux_data() to adjust insn_aux_data. The
+ * indirect_target flag for the original instruction is moved to the last of the new
+ * instructions, but the indirect jump target is actually the first one, so move
+ * it back.
+ */
+ if (env->insn_aux_data[i].indirect_target) {
+ env->insn_aux_data[i].indirect_target = 0;
+ env->insn_aux_data[i - insn_delta].indirect_target = 1;
+ }
+ }
+
+ prog->blinded = 1;
+ return 0;
+}
+
static int fixup_call_args(struct bpf_verifier_env *env)
{
#ifndef CONFIG_BPF_JIT_ALWAYS_ON
@@ -23105,6 +23297,9 @@ static int fixup_call_args(struct bpf_verifier_env *env)
if (env->prog->jit_requested &&
!bpf_prog_is_offloaded(env->prog->aux)) {
+ err = bpf_blind_constants(env);
+ if (err)
+ return err;
err = jit_subprogs(env);
if (err == 0)
return 0;
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit
2026-03-06 10:23 [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier Xu Kuohai
@ 2026-03-06 10:23 ` Xu Kuohai
2026-03-07 6:40 ` Yeoreum Yun
2026-03-06 10:23 ` [bpf-next v6 3/5] bpf: Add helper to detect indirect jump targets Xu Kuohai
` (2 subsequent siblings)
4 siblings, 1 reply; 18+ messages in thread
From: Xu Kuohai @ 2026-03-06 10:23 UTC (permalink / raw)
To: bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Shahab Vahedi, Russell King, Tiezhu Yang,
Hengqi Chen, Johan Almbladh, Paul Burton, Hari Bathini,
Christophe Leroy, Naveen N Rao, Luke Nelson, Xi Wang,
Björn Töpel, Pu Lehui, Ilya Leoshkevich, Heiko Carstens,
Vasily Gorbik, David S . Miller, Wang YanQing
From: Xu Kuohai <xukuohai@huawei.com>
Pass bpf_verifier_env to bpf_int_jit_compile(). The follow-up patch will
use env->insn_aux_data in the JIT stage to detect indirect jump targets.
Since bpf_prog_select_runtime() can be called by cbpf and test code
without verifier, introduce helper function __bpf_prog_select_runtime()
to accept the env parameter.
Remove the call to bpf_prog_select_runtime() in bpf_prog_load(), and
switch to call __bpf_prog_select_runtime() in the verifier, with env
variable passed. The original bpf_prog_select_runtime() is preserved for
cbpf and test code, where env is NULL.
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
arch/arc/net/bpf_jit_core.c | 17 ++++++++--------
arch/arm/net/bpf_jit_32.c | 2 +-
arch/arm64/net/bpf_jit_comp.c | 2 +-
arch/loongarch/net/bpf_jit.c | 2 +-
arch/mips/net/bpf_jit_comp.c | 2 +-
arch/parisc/net/bpf_jit_core.c | 2 +-
arch/powerpc/net/bpf_jit_comp.c | 2 +-
arch/riscv/net/bpf_jit_core.c | 2 +-
arch/s390/net/bpf_jit_comp.c | 2 +-
arch/sparc/net/bpf_jit_comp_64.c | 2 +-
arch/x86/net/bpf_jit_comp.c | 2 +-
arch/x86/net/bpf_jit_comp32.c | 2 +-
include/linux/filter.h | 4 +++-
kernel/bpf/core.c | 34 +++++++++++++++++++-------------
kernel/bpf/syscall.c | 4 ----
kernel/bpf/verifier.c | 8 ++++++--
16 files changed, 49 insertions(+), 40 deletions(-)
diff --git a/arch/arc/net/bpf_jit_core.c b/arch/arc/net/bpf_jit_core.c
index 12facf5750da..cf708c308adb 100644
--- a/arch/arc/net/bpf_jit_core.c
+++ b/arch/arc/net/bpf_jit_core.c
@@ -153,7 +153,8 @@ static void jit_dump(const struct jit_context *ctx)
}
/* Initialise the context so there's no garbage. */
-static int jit_ctx_init(struct jit_context *ctx, struct bpf_prog *prog)
+static int jit_ctx_init(struct jit_context *ctx, struct bpf_verifier_env *env,
+ struct bpf_prog *prog)
{
memset(ctx, 0, sizeof(*ctx));
@@ -1317,7 +1318,7 @@ static int jit_patch_relocations(struct jit_context *ctx)
* to get the necessary data for the real compilation phase,
* jit_compile().
*/
-static struct bpf_prog *do_normal_pass(struct bpf_prog *prog)
+static struct bpf_prog *do_normal_pass(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct jit_context ctx;
@@ -1325,7 +1326,7 @@ static struct bpf_prog *do_normal_pass(struct bpf_prog *prog)
if (!prog->jit_requested)
return prog;
- if (jit_ctx_init(&ctx, prog)) {
+ if (jit_ctx_init(&ctx, env, prog)) {
jit_ctx_cleanup(&ctx);
return prog;
}
@@ -1356,7 +1357,7 @@ static struct bpf_prog *do_normal_pass(struct bpf_prog *prog)
* again to get the newly translated addresses in order to resolve
* the "call"s.
*/
-static struct bpf_prog *do_extra_pass(struct bpf_prog *prog)
+static struct bpf_prog *do_extra_pass(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct jit_context ctx;
@@ -1364,7 +1365,7 @@ static struct bpf_prog *do_extra_pass(struct bpf_prog *prog)
if (check_jit_context(prog))
return prog;
- if (jit_ctx_init(&ctx, prog)) {
+ if (jit_ctx_init(&ctx, env, prog)) {
jit_ctx_cleanup(&ctx);
return prog;
}
@@ -1393,15 +1394,15 @@ static struct bpf_prog *do_extra_pass(struct bpf_prog *prog)
* (re)locations involved that their addresses are not known
* during the first run.
*/
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
vm_dump(prog);
/* Was this program already translated? */
if (!prog->jited)
- return do_normal_pass(prog);
+ return do_normal_pass(env, prog);
else
- return do_extra_pass(prog);
+ return do_extra_pass(env, prog);
return prog;
}
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index e6b1bb2de627..1628b6fc70a4 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -2142,7 +2142,7 @@ bool bpf_jit_needs_zext(void)
return true;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct bpf_binary_header *header;
struct jit_ctx ctx;
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index c5ed9d84c3ae..0bd16709165e 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -2006,7 +2006,7 @@ struct arm64_jit_data {
struct jit_ctx ctx;
};
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
int image_size, prog_size, extable_size, extable_align, extable_offset;
struct bpf_binary_header *header;
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index 3a5cc3e88424..56e53291b909 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -1909,7 +1909,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
return ret < 0 ? ret : ret * LOONGARCH_INSN_SIZE;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
bool extra_pass = false;
u8 *image_ptr, *ro_image_ptr;
diff --git a/arch/mips/net/bpf_jit_comp.c b/arch/mips/net/bpf_jit_comp.c
index d2b6c955f18e..6ee4abe6a1f7 100644
--- a/arch/mips/net/bpf_jit_comp.c
+++ b/arch/mips/net/bpf_jit_comp.c
@@ -909,7 +909,7 @@ bool bpf_jit_needs_zext(void)
return true;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct bpf_binary_header *header = NULL;
struct jit_context ctx;
diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c
index 4d339636a34a..90d081734d0f 100644
--- a/arch/parisc/net/bpf_jit_core.c
+++ b/arch/parisc/net/bpf_jit_core.c
@@ -41,7 +41,7 @@ bool bpf_jit_needs_zext(void)
return true;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
unsigned int prog_size = 0, extable_size = 0;
bool extra_pass = false;
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 7a7c49640a2f..a6fd7ef249da 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -129,7 +129,7 @@ bool bpf_jit_needs_zext(void)
return true;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *fp)
{
u32 proglen;
u32 alloclen;
diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
index c77e8aba14d3..bffaf584226c 100644
--- a/arch/riscv/net/bpf_jit_core.c
+++ b/arch/riscv/net/bpf_jit_core.c
@@ -41,7 +41,7 @@ bool bpf_jit_needs_zext(void)
return true;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
unsigned int prog_size = 0, extable_size = 0;
bool extra_pass = false;
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index d6de2abfe4a7..061f16d1e3b1 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -2303,7 +2303,7 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
/*
* Compile eBPF program "fp"
*/
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *fp)
{
struct bpf_binary_header *header;
struct s390_jit_data *jit_data;
diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c
index 86abd84d4005..eca9365c72e7 100644
--- a/arch/sparc/net/bpf_jit_comp_64.c
+++ b/arch/sparc/net/bpf_jit_comp_64.c
@@ -1477,7 +1477,7 @@ struct sparc64_jit_data {
struct jit_ctx ctx;
};
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct sparc64_jit_data *jit_data;
struct bpf_binary_header *header;
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index bb8e7541d078..2c57ee446fc9 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -3722,7 +3722,7 @@ struct x64_jit_data {
#define MAX_PASSES 20
#define PADDING_PASSES (MAX_PASSES - 5)
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct bpf_binary_header *rw_header = NULL;
struct bpf_binary_header *header = NULL;
diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
index 5f259577614a..852baf2e4db4 100644
--- a/arch/x86/net/bpf_jit_comp32.c
+++ b/arch/x86/net/bpf_jit_comp32.c
@@ -2518,7 +2518,7 @@ bool bpf_jit_needs_zext(void)
return true;
}
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
struct bpf_binary_header *header = NULL;
int proglen, oldproglen = 0;
diff --git a/include/linux/filter.h b/include/linux/filter.h
index b69369dc3727..6c951bb2ec99 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1108,6 +1108,8 @@ static inline int sk_filter_reason(struct sock *sk, struct sk_buff *skb,
return sk_filter_trim_cap(sk, skb, 1, reason);
}
+struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
+ int *err);
struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err);
void bpf_prog_free(struct bpf_prog *fp);
@@ -1153,7 +1155,7 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
((u64 (*)(u64, u64, u64, u64, u64, const struct bpf_insn *)) \
(void *)__bpf_call_base)
-struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
+struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog);
void bpf_jit_compile(struct bpf_prog *prog);
bool bpf_jit_needs_zext(void);
bool bpf_jit_inlines_helper_call(s32 imm);
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 93150343ac35..741e09b8a2be 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2242,18 +2242,8 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
return select_interpreter;
}
-/**
- * bpf_prog_select_runtime - select exec runtime for BPF program
- * @fp: bpf_prog populated with BPF program
- * @err: pointer to error variable
- *
- * Try to JIT eBPF program, if JIT is not available, use interpreter.
- * The BPF program will be executed via bpf_prog_run() function.
- *
- * Return: the &fp argument along with &err set to 0 for success or
- * a negative errno code on failure
- */
-struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
+struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
+ int *err)
{
/* In case of BPF to BPF calls, verifier did all the prep
* work with regards to JITing, etc.
@@ -2281,7 +2271,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
if (*err)
return fp;
- fp = bpf_int_jit_compile(fp);
+ fp = bpf_int_jit_compile(env, fp);
bpf_prog_jit_attempt_done(fp);
if (!fp->jited && jit_needed) {
*err = -ENOTSUPP;
@@ -2307,6 +2297,22 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
return fp;
}
+
+/**
+ * bpf_prog_select_runtime - select exec runtime for BPF program
+ * @fp: bpf_prog populated with BPF program
+ * @err: pointer to error variable
+ *
+ * Try to JIT eBPF program, if JIT is not available, use interpreter.
+ * The BPF program will be executed via bpf_prog_run() function.
+ *
+ * Return: the &fp argument along with &err set to 0 for success or
+ * a negative errno code on failure
+ */
+struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
+{
+ return __bpf_prog_select_runtime(NULL, fp, err);
+}
EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
static unsigned int __bpf_prog_ret1(const void *ctx,
@@ -2794,7 +2800,7 @@ const struct bpf_func_proto bpf_tail_call_proto = {
* It is encouraged to implement bpf_int_jit_compile() instead, so that
* eBPF and implicitly also cBPF can get JITed!
*/
-struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_prog *prog)
+struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
return prog;
}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 274039e36465..fb07be46c936 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3090,10 +3090,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
if (err < 0)
goto free_used_maps;
- prog = bpf_prog_select_runtime(prog, &err);
- if (err < 0)
- goto free_used_maps;
-
err = bpf_prog_mark_insn_arrays_ready(prog);
if (err < 0)
goto free_used_maps;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e2fffa08cba0..06202ba53aec 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22946,7 +22946,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
func[i]->aux->might_sleep = env->subprog_info[i].might_sleep;
if (!i)
func[i]->aux->exception_boundary = env->seen_exception;
- func[i] = bpf_int_jit_compile(func[i]);
+ func[i] = bpf_int_jit_compile(env, func[i]);
if (!func[i]->jited) {
err = -ENOTSUPP;
goto out_free;
@@ -22990,7 +22990,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
}
for (i = 0; i < env->subprog_cnt; i++) {
old_bpf_func = func[i]->bpf_func;
- tmp = bpf_int_jit_compile(func[i]);
+ tmp = bpf_int_jit_compile(env, func[i]);
if (tmp != func[i] || func[i]->bpf_func != old_bpf_func) {
verbose(env, "JIT doesn't support bpf-to-bpf calls\n");
err = -ENOTSUPP;
@@ -26397,6 +26397,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
convert_pseudo_ld_imm64(env);
}
+ env->prog = __bpf_prog_select_runtime(env, env->prog, &ret);
+ if (ret)
+ goto err_release_maps;
+
adjust_btf_func(env);
err_release_maps:
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [bpf-next v6 3/5] bpf: Add helper to detect indirect jump targets
2026-03-06 10:23 [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit Xu Kuohai
@ 2026-03-06 10:23 ` Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 4/5] bpf, x86: Emit ENDBR for " Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 5/5] bpf, arm64: Emit BTI for indirect jump target Xu Kuohai
4 siblings, 0 replies; 18+ messages in thread
From: Xu Kuohai @ 2026-03-06 10:23 UTC (permalink / raw)
To: bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Shahab Vahedi, Russell King, Tiezhu Yang,
Hengqi Chen, Johan Almbladh, Paul Burton, Hari Bathini,
Christophe Leroy, Naveen N Rao, Luke Nelson, Xi Wang,
Björn Töpel, Pu Lehui, Ilya Leoshkevich, Heiko Carstens,
Vasily Gorbik, David S . Miller, Wang YanQing
From: Xu Kuohai <xukuohai@huawei.com>
Introduce helper bpf_insn_is_indirect_target to check whether a BPF
instruction is an indirect jump target.
Since the verifier knows which instructions are indirect jump targets,
add a new flag indirect_target to struct bpf_insn_aux_data to mark
them. The verifier sets this flag when verifing an indirect jump target
instruction, and the helper checks it to determine whether an
instruction is an indirect jump target.
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
include/linux/bpf.h | 2 ++
include/linux/bpf_verifier.h | 9 +++++----
kernel/bpf/core.c | 9 +++++++++
kernel/bpf/verifier.c | 7 +++++++
4 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 05b34a6355b0..90760e250865 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1541,6 +1541,8 @@ bool bpf_has_frame_pointer(unsigned long ip);
int bpf_jit_charge_modmem(u32 size);
void bpf_jit_uncharge_modmem(u32 size);
bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
+bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
+ int insn_idx);
#else
static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
struct bpf_trampoline *tr,
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 090aa26d1c98..6431b94746cf 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -578,16 +578,17 @@ struct bpf_insn_aux_data {
/* below fields are initialized once */
unsigned int orig_idx; /* original instruction index */
- bool jmp_point;
- bool prune_point;
+ u32 jmp_point:1;
+ u32 prune_point:1;
/* ensure we check state equivalence and save state checkpoint and
* this instruction, regardless of any heuristics
*/
- bool force_checkpoint;
+ u32 force_checkpoint:1;
/* true if instruction is a call to a helper function that
* accepts callback function as a parameter.
*/
- bool calls_callback;
+ u32 calls_callback:1;
+ u32 indirect_target:1; /* if it is an indirect jump target */
/*
* CFG strongly connected component this instruction belongs to,
* zero if it is a singleton SCC.
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 741e09b8a2be..31a57de520af 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1290,6 +1290,15 @@ const char *bpf_jit_get_prog_name(struct bpf_prog *prog)
return prog->aux->ksym.name;
return prog->aux->name;
}
+
+bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
+ int insn_idx)
+{
+ if (!env)
+ return false;
+ insn_idx += prog->aux->subprog_start;
+ return env->insn_aux_data[insn_idx].indirect_target;
+}
#endif /* CONFIG_BPF_JIT */
/* Base function for offset calculation. Needs to go into .text section,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 06202ba53aec..13f34f2dd2b6 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3998,6 +3998,11 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx)
return env->insn_aux_data[insn_idx].jmp_point;
}
+static void mark_indirect_target(struct bpf_verifier_env *env, int idx)
+{
+ env->insn_aux_data[idx].indirect_target = true;
+}
+
#define LR_FRAMENO_BITS 3
#define LR_SPI_BITS 6
#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1)
@@ -21051,12 +21056,14 @@ static int check_indirect_jump(struct bpf_verifier_env *env, struct bpf_insn *in
}
for (i = 0; i < n - 1; i++) {
+ mark_indirect_target(env, env->gotox_tmp_buf->items[i]);
other_branch = push_stack(env, env->gotox_tmp_buf->items[i],
env->insn_idx, env->cur_state->speculative);
if (IS_ERR(other_branch))
return PTR_ERR(other_branch);
}
env->insn_idx = env->gotox_tmp_buf->items[n-1];
+ mark_indirect_target(env, env->insn_idx);
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [bpf-next v6 4/5] bpf, x86: Emit ENDBR for indirect jump targets
2026-03-06 10:23 [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets Xu Kuohai
` (2 preceding siblings ...)
2026-03-06 10:23 ` [bpf-next v6 3/5] bpf: Add helper to detect indirect jump targets Xu Kuohai
@ 2026-03-06 10:23 ` Xu Kuohai
2026-03-07 1:36 ` Eduard Zingerman
2026-03-06 10:23 ` [bpf-next v6 5/5] bpf, arm64: Emit BTI for indirect jump target Xu Kuohai
4 siblings, 1 reply; 18+ messages in thread
From: Xu Kuohai @ 2026-03-06 10:23 UTC (permalink / raw)
To: bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Shahab Vahedi, Russell King, Tiezhu Yang,
Hengqi Chen, Johan Almbladh, Paul Burton, Hari Bathini,
Christophe Leroy, Naveen N Rao, Luke Nelson, Xi Wang,
Björn Töpel, Pu Lehui, Ilya Leoshkevich, Heiko Carstens,
Vasily Gorbik, David S . Miller, Wang YanQing
From: Xu Kuohai <xukuohai@huawei.com>
On CPUs that support CET/IBT, the indirect jump selftest triggers
a kernel panic because the indirect jump targets lack ENDBR
instructions.
To fix it, emit an ENDBR instruction to each indirect jump target. Since
the ENDBR instruction shifts the position of original jited instructions,
fix the instruction address calculation wherever the addresses are used.
For reference, below is a sample panic log.
Missing ENDBR: bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
------------[ cut here ]------------
kernel BUG at arch/x86/kernel/cet.c:133!
Oops: invalid opcode: 0000 [#1] SMP NOPTI
...
? 0xffffffffc00fb258
? bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
bpf_prog_test_run_syscall+0x110/0x2f0
? fdget+0xba/0xe0
__sys_bpf+0xe4b/0x2590
? __kmalloc_node_track_caller_noprof+0x1c7/0x680
? bpf_prog_test_run_syscall+0x215/0x2f0
__x64_sys_bpf+0x21/0x30
do_syscall_64+0x85/0x620
? bpf_prog_test_run_syscall+0x1e2/0x2f0
Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
arch/x86/net/bpf_jit_comp.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 2c57ee446fc9..752331a64fc0 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1658,8 +1658,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
return 0;
}
-static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
- int oldproglen, struct jit_context *ctx, bool jmp_padding)
+static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+ u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
{
bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
struct bpf_insn *insn = bpf_prog->insnsi;
@@ -1743,6 +1743,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
dst_reg = X86_REG_R9;
}
+#ifdef CONFIG_X86_KERNEL_IBT
+ if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
+ EMIT_ENDBR();
+#endif
+
switch (insn->code) {
/* ALU */
case BPF_ALU | BPF_ADD | BPF_X:
@@ -2449,7 +2454,7 @@ st: if (is_imm8(insn->off))
/* call */
case BPF_JMP | BPF_CALL: {
- u8 *ip = image + addrs[i - 1];
+ u8 *ip = image + addrs[i - 1] + (prog - temp);
func = (u8 *) __bpf_call_base + imm32;
if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
@@ -2474,7 +2479,8 @@ st: if (is_imm8(insn->off))
if (imm32)
emit_bpf_tail_call_direct(bpf_prog,
&bpf_prog->aux->poke_tab[imm32 - 1],
- &prog, image + addrs[i - 1],
+ &prog,
+ image + addrs[i - 1] + (prog - temp),
callee_regs_used,
stack_depth,
ctx);
@@ -2483,7 +2489,7 @@ st: if (is_imm8(insn->off))
&prog,
callee_regs_used,
stack_depth,
- image + addrs[i - 1],
+ image + addrs[i - 1] + (prog - temp),
ctx);
break;
@@ -2648,7 +2654,8 @@ st: if (is_imm8(insn->off))
break;
case BPF_JMP | BPF_JA | BPF_X:
- emit_indirect_jump(&prog, insn->dst_reg, image + addrs[i - 1]);
+ emit_indirect_jump(&prog, insn->dst_reg,
+ image + addrs[i - 1] + (prog - temp));
break;
case BPF_JMP | BPF_JA:
case BPF_JMP32 | BPF_JA:
@@ -2738,7 +2745,7 @@ st: if (is_imm8(insn->off))
ctx->cleanup_addr = proglen;
if (bpf_prog_was_classic(bpf_prog) &&
!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
- u8 *ip = image + addrs[i - 1];
+ u8 *ip = image + addrs[i - 1] + (prog - temp);
if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
return -EINVAL;
@@ -3800,7 +3807,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
for (pass = 0; pass < MAX_PASSES || image; pass++) {
if (!padding && pass >= PADDING_PASSES)
padding = true;
- proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
+ proglen = do_jit(env, prog, addrs, image, rw_image, oldproglen, &ctx, padding);
if (proglen <= 0) {
out_image:
image = NULL;
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [bpf-next v6 5/5] bpf, arm64: Emit BTI for indirect jump target
2026-03-06 10:23 [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets Xu Kuohai
` (3 preceding siblings ...)
2026-03-06 10:23 ` [bpf-next v6 4/5] bpf, x86: Emit ENDBR for " Xu Kuohai
@ 2026-03-06 10:23 ` Xu Kuohai
4 siblings, 0 replies; 18+ messages in thread
From: Xu Kuohai @ 2026-03-06 10:23 UTC (permalink / raw)
To: bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Shahab Vahedi, Russell King, Tiezhu Yang,
Hengqi Chen, Johan Almbladh, Paul Burton, Hari Bathini,
Christophe Leroy, Naveen N Rao, Luke Nelson, Xi Wang,
Björn Töpel, Pu Lehui, Ilya Leoshkevich, Heiko Carstens,
Vasily Gorbik, David S . Miller, Wang YanQing
From: Xu Kuohai <xukuohai@huawei.com>
On CPUs that support BTI, the indirect jump selftest triggers a kernel
panic because there is no BTI instructions at the indirect jump targets.
Fix it by emitting a BTI instruction for each indirect jump target.
For reference, below is a sample panic log.
Internal error: Oops - BTI: 0000000036000003 [#1] SMP
...
Call trace:
bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x54/0xf8 (P)
bpf_prog_run_pin_on_cpu+0x140/0x468
bpf_prog_test_run_syscall+0x280/0x3b8
bpf_prog_test_run+0x22c/0x2c0
Fixes: f4a66cf1cb14 ("bpf: arm64: Add support for indirect jumps")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
arch/arm64/net/bpf_jit_comp.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 0bd16709165e..d799ded1b590 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1198,8 +1198,8 @@ static int add_exception_handler(const struct bpf_insn *insn,
* >0 - successfully JITed a 16-byte eBPF instruction.
* <0 - failed to JIT.
*/
-static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
- bool extra_pass)
+static int build_insn(const struct bpf_verifier_env *env, const struct bpf_insn *insn,
+ struct jit_ctx *ctx, bool extra_pass)
{
const u8 code = insn->code;
u8 dst = bpf2a64[insn->dst_reg];
@@ -1224,6 +1224,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
int ret;
bool sign_extend;
+ if (bpf_insn_is_indirect_target(env, ctx->prog, i))
+ emit_bti(A64_BTI_J, ctx);
+
switch (code) {
/* dst = src */
case BPF_ALU | BPF_MOV | BPF_X:
@@ -1899,7 +1902,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
return 0;
}
-static int build_body(struct jit_ctx *ctx, bool extra_pass)
+static int build_body(struct bpf_verifier_env *env, struct jit_ctx *ctx, bool extra_pass)
{
const struct bpf_prog *prog = ctx->prog;
int i;
@@ -1918,7 +1921,7 @@ static int build_body(struct jit_ctx *ctx, bool extra_pass)
int ret;
ctx->offset[i] = ctx->idx;
- ret = build_insn(insn, ctx, extra_pass);
+ ret = build_insn(env, insn, ctx, extra_pass);
if (ret > 0) {
i++;
ctx->offset[i] = ctx->idx;
@@ -2079,7 +2082,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
if (build_prologue(&ctx, was_classic))
goto out_off;
- if (build_body(&ctx, extra_pass))
+ if (build_body(env, &ctx, extra_pass))
goto out_off;
ctx.epilogue_offset = ctx.idx;
@@ -2127,7 +2130,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
/* Dont write body instructions to memory for now */
ctx.write = false;
- if (build_body(&ctx, extra_pass))
+ if (build_body(env, &ctx, extra_pass))
goto out_free_hdr;
ctx.epilogue_offset = ctx.idx;
@@ -2136,7 +2139,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
ctx.write = true;
/* Pass 3: Adjust jump offset and write final image */
- if (build_body(&ctx, extra_pass) ||
+ if (build_body(env, &ctx, extra_pass) ||
WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset))
goto out_free_hdr;
--
2.47.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier
2026-03-06 10:23 ` [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier Xu Kuohai
@ 2026-03-06 10:38 ` bot+bpf-ci
2026-03-06 18:30 ` Alexei Starovoitov
1 sibling, 0 replies; 18+ messages in thread
From: bot+bpf-ci @ 2026-03-06 10:38 UTC (permalink / raw)
To: xukuohai, bpf, linux-kernel, linux-arm-kernel
Cc: ast, daniel, andrii, martin.lau, eddyz87, yonghong.song, puranjay,
a.s.protopopov, list+bpf, linux, yangtiezhu, hengqi.chen,
johan.almbladh, paulburton, hbathini, chleroy, naveen,
luke.r.nels, xi.wang, bjorn, pulehui, iii, hca, gor, davem,
udknight, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song,
clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2374 bytes --]
> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
> index adf84962d579..c5ed9d84c3ae 100644
> --- a/arch/arm64/net/bpf_jit_comp.c
> +++ b/arch/arm64/net/bpf_jit_comp.c
[ ... ]
> @@ -2201,7 +2170,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
> /* ro_header has been freed */
> ro_header = NULL;
> - prog = orig_prog;
> goto out_off;
> }
With the orig_prog fallback removed, if bpf_jit_binary_pack_finalize()
fails on the extra pass, prog->bpf_func and prog->jited still hold
the values set during the first pass. At that point ro_header has been
freed, so bpf_func points to freed memory.
In jit_subprogs() the second loop checks:
old_bpf_func = func[i]->bpf_func;
tmp = bpf_int_jit_compile(func[i]);
if (tmp != func[i] || func[i]->bpf_func != old_bpf_func) {
Since bpf_func is unchanged, this does not detect the failure. The
program continues with jited=1 and a stale bpf_func.
The powerpc and riscv JITs handle this correctly in the same commit:
arch/riscv/net/bpf_jit_core.c:bpf_int_jit_compile():
if (WARN_ON(bpf_jit_binary_pack_finalize(...))) {
jit_data->ro_header = NULL;
prog->bpf_func = NULL;
prog->jited = 0;
prog->jited_len = 0;
goto out_offset;
}
Should the arm64 path also clear bpf_func, jited, and jited_len here
to match?
> diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
> index 3bd89f55960d..3a5cc3e88424 100644
> --- a/arch/loongarch/net/bpf_jit.c
> +++ b/arch/loongarch/net/bpf_jit.c
[ ... ]
> @@ -2041,7 +2014,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
> /* ro_header has been freed */
> ro_header = NULL;
> - prog = orig_prog;
> goto out_free;
> }
Same issue as arm64 above. The loongarch JIT also sets prog->jited and
prog->bpf_func before finalize, and the failure path does not clear
them. Would it make sense to add the same clearing here as well?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/22758822985
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier
2026-03-06 10:23 ` [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier Xu Kuohai
2026-03-06 10:38 ` bot+bpf-ci
@ 2026-03-06 18:30 ` Alexei Starovoitov
2026-03-07 3:10 ` Xu Kuohai
1 sibling, 1 reply; 18+ messages in thread
From: Alexei Starovoitov @ 2026-03-06 18:30 UTC (permalink / raw)
To: Xu Kuohai
Cc: bpf, LKML, linux-arm-kernel, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Yonghong Song, Puranjay Mohan, Anton Protopopov, Shahab Vahedi,
Russell King, Tiezhu Yang, Hengqi Chen, Johan Almbladh,
Paul Burton, Hari Bathini, Christophe Leroy, Naveen N Rao,
Luke Nelson, Xi Wang, Björn Töpel, Pu Lehui,
Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik, David S . Miller,
Wang YanQing
On Fri, Mar 6, 2026 at 1:56 AM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>
> From: Xu Kuohai <xukuohai@huawei.com>
>
> During the JIT stage, constants blinding rewrites instructions but only
> rewrites the private instruction copy of the JITed subprog, leaving the
> global instructions and insn_aux_data unchanged. This causes a mismatch
> between subprog instructions and the global state, making it difficult
> to look up the global insn_aux_data in the JIT.
>
> To avoid this mismatch, and given that all arch-specific JITs already
> support constants blinding, move it to the generic verifier code, and
> switch to rewrite the global env->insnsi with the global states
> adjusted, as other rewrites in the verifier do.
>
> This removes the constant blinding calls in each JIT, which are largely
> duplicated code across architectures.
>
> And the prog clone functions and insn_array adjustment for the JIT
> constant blinding are no longer needed, remove them too.
>
> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> ---
> arch/arc/net/bpf_jit_core.c | 20 +--
> arch/arm/net/bpf_jit_32.c | 41 +----
> arch/arm64/net/bpf_jit_comp.c | 59 ++-----
> arch/loongarch/net/bpf_jit.c | 50 ++----
> arch/mips/net/bpf_jit_comp.c | 20 +--
> arch/parisc/net/bpf_jit_core.c | 38 +----
> arch/powerpc/net/bpf_jit_comp.c | 45 ++----
> arch/riscv/net/bpf_jit_core.c | 45 ++----
> arch/s390/net/bpf_jit_comp.c | 41 +----
> arch/sparc/net/bpf_jit_comp_64.c | 41 +----
> arch/x86/net/bpf_jit_comp.c | 40 +----
> arch/x86/net/bpf_jit_comp32.c | 33 +---
> include/linux/filter.h | 3 -
> kernel/bpf/core.c | 263 -------------------------------
> kernel/bpf/verifier.c | 215 +++++++++++++++++++++++--
> 15 files changed, 288 insertions(+), 666 deletions(-)
JIT changes are fine, but pls don't move main
bpf_jit_blind* logic from core.c.
It makes the diff unnecessary big.
pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 4/5] bpf, x86: Emit ENDBR for indirect jump targets
2026-03-06 10:23 ` [bpf-next v6 4/5] bpf, x86: Emit ENDBR for " Xu Kuohai
@ 2026-03-07 1:36 ` Eduard Zingerman
2026-03-07 3:15 ` Xu Kuohai
0 siblings, 1 reply; 18+ messages in thread
From: Eduard Zingerman @ 2026-03-07 1:36 UTC (permalink / raw)
To: Xu Kuohai, bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
On Fri, 2026-03-06 at 18:23 +0800, Xu Kuohai wrote:
> From: Xu Kuohai <xukuohai@huawei.com>
>
> On CPUs that support CET/IBT, the indirect jump selftest triggers
> a kernel panic because the indirect jump targets lack ENDBR
> instructions.
>
> To fix it, emit an ENDBR instruction to each indirect jump target. Since
> the ENDBR instruction shifts the position of original jited instructions,
> fix the instruction address calculation wherever the addresses are used.
>
> For reference, below is a sample panic log.
>
> Missing ENDBR: bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
> ------------[ cut here ]------------
> kernel BUG at arch/x86/kernel/cet.c:133!
> Oops: invalid opcode: 0000 [#1] SMP NOPTI
>
> ...
>
> ? 0xffffffffc00fb258
> ? bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
> bpf_prog_test_run_syscall+0x110/0x2f0
> ? fdget+0xba/0xe0
> __sys_bpf+0xe4b/0x2590
> ? __kmalloc_node_track_caller_noprof+0x1c7/0x680
> ? bpf_prog_test_run_syscall+0x215/0x2f0
> __x64_sys_bpf+0x21/0x30
> do_syscall_64+0x85/0x620
> ? bpf_prog_test_run_syscall+0x1e2/0x2f0
>
> Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps")
> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> ---
> arch/x86/net/bpf_jit_comp.c | 23 +++++++++++++++--------
> 1 file changed, 15 insertions(+), 8 deletions(-)
>
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 2c57ee446fc9..752331a64fc0 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -1658,8 +1658,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
> return 0;
> }
>
> -static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
> - int oldproglen, struct jit_context *ctx, bool jmp_padding)
> +static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
> + u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
> {
> bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
> struct bpf_insn *insn = bpf_prog->insnsi;
> @@ -1743,6 +1743,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
> dst_reg = X86_REG_R9;
> }
>
> +#ifdef CONFIG_X86_KERNEL_IBT
> + if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
> + EMIT_ENDBR();
> +#endif
> +
> switch (insn->code) {
> /* ALU */
> case BPF_ALU | BPF_ADD | BPF_X:
> @@ -2449,7 +2454,7 @@ st: if (is_imm8(insn->off))
>
> /* call */
> case BPF_JMP | BPF_CALL: {
> - u8 *ip = image + addrs[i - 1];
> + u8 *ip = image + addrs[i - 1] + (prog - temp);
Sorry, meant to reply to v5 but got distracted.
It seems tedious/error prone to have this addend at each location,
would it be possible to move the 'ip' variable calculation outside
of the switch? It appears that at each point there would be no
EMIT invocations between 'ip' computation and usage.
>
> func = (u8 *) __bpf_call_base + imm32;
> if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
> @@ -2474,7 +2479,8 @@ st: if (is_imm8(insn->off))
> if (imm32)
> emit_bpf_tail_call_direct(bpf_prog,
> &bpf_prog->aux->poke_tab[imm32 - 1],
> - &prog, image + addrs[i - 1],
> + &prog,
> + image + addrs[i - 1] + (prog - temp),
> callee_regs_used,
> stack_depth,
> ctx);
> @@ -2483,7 +2489,7 @@ st: if (is_imm8(insn->off))
> &prog,
> callee_regs_used,
> stack_depth,
> - image + addrs[i - 1],
> + image + addrs[i - 1] + (prog - temp),
> ctx);
> break;
>
> @@ -2648,7 +2654,8 @@ st: if (is_imm8(insn->off))
> break;
>
> case BPF_JMP | BPF_JA | BPF_X:
> - emit_indirect_jump(&prog, insn->dst_reg, image + addrs[i - 1]);
> + emit_indirect_jump(&prog, insn->dst_reg,
> + image + addrs[i - 1] + (prog - temp));
> break;
> case BPF_JMP | BPF_JA:
> case BPF_JMP32 | BPF_JA:
> @@ -2738,7 +2745,7 @@ st: if (is_imm8(insn->off))
> ctx->cleanup_addr = proglen;
> if (bpf_prog_was_classic(bpf_prog) &&
> !ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
> - u8 *ip = image + addrs[i - 1];
> + u8 *ip = image + addrs[i - 1] + (prog - temp);
>
> if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
> return -EINVAL;
> @@ -3800,7 +3807,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
> for (pass = 0; pass < MAX_PASSES || image; pass++) {
> if (!padding && pass >= PADDING_PASSES)
> padding = true;
> - proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
> + proglen = do_jit(env, prog, addrs, image, rw_image, oldproglen, &ctx, padding);
> if (proglen <= 0) {
> out_image:
> image = NULL;
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier
2026-03-06 18:30 ` Alexei Starovoitov
@ 2026-03-07 3:10 ` Xu Kuohai
0 siblings, 0 replies; 18+ messages in thread
From: Xu Kuohai @ 2026-03-07 3:10 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, LKML, linux-arm-kernel, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Yonghong Song, Puranjay Mohan, Anton Protopopov, Shahab Vahedi,
Russell King, Tiezhu Yang, Hengqi Chen, Johan Almbladh,
Paul Burton, Hari Bathini, Christophe Leroy, Naveen N Rao,
Luke Nelson, Xi Wang, Björn Töpel, Pu Lehui,
Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik, David S . Miller,
Wang YanQing
On 3/7/2026 2:30 AM, Alexei Starovoitov wrote:
> On Fri, Mar 6, 2026 at 1:56 AM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>>
>> From: Xu Kuohai <xukuohai@huawei.com>
>>
>> During the JIT stage, constants blinding rewrites instructions but only
>> rewrites the private instruction copy of the JITed subprog, leaving the
>> global instructions and insn_aux_data unchanged. This causes a mismatch
>> between subprog instructions and the global state, making it difficult
>> to look up the global insn_aux_data in the JIT.
>>
>> To avoid this mismatch, and given that all arch-specific JITs already
>> support constants blinding, move it to the generic verifier code, and
>> switch to rewrite the global env->insnsi with the global states
>> adjusted, as other rewrites in the verifier do.
>>
>> This removes the constant blinding calls in each JIT, which are largely
>> duplicated code across architectures.
>>
>> And the prog clone functions and insn_array adjustment for the JIT
>> constant blinding are no longer needed, remove them too.
>>
>> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
>> ---
>> arch/arc/net/bpf_jit_core.c | 20 +--
>> arch/arm/net/bpf_jit_32.c | 41 +----
>> arch/arm64/net/bpf_jit_comp.c | 59 ++-----
>> arch/loongarch/net/bpf_jit.c | 50 ++----
>> arch/mips/net/bpf_jit_comp.c | 20 +--
>> arch/parisc/net/bpf_jit_core.c | 38 +----
>> arch/powerpc/net/bpf_jit_comp.c | 45 ++----
>> arch/riscv/net/bpf_jit_core.c | 45 ++----
>> arch/s390/net/bpf_jit_comp.c | 41 +----
>> arch/sparc/net/bpf_jit_comp_64.c | 41 +----
>> arch/x86/net/bpf_jit_comp.c | 40 +----
>> arch/x86/net/bpf_jit_comp32.c | 33 +---
>> include/linux/filter.h | 3 -
>> kernel/bpf/core.c | 263 -------------------------------
>> kernel/bpf/verifier.c | 215 +++++++++++++++++++++++--
>> 15 files changed, 288 insertions(+), 666 deletions(-)
>
> JIT changes are fine, but pls don't move main
> bpf_jit_blind* logic from core.c.
> It makes the diff unnecessary big.
>
ok, will leave it there
> pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 4/5] bpf, x86: Emit ENDBR for indirect jump targets
2026-03-07 1:36 ` Eduard Zingerman
@ 2026-03-07 3:15 ` Xu Kuohai
2026-03-07 3:31 ` Alexei Starovoitov
0 siblings, 1 reply; 18+ messages in thread
From: Xu Kuohai @ 2026-03-07 3:15 UTC (permalink / raw)
To: Eduard Zingerman, bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
On 3/7/2026 9:36 AM, Eduard Zingerman wrote:
> On Fri, 2026-03-06 at 18:23 +0800, Xu Kuohai wrote:
>> From: Xu Kuohai <xukuohai@huawei.com>
>>
>> On CPUs that support CET/IBT, the indirect jump selftest triggers
>> a kernel panic because the indirect jump targets lack ENDBR
>> instructions.
>>
>> To fix it, emit an ENDBR instruction to each indirect jump target. Since
>> the ENDBR instruction shifts the position of original jited instructions,
>> fix the instruction address calculation wherever the addresses are used.
>>
>> For reference, below is a sample panic log.
>>
>> Missing ENDBR: bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
>> ------------[ cut here ]------------
>> kernel BUG at arch/x86/kernel/cet.c:133!
>> Oops: invalid opcode: 0000 [#1] SMP NOPTI
>>
>> ...
>>
>> ? 0xffffffffc00fb258
>> ? bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
>> bpf_prog_test_run_syscall+0x110/0x2f0
>> ? fdget+0xba/0xe0
>> __sys_bpf+0xe4b/0x2590
>> ? __kmalloc_node_track_caller_noprof+0x1c7/0x680
>> ? bpf_prog_test_run_syscall+0x215/0x2f0
>> __x64_sys_bpf+0x21/0x30
>> do_syscall_64+0x85/0x620
>> ? bpf_prog_test_run_syscall+0x1e2/0x2f0
>>
>> Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps")
>> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
>> ---
>> arch/x86/net/bpf_jit_comp.c | 23 +++++++++++++++--------
>> 1 file changed, 15 insertions(+), 8 deletions(-)
>>
>> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
>> index 2c57ee446fc9..752331a64fc0 100644
>> --- a/arch/x86/net/bpf_jit_comp.c
>> +++ b/arch/x86/net/bpf_jit_comp.c
>> @@ -1658,8 +1658,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
>> return 0;
>> }
>>
>> -static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
>> - int oldproglen, struct jit_context *ctx, bool jmp_padding)
>> +static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
>> + u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
>> {
>> bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
>> struct bpf_insn *insn = bpf_prog->insnsi;
>> @@ -1743,6 +1743,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
>> dst_reg = X86_REG_R9;
>> }
>>
>> +#ifdef CONFIG_X86_KERNEL_IBT
>> + if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
>> + EMIT_ENDBR();
>> +#endif
>> +
>> switch (insn->code) {
>> /* ALU */
>> case BPF_ALU | BPF_ADD | BPF_X:
>> @@ -2449,7 +2454,7 @@ st: if (is_imm8(insn->off))
>>
>> /* call */
>> case BPF_JMP | BPF_CALL: {
>> - u8 *ip = image + addrs[i - 1];
>> + u8 *ip = image + addrs[i - 1] + (prog - temp);
>
> Sorry, meant to reply to v5 but got distracted.
> It seems tedious/error prone to have this addend at each location,
> would it be possible to move the 'ip' variable calculation outside
> of the switch? It appears that at each point there would be no
> EMIT invocations between 'ip' computation and usage.
>
Besides the changes shown in this patch, there is another line in the
file computing address using 'image + addrs[i - 1] + (prog - temp)'.
It is at the call to emit_return() in the 'BPF_JMP | BPF_EXIT' case.
But there are indeed EMIT*() invocations before the address copmutation,
so a pre-computed address before the switch statement is stale in
this case.
To fix this, how about introducing a macro for the address computation,
as the following diff (based on this patch) shows:
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1606,6 +1606,8 @@ static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
+#define CURR_IP (image + addrs[i - 1] + (prog - temp))
+
#define __LOAD_TCC_PTR(off) \
EMIT3_off32(0x48, 0x8B, 0x85, off)
/* mov rax, qword ptr [rbp - rounded_stack_depth - 16] */
@@ -2454,7 +2456,7 @@ st: if (is_imm8(insn->off))
/* call */
case BPF_JMP | BPF_CALL: {
- u8 *ip = image + addrs[i - 1] + (prog - temp);
+ u8 *ip = CURR_IP;
func = (u8 *) __bpf_call_base + imm32;
if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
@@ -2480,7 +2482,7 @@ st: if (is_imm8(insn->off))
emit_bpf_tail_call_direct(bpf_prog,
&bpf_prog->aux->poke_tab[imm32 - 1],
&prog,
- image + addrs[i - 1] + (prog - temp),
+ CURR_IP,
callee_regs_used,
stack_depth,
ctx);
@@ -2489,7 +2491,7 @@ st: if (is_imm8(insn->off))
&prog,
callee_regs_used,
stack_depth,
- image + addrs[i - 1] + (prog - temp),
+ CURR_IP,
ctx);
break;
@@ -2654,8 +2656,7 @@ st: if (is_imm8(insn->off))
break;
case BPF_JMP | BPF_JA | BPF_X:
- emit_indirect_jump(&prog, insn->dst_reg,
- image + addrs[i - 1] + (prog - temp));
+ emit_indirect_jump(&prog, insn->dst_reg, CURR_IP);
break;
case BPF_JMP | BPF_JA:
case BPF_JMP32 | BPF_JA:
@@ -2745,7 +2746,7 @@ st: if (is_imm8(insn->off))
ctx->cleanup_addr = proglen;
if (bpf_prog_was_classic(bpf_prog) &&
!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
- u8 *ip = image + addrs[i - 1] + (prog - temp);
+ u8 *ip = CURR_IP;
if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
return -EINVAL;
@@ -2761,7 +2762,7 @@ st: if (is_imm8(insn->off))
EMIT1(0xC9); /* leave */
bpf_prog->aux->ksym.fp_end = prog - temp;
- emit_return(&prog, image + addrs[i - 1] + (prog - temp));
+ emit_return(&prog, CURR_IP);
break;
Would it make sense?
>>
>> func = (u8 *) __bpf_call_base + imm32;
>> if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
>> @@ -2474,7 +2479,8 @@ st: if (is_imm8(insn->off))
>> if (imm32)
>> emit_bpf_tail_call_direct(bpf_prog,
>> &bpf_prog->aux->poke_tab[imm32 - 1],
>> - &prog, image + addrs[i - 1],
>> + &prog,
>> + image + addrs[i - 1] + (prog - temp),
>> callee_regs_used,
>> stack_depth,
>> ctx);
>> @@ -2483,7 +2489,7 @@ st: if (is_imm8(insn->off))
>> &prog,
>> callee_regs_used,
>> stack_depth,
>> - image + addrs[i - 1],
>> + image + addrs[i - 1] + (prog - temp),
>> ctx);
>> break;
>>
>> @@ -2648,7 +2654,8 @@ st: if (is_imm8(insn->off))
>> break;
>>
>> case BPF_JMP | BPF_JA | BPF_X:
>> - emit_indirect_jump(&prog, insn->dst_reg, image + addrs[i - 1]);
>> + emit_indirect_jump(&prog, insn->dst_reg,
>> + image + addrs[i - 1] + (prog - temp));
>> break;
>> case BPF_JMP | BPF_JA:
>> case BPF_JMP32 | BPF_JA:
>> @@ -2738,7 +2745,7 @@ st: if (is_imm8(insn->off))
>> ctx->cleanup_addr = proglen;
>> if (bpf_prog_was_classic(bpf_prog) &&
>> !ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
>> - u8 *ip = image + addrs[i - 1];
>> + u8 *ip = image + addrs[i - 1] + (prog - temp);
>>
>> if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
>> return -EINVAL;
>> @@ -3800,7 +3807,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
>> for (pass = 0; pass < MAX_PASSES || image; pass++) {
>> if (!padding && pass >= PADDING_PASSES)
>> padding = true;
>> - proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
>> + proglen = do_jit(env, prog, addrs, image, rw_image, oldproglen, &ctx, padding);
>> if (proglen <= 0) {
>> out_image:
>> image = NULL;
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 4/5] bpf, x86: Emit ENDBR for indirect jump targets
2026-03-07 3:15 ` Xu Kuohai
@ 2026-03-07 3:31 ` Alexei Starovoitov
2026-03-07 3:56 ` Xu Kuohai
0 siblings, 1 reply; 18+ messages in thread
From: Alexei Starovoitov @ 2026-03-07 3:31 UTC (permalink / raw)
To: Xu Kuohai
Cc: Eduard Zingerman, bpf, LKML, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Yonghong Song,
Puranjay Mohan, Anton Protopopov, Shahab Vahedi, Russell King,
Tiezhu Yang, Hengqi Chen, Johan Almbladh, Paul Burton,
Hari Bathini, Christophe Leroy, Naveen N Rao, Luke Nelson,
Xi Wang, Björn Töpel, Pu Lehui, Ilya Leoshkevich,
Heiko Carstens, Vasily Gorbik, David S . Miller, Wang YanQing
On Fri, Mar 6, 2026 at 7:15 PM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>
> On 3/7/2026 9:36 AM, Eduard Zingerman wrote:
> > On Fri, 2026-03-06 at 18:23 +0800, Xu Kuohai wrote:
> >> From: Xu Kuohai <xukuohai@huawei.com>
> >>
> >> On CPUs that support CET/IBT, the indirect jump selftest triggers
> >> a kernel panic because the indirect jump targets lack ENDBR
> >> instructions.
> >>
> >> To fix it, emit an ENDBR instruction to each indirect jump target. Since
> >> the ENDBR instruction shifts the position of original jited instructions,
> >> fix the instruction address calculation wherever the addresses are used.
> >>
> >> For reference, below is a sample panic log.
> >>
> >> Missing ENDBR: bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
> >> ------------[ cut here ]------------
> >> kernel BUG at arch/x86/kernel/cet.c:133!
> >> Oops: invalid opcode: 0000 [#1] SMP NOPTI
> >>
> >> ...
> >>
> >> ? 0xffffffffc00fb258
> >> ? bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
> >> bpf_prog_test_run_syscall+0x110/0x2f0
> >> ? fdget+0xba/0xe0
> >> __sys_bpf+0xe4b/0x2590
> >> ? __kmalloc_node_track_caller_noprof+0x1c7/0x680
> >> ? bpf_prog_test_run_syscall+0x215/0x2f0
> >> __x64_sys_bpf+0x21/0x30
> >> do_syscall_64+0x85/0x620
> >> ? bpf_prog_test_run_syscall+0x1e2/0x2f0
> >>
> >> Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps")
> >> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> >> ---
> >> arch/x86/net/bpf_jit_comp.c | 23 +++++++++++++++--------
> >> 1 file changed, 15 insertions(+), 8 deletions(-)
> >>
> >> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> >> index 2c57ee446fc9..752331a64fc0 100644
> >> --- a/arch/x86/net/bpf_jit_comp.c
> >> +++ b/arch/x86/net/bpf_jit_comp.c
> >> @@ -1658,8 +1658,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
> >> return 0;
> >> }
> >>
> >> -static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
> >> - int oldproglen, struct jit_context *ctx, bool jmp_padding)
> >> +static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
> >> + u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
> >> {
> >> bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
> >> struct bpf_insn *insn = bpf_prog->insnsi;
> >> @@ -1743,6 +1743,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
> >> dst_reg = X86_REG_R9;
> >> }
> >>
> >> +#ifdef CONFIG_X86_KERNEL_IBT
> >> + if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
> >> + EMIT_ENDBR();
> >> +#endif
> >> +
> >> switch (insn->code) {
> >> /* ALU */
> >> case BPF_ALU | BPF_ADD | BPF_X:
> >> @@ -2449,7 +2454,7 @@ st: if (is_imm8(insn->off))
> >>
> >> /* call */
> >> case BPF_JMP | BPF_CALL: {
> >> - u8 *ip = image + addrs[i - 1];
> >> + u8 *ip = image + addrs[i - 1] + (prog - temp);
> >
> > Sorry, meant to reply to v5 but got distracted.
> > It seems tedious/error prone to have this addend at each location,
> > would it be possible to move the 'ip' variable calculation outside
> > of the switch? It appears that at each point there would be no
> > EMIT invocations between 'ip' computation and usage.
> >
>
> Besides the changes shown in this patch, there is another line in the
> file computing address using 'image + addrs[i - 1] + (prog - temp)'.
>
> It is at the call to emit_return() in the 'BPF_JMP | BPF_EXIT' case.
> But there are indeed EMIT*() invocations before the address copmutation,
> so a pre-computed address before the switch statement is stale in
> this case.
>
> To fix this, how about introducing a macro for the address computation,
> as the following diff (based on this patch) shows:
>
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -1606,6 +1606,8 @@ static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
>
> #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
>
> +#define CURR_IP (image + addrs[i - 1] + (prog - temp))
> +
No. Don't obfuscate it with macro.
I don't like INSN_SZ_DIFF either.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 4/5] bpf, x86: Emit ENDBR for indirect jump targets
2026-03-07 3:31 ` Alexei Starovoitov
@ 2026-03-07 3:56 ` Xu Kuohai
0 siblings, 0 replies; 18+ messages in thread
From: Xu Kuohai @ 2026-03-07 3:56 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Eduard Zingerman, bpf, LKML, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau, Yonghong Song,
Puranjay Mohan, Anton Protopopov, Shahab Vahedi, Russell King,
Tiezhu Yang, Hengqi Chen, Johan Almbladh, Paul Burton,
Hari Bathini, Christophe Leroy, Naveen N Rao, Luke Nelson,
Xi Wang, Björn Töpel, Pu Lehui, Ilya Leoshkevich,
Heiko Carstens, Vasily Gorbik, David S . Miller, Wang YanQing
On 3/7/2026 11:31 AM, Alexei Starovoitov wrote:
> On Fri, Mar 6, 2026 at 7:15 PM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>>
>> On 3/7/2026 9:36 AM, Eduard Zingerman wrote:
>>> On Fri, 2026-03-06 at 18:23 +0800, Xu Kuohai wrote:
>>>> From: Xu Kuohai <xukuohai@huawei.com>
>>>>
>>>> On CPUs that support CET/IBT, the indirect jump selftest triggers
>>>> a kernel panic because the indirect jump targets lack ENDBR
>>>> instructions.
>>>>
>>>> To fix it, emit an ENDBR instruction to each indirect jump target. Since
>>>> the ENDBR instruction shifts the position of original jited instructions,
>>>> fix the instruction address calculation wherever the addresses are used.
>>>>
>>>> For reference, below is a sample panic log.
>>>>
>>>> Missing ENDBR: bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
>>>> ------------[ cut here ]------------
>>>> kernel BUG at arch/x86/kernel/cet.c:133!
>>>> Oops: invalid opcode: 0000 [#1] SMP NOPTI
>>>>
>>>> ...
>>>>
>>>> ? 0xffffffffc00fb258
>>>> ? bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1
>>>> bpf_prog_test_run_syscall+0x110/0x2f0
>>>> ? fdget+0xba/0xe0
>>>> __sys_bpf+0xe4b/0x2590
>>>> ? __kmalloc_node_track_caller_noprof+0x1c7/0x680
>>>> ? bpf_prog_test_run_syscall+0x215/0x2f0
>>>> __x64_sys_bpf+0x21/0x30
>>>> do_syscall_64+0x85/0x620
>>>> ? bpf_prog_test_run_syscall+0x1e2/0x2f0
>>>>
>>>> Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps")
>>>> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
>>>> ---
>>>> arch/x86/net/bpf_jit_comp.c | 23 +++++++++++++++--------
>>>> 1 file changed, 15 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
>>>> index 2c57ee446fc9..752331a64fc0 100644
>>>> --- a/arch/x86/net/bpf_jit_comp.c
>>>> +++ b/arch/x86/net/bpf_jit_comp.c
>>>> @@ -1658,8 +1658,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
>>>> return 0;
>>>> }
>>>>
>>>> -static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
>>>> - int oldproglen, struct jit_context *ctx, bool jmp_padding)
>>>> +static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
>>>> + u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
>>>> {
>>>> bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
>>>> struct bpf_insn *insn = bpf_prog->insnsi;
>>>> @@ -1743,6 +1743,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
>>>> dst_reg = X86_REG_R9;
>>>> }
>>>>
>>>> +#ifdef CONFIG_X86_KERNEL_IBT
>>>> + if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
>>>> + EMIT_ENDBR();
>>>> +#endif
>>>> +
>>>> switch (insn->code) {
>>>> /* ALU */
>>>> case BPF_ALU | BPF_ADD | BPF_X:
>>>> @@ -2449,7 +2454,7 @@ st: if (is_imm8(insn->off))
>>>>
>>>> /* call */
>>>> case BPF_JMP | BPF_CALL: {
>>>> - u8 *ip = image + addrs[i - 1];
>>>> + u8 *ip = image + addrs[i - 1] + (prog - temp);
>>>
>>> Sorry, meant to reply to v5 but got distracted.
>>> It seems tedious/error prone to have this addend at each location,
>>> would it be possible to move the 'ip' variable calculation outside
>>> of the switch? It appears that at each point there would be no
>>> EMIT invocations between 'ip' computation and usage.
>>>
>>
>> Besides the changes shown in this patch, there is another line in the
>> file computing address using 'image + addrs[i - 1] + (prog - temp)'.
>>
>> It is at the call to emit_return() in the 'BPF_JMP | BPF_EXIT' case.
>> But there are indeed EMIT*() invocations before the address copmutation,
>> so a pre-computed address before the switch statement is stale in
>> this case.
>>
>> To fix this, how about introducing a macro for the address computation,
>> as the following diff (based on this patch) shows:
>>
>> --- a/arch/x86/net/bpf_jit_comp.c
>> +++ b/arch/x86/net/bpf_jit_comp.c
>> @@ -1606,6 +1606,8 @@ static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
>>
>> #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
>>
>> +#define CURR_IP (image + addrs[i - 1] + (prog - temp))
>> +
>
> No. Don't obfuscate it with macro.
> I don't like INSN_SZ_DIFF either.
>
>
OK, will use Eduward's approach as is.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit
2026-03-06 10:23 ` [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit Xu Kuohai
@ 2026-03-07 6:40 ` Yeoreum Yun
2026-03-07 6:57 ` Xu Kuohai
0 siblings, 1 reply; 18+ messages in thread
From: Yeoreum Yun @ 2026-03-07 6:40 UTC (permalink / raw)
To: Xu Kuohai
Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
Hi,
[...]
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
Does this also work for bpf_prepare_filter()?
For example, ptp_classifier_init() calls it without invoking bpf_check(),
so there is no env available in that context.
[...]
Thanks.
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit
2026-03-07 6:40 ` Yeoreum Yun
@ 2026-03-07 6:57 ` Xu Kuohai
2026-03-07 7:22 ` Yeoreum Yun
0 siblings, 1 reply; 18+ messages in thread
From: Xu Kuohai @ 2026-03-07 6:57 UTC (permalink / raw)
To: Yeoreum Yun
Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
On 3/7/2026 2:40 PM, Yeoreum Yun wrote:
> Hi,
>
> [...]
>
>> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>
> Does this also work for bpf_prepare_filter()?
> For example, ptp_classifier_init() calls it without invoking bpf_check(),
> so there is no env available in that context.
>
It works. The original bpf_prog_select_runtime() is preserved for
cbpf and test code, and passes NULL env to bpf_int_jit_compile().
> [...]
>
> Thanks.
>
> --
> Sincerely,
> Yeoreum Yun
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit
2026-03-07 6:57 ` Xu Kuohai
@ 2026-03-07 7:22 ` Yeoreum Yun
2026-03-07 7:35 ` Xu Kuohai
0 siblings, 1 reply; 18+ messages in thread
From: Yeoreum Yun @ 2026-03-07 7:22 UTC (permalink / raw)
To: Xu Kuohai
Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
Hi,
> On 3/7/2026 2:40 PM, Yeoreum Yun wrote:
> > Hi,
> >
> > [...]
> >
> > > -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> > > +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
> >
> > Does this also work for bpf_prepare_filter()?
> > For example, ptp_classifier_init() calls it without invoking bpf_check(),
> > so there is no env available in that context.
> >
>
> It works. The original bpf_prog_select_runtime() is preserved for
> cbpf and test code, and passes NULL env to bpf_int_jit_compile().
Yes, I agree it work with the NULL when I see you patch but
I mean I couldn't find out modification in bpf_prepare_filter()
-- bpf_jit_compile(fp) -> bpf_jit_compile(NULL, fp)
>
> > [...]
> >
> > Thanks.
> >
> > --
> > Sincerely,
> > Yeoreum Yun
> >
> >
>
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit
2026-03-07 7:22 ` Yeoreum Yun
@ 2026-03-07 7:35 ` Xu Kuohai
2026-03-07 8:00 ` Yeoreum Yun
0 siblings, 1 reply; 18+ messages in thread
From: Xu Kuohai @ 2026-03-07 7:35 UTC (permalink / raw)
To: Yeoreum Yun
Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
On 3/7/2026 3:22 PM, Yeoreum Yun wrote:
> Hi,
>
>> On 3/7/2026 2:40 PM, Yeoreum Yun wrote:
>>> Hi,
>>>
>>> [...]
>>>
>>>> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>>>> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>>>
>>> Does this also work for bpf_prepare_filter()?
>>> For example, ptp_classifier_init() calls it without invoking bpf_check(),
>>> so there is no env available in that context.
>>>
>>
>> It works. The original bpf_prog_select_runtime() is preserved for
>> cbpf and test code, and passes NULL env to bpf_int_jit_compile().
>
> Yes, I agree it work with the NULL when I see you patch but
> I mean I couldn't find out modification in bpf_prepare_filter()
> -- bpf_jit_compile(fp) -> bpf_jit_compile(NULL, fp)
>
bpf_jit_compile() is the old cbpf jit, no modification is required.
>
>
>
>>
>>> [...]
>>>
>>> Thanks.
>>>
>>> --
>>> Sincerely,
>>> Yeoreum Yun
>>>
>>>
>>
>
> --
> Sincerely,
> Yeoreum Yun
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit
2026-03-07 7:35 ` Xu Kuohai
@ 2026-03-07 8:00 ` Yeoreum Yun
0 siblings, 0 replies; 18+ messages in thread
From: Yeoreum Yun @ 2026-03-07 8:00 UTC (permalink / raw)
To: Xu Kuohai
Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Yonghong Song, Puranjay Mohan, Anton Protopopov,
Shahab Vahedi, Russell King, Tiezhu Yang, Hengqi Chen,
Johan Almbladh, Paul Burton, Hari Bathini, Christophe Leroy,
Naveen N Rao, Luke Nelson, Xi Wang, Björn Töpel,
Pu Lehui, Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik,
David S . Miller, Wang YanQing
> > Yes, I agree it work with the NULL when I see you patch but
> > I mean I couldn't find out modification in bpf_prepare_filter()
> > -- bpf_jit_compile(fp) -> bpf_jit_compile(NULL, fp)
> >
>
> bpf_jit_compile() is the old cbpf jit, no modification is required.
Ah. Thanks. It was not bpf_init_jit_comiple(). Sorry to make noise!
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-03-07 8:01 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-06 10:23 [bpf-next v6 0/5] emit ENDBR/BTI instructions for indirect jump targets Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 1/5] bpf: Move constants blinding from JIT to verifier Xu Kuohai
2026-03-06 10:38 ` bot+bpf-ci
2026-03-06 18:30 ` Alexei Starovoitov
2026-03-07 3:10 ` Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 2/5] bpf: Pass bpf_verifier_env to jit Xu Kuohai
2026-03-07 6:40 ` Yeoreum Yun
2026-03-07 6:57 ` Xu Kuohai
2026-03-07 7:22 ` Yeoreum Yun
2026-03-07 7:35 ` Xu Kuohai
2026-03-07 8:00 ` Yeoreum Yun
2026-03-06 10:23 ` [bpf-next v6 3/5] bpf: Add helper to detect indirect jump targets Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 4/5] bpf, x86: Emit ENDBR for " Xu Kuohai
2026-03-07 1:36 ` Eduard Zingerman
2026-03-07 3:15 ` Xu Kuohai
2026-03-07 3:31 ` Alexei Starovoitov
2026-03-07 3:56 ` Xu Kuohai
2026-03-06 10:23 ` [bpf-next v6 5/5] bpf, arm64: Emit BTI for indirect jump target Xu Kuohai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox