From: Naveen N. Rao <hidden> Date: 2021-10-01 21:15:49
Various fixes to the eBPF JIT for powerpc, thanks to some new tests
added by Johan. This series fixes all failures in test_bpf on powerpc64.
There are still some failures on powerpc32 to be looked into.
- Naveen
Naveen N. Rao (8):
powerpc/lib: Add helper to check if offset is within conditional
branch range
powerpc/bpf: Validate branch ranges
powerpc/bpf: Handle large branch ranges with BPF_EXIT
powerpc/bpf: Fix BPF_MOD when imm == 1
powerpc/bpf: Fix BPF_SUB when imm == 0x80000000
powerpc/bpf: Limit 'ldbrx' to processors compliant with ISA v2.06
powerpc/security: Add a helper to query stf_barrier type
powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
Ravi Bangoria (1):
powerpc/bpf: Remove unused SEEN_STACK
arch/powerpc/include/asm/code-patching.h | 1 +
arch/powerpc/include/asm/ppc-opcode.h | 1 +
arch/powerpc/include/asm/security_features.h | 5 +
arch/powerpc/kernel/security.c | 5 +
arch/powerpc/lib/code-patching.c | 7 +-
arch/powerpc/net/bpf_jit.h | 39 ++++---
arch/powerpc/net/bpf_jit64.h | 8 +-
arch/powerpc/net/bpf_jit_comp.c | 28 ++++-
arch/powerpc/net/bpf_jit_comp32.c | 10 +-
arch/powerpc/net/bpf_jit_comp64.c | 113 ++++++++++++++-----
10 files changed, 167 insertions(+), 50 deletions(-)
base-commit: 044c2d99d9f43c6d6fde8bed00672517dd9a5a57
--
2.33.0
From: Naveen N. Rao <hidden> Date: 2021-10-01 21:15:50
Add a helper to check if a given offset is within the branch range for a
powerpc conditional branch instruction, and update some sites to use the
new helper.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/include/asm/code-patching.h | 1 +
arch/powerpc/lib/code-patching.c | 7 ++++++-
arch/powerpc/net/bpf_jit.h | 7 +------
3 files changed, 8 insertions(+), 7 deletions(-)
@@ -280,7 +285,7 @@ int create_cond_branch(struct ppc_inst *instr, const u32 *addr,offset=offset-(unsignedlong)addr;/* Check we can represent the target in the instruction format */-if(offset<-0x8000||offset>0x7FFF||offset&0x3)+if(!is_offset_in_cond_branch_range(offset))return1;/* Mask out the flags and target, so they don't step on each other. */
@@ -210,7 +210,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)/* Now build the prologue, body code & epilogue for real. */cgctx.idx=0;bpf_jit_build_prologue(code_base,&cgctx);-bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);+if(bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass)){+bpf_jit_binary_free(bpf_hdr);+fp=org_fp;+gotoout_addrs;+}bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
From: Naveen N. Rao <hidden> Date: 2021-10-01 21:15:58
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/net/bpf_jit.h | 3 +++
arch/powerpc/net/bpf_jit_comp.c | 22 +++++++++++++++++++++-
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
@@ -852,7 +852,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,tmp_reg,exit_addr);/* else fall through to the epilogue */break;
@@ -761,7 +761,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,b2p[TMP_REG_1],exit_addr);/* else fall through to the epilogue */break;
@@ -601,17 +601,21 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *EMIT(PPC_RAW_MR(dst_reg,b2p[TMP_REG_1]));break;case64:-/*-*Wayeasierandfaster(?)tostorethevalue-*intostackandthenuseldbrx-*-*ctx->seenwillbereliableinpass2,but-*theinstructionsgeneratedwillremainthe-*sameacrossallpasses-*/+/* Store the value to stack and then use byte-reverse loads */PPC_BPF_STL(dst_reg,1,bpf_jit_stack_local(ctx));EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1],1,bpf_jit_stack_local(ctx)));-EMIT(PPC_RAW_LDBRX(dst_reg,0,b2p[TMP_REG_1]));+if(cpu_has_feature(CPU_FTR_ARCH_206)){+EMIT(PPC_RAW_LDBRX(dst_reg,0,b2p[TMP_REG_1]));+}else{+EMIT(PPC_RAW_LWBRX(dst_reg,0,b2p[TMP_REG_1]));+if(IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))+EMIT(PPC_RAW_SLDI(dst_reg,dst_reg,32));+EMIT(PPC_RAW_LI(b2p[TMP_REG_2],4));+EMIT(PPC_RAW_LWBRX(b2p[TMP_REG_2],b2p[TMP_REG_2],b2p[TMP_REG_1]));+if(IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))+EMIT(PPC_RAW_SLDI(b2p[TMP_REG_2],b2p[TMP_REG_2],32));+EMIT(PPC_RAW_OR(dst_reg,dst_reg,b2p[TMP_REG_2]));+}break;}break;
From: Naveen N. Rao <hidden> Date: 2021-10-01 21:16:15
Emit similar instruction sequences to commit a048a07d7f4535
("powerpc/64s: Add support for a store forwarding barrier at kernel
entry/exit") when encountering BPF_NOSPEC.
Mitigations are enabled depending on what the firmware advertises. In
particular, we do not gate these mitigations based on current settings,
just like in x86. Due to this, we don't need to take any action if
mitigations are enabled or disabled at runtime.
Signed-off-by: Naveen N. Rao <redacted>
---
Thanks to Daniel Borkmann and Nick Piggin for their help in putting
together this patch!
arch/powerpc/net/bpf_jit64.h | 8 ++---
arch/powerpc/net/bpf_jit_comp64.c | 55 ++++++++++++++++++++++++++++---
2 files changed, 55 insertions(+), 8 deletions(-)
From: Naveen N. Rao <hidden> Date: 2021-10-01 21:17:02
Add a helper to return the stf_barrier type for the current processor.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/include/asm/security_features.h | 5 +++++
arch/powerpc/kernel/security.c | 5 +++++
2 files changed, 10 insertions(+)
@@ -263,6 +263,11 @@ static int __init handle_no_stf_barrier(char *p)early_param("no_stf_barrier",handle_no_stf_barrier);+enumstf_barrier_typestf_barrier_type_get(void)+{+returnstf_enabled_flush_types;+}+/* This is the generic flag used by other architectures */staticint__inithandle_ssbd(char*p){
From: Song Liu <song@kernel.org> Date: 2021-10-01 21:37:47
On Fri, Oct 1, 2021 at 2:16 PM Naveen N. Rao
[off-list ref] wrote:
Add a helper to check if a given offset is within the branch range for a
powerpc conditional branch instruction, and update some sites to use the
new helper.
Signed-off-by: Naveen N. Rao <redacted>
+
/*
* Helper to check if a given instruction is a conditional branch
* Derived from the conditional checks in analyse_instr()
@@ -280,7 +285,7 @@ int create_cond_branch(struct ppc_inst *instr, const u32 *addr, offset = offset - (unsigned long)addr; /* Check we can represent the target in the instruction format */- if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3)+ if (!is_offset_in_cond_branch_range(offset)) return 1; /* Mask out the flags and target, so they don't step on each other. */
From: Song Liu <song@kernel.org> Date: 2021-10-01 21:45:51
On Fri, Oct 1, 2021 at 2:16 PM Naveen N. Rao
[off-list ref] wrote:
Add checks to ensure that we never emit branch instructions with
truncated branch offsets.
Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Naveen N. Rao <redacted>
@@ -210,7 +210,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)/* Now build the prologue, body code & epilogue for real. */cgctx.idx=0;bpf_jit_build_prologue(code_base,&cgctx);-bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);+if(bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass)){+bpf_jit_binary_free(bpf_hdr);+fp=org_fp;+gotoout_addrs;+}bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
From: Song Liu <song@kernel.org> Date: 2021-10-01 21:47:23
On Fri, Oct 1, 2021 at 2:16 PM Naveen N. Rao
[off-list ref] wrote:
From: Ravi Bangoria <redacted>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Signed-off-by: Ravi Bangoria <redacted>
Reviewed-by: Christophe Leroy <redacted>
From: Song Liu <song@kernel.org> Date: 2021-10-01 21:54:12
On Fri, Oct 1, 2021 at 2:17 PM Naveen N. Rao
[off-list ref] wrote:
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
@@ -852,7 +852,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,tmp_reg,exit_addr);/* else fall through to the epilogue */break;
@@ -761,7 +761,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,b2p[TMP_REG_1],exit_addr);/* else fall through to the epilogue */break;--
From: Song Liu <song@kernel.org> Date: 2021-10-01 21:55:24
On Fri, Oct 1, 2021 at 2:16 PM Naveen N. Rao
[off-list ref] wrote:
Only ignore the operation if dividing by 1.
Fixes: 156d0e290e969c ("powerpc/ebpf/jit: Implement JIT compiler for extended BPF")
Signed-off-by: Naveen N. Rao <redacted>
From: Song Liu <song@kernel.org> Date: 2021-10-01 22:01:22
On Fri, Oct 1, 2021 at 2:17 PM Naveen N. Rao
[off-list ref] wrote:
We aren't handling subtraction involving an immediate value of
0x80000000 properly. Fix the same.
Fixes: 156d0e290e969c ("powerpc/ebpf/jit: Implement JIT compiler for extended BPF")
Signed-off-by: Naveen N. Rao <redacted>
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:29:35
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
Add checks to ensure that we never emit branch instructions with
truncated branch offsets.
Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Naveen N. Rao <redacted>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
@@ -210,7 +210,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)/* Now build the prologue, body code & epilogue for real. */cgctx.idx=0;bpf_jit_build_prologue(code_base,&cgctx);-bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);+if(bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass)){+bpf_jit_binary_free(bpf_hdr);+fp=org_fp;+gotoout_addrs;+}bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:30:42
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
From: Ravi Bangoria <redacted>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Signed-off-by: Ravi Bangoria <redacted>
Reviewed-by: Christophe Leroy <redacted>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:31:48
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
@@ -852,7 +852,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,tmp_reg,exit_addr);/* else fall through to the epilogue */break;
@@ -761,7 +761,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,b2p[TMP_REG_1],exit_addr);/* else fall through to the epilogue */break;--
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:32:28
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
Only ignore the operation if dividing by 1.
Fixes: 156d0e290e969c ("powerpc/ebpf/jit: Implement JIT compiler for extended BPF")
Signed-off-by: Naveen N. Rao <redacted>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:33:54
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
We aren't handling subtraction involving an immediate value of
0x80000000 properly. Fix the same.
Fixes: 156d0e290e969c ("powerpc/ebpf/jit: Implement JIT compiler for extended BPF")
Signed-off-by: Naveen N. Rao <redacted>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:35:23
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
Johan reported the below crash with test_bpf on ppc64 e5500:
test_bpf: #296 ALU_END_FROM_LE 64: 0x0123456789abcdef -> 0x67452301 jited:1
Oops: Exception in kernel mode, sig: 4 [#1]
BE PAGE_SIZE=4K SMP NR_CPUS=24 QEMU e500
Modules linked in: test_bpf(+)
CPU: 0 PID: 76 Comm: insmod Not tainted 5.14.0-03771-g98c2059e008a-dirty #1
NIP: 8000000000061c3c LR: 80000000006dea64 CTR: 8000000000061c18
REGS: c0000000032d3420 TRAP: 0700 Not tainted (5.14.0-03771-g98c2059e008a-dirty)
MSR: 0000000080089000 <EE,ME> CR: 88002822 XER: 20000000 IRQMASK: 0
<...>
NIP [8000000000061c3c] 0x8000000000061c3c
LR [80000000006dea64] .__run_one+0x104/0x17c [test_bpf]
Call Trace:
.__run_one+0x60/0x17c [test_bpf] (unreliable)
.test_bpf_init+0x6a8/0xdc8 [test_bpf]
.do_one_initcall+0x6c/0x28c
.do_init_module+0x68/0x28c
.load_module+0x2460/0x2abc
.__do_sys_init_module+0x120/0x18c
.system_call_exception+0x110/0x1b8
system_call_common+0xf0/0x210
--- interrupt: c00 at 0x101d0acc
<...>
---[ end trace 47b2bf19090bb3d0 ]---
Illegal instruction
The illegal instruction turned out to be 'ldbrx' emitted for
BPF_FROM_[L|B]E, which was only introduced in ISA v2.06. Guard use of
the same and implement an alternative approach for older processors.
Fixes: 156d0e290e969c ("powerpc/ebpf/jit: Implement JIT compiler for extended BPF")
Reported-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Signed-off-by: Naveen N. Rao <redacted>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
@@ -601,17 +601,21 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *EMIT(PPC_RAW_MR(dst_reg,b2p[TMP_REG_1]));break;case64:-/*-*Wayeasierandfaster(?)tostorethevalue-*intostackandthenuseldbrx-*-*ctx->seenwillbereliableinpass2,but-*theinstructionsgeneratedwillremainthe-*sameacrossallpasses-*/+/* Store the value to stack and then use byte-reverse loads */PPC_BPF_STL(dst_reg,1,bpf_jit_stack_local(ctx));EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1],1,bpf_jit_stack_local(ctx)));-EMIT(PPC_RAW_LDBRX(dst_reg,0,b2p[TMP_REG_1]));+if(cpu_has_feature(CPU_FTR_ARCH_206)){+EMIT(PPC_RAW_LDBRX(dst_reg,0,b2p[TMP_REG_1]));+}else{+EMIT(PPC_RAW_LWBRX(dst_reg,0,b2p[TMP_REG_1]));+if(IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))+EMIT(PPC_RAW_SLDI(dst_reg,dst_reg,32));+EMIT(PPC_RAW_LI(b2p[TMP_REG_2],4));+EMIT(PPC_RAW_LWBRX(b2p[TMP_REG_2],b2p[TMP_REG_2],b2p[TMP_REG_1]));+if(IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))+EMIT(PPC_RAW_SLDI(b2p[TMP_REG_2],b2p[TMP_REG_2],32));+EMIT(PPC_RAW_OR(dst_reg,dst_reg,b2p[TMP_REG_2]));+}break;}break;--
From: Johan Almbladh <johan.almbladh@anyfinetworks.com> Date: 2021-10-02 17:41:16
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
Various fixes to the eBPF JIT for powerpc, thanks to some new tests
added by Johan. This series fixes all failures in test_bpf on powerpc64.
There are still some failures on powerpc32 to be looked into.
Great work! I have tested it on powerpc64 in QEMU, which is the same
setup that previously triggered an illegal instruction, and all tests
pass now. On powerpc32 there are still some issues left as you say.
Thanks!
Johan
- Naveen
Naveen N. Rao (8):
powerpc/lib: Add helper to check if offset is within conditional
branch range
powerpc/bpf: Validate branch ranges
powerpc/bpf: Handle large branch ranges with BPF_EXIT
powerpc/bpf: Fix BPF_MOD when imm == 1
powerpc/bpf: Fix BPF_SUB when imm == 0x80000000
powerpc/bpf: Limit 'ldbrx' to processors compliant with ISA v2.06
powerpc/security: Add a helper to query stf_barrier type
powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
Ravi Bangoria (1):
powerpc/bpf: Remove unused SEEN_STACK
arch/powerpc/include/asm/code-patching.h | 1 +
arch/powerpc/include/asm/ppc-opcode.h | 1 +
arch/powerpc/include/asm/security_features.h | 5 +
arch/powerpc/kernel/security.c | 5 +
arch/powerpc/lib/code-patching.c | 7 +-
arch/powerpc/net/bpf_jit.h | 39 ++++---
arch/powerpc/net/bpf_jit64.h | 8 +-
arch/powerpc/net/bpf_jit_comp.c | 28 ++++-
arch/powerpc/net/bpf_jit_comp32.c | 10 +-
arch/powerpc/net/bpf_jit_comp64.c | 113 ++++++++++++++-----
10 files changed, 167 insertions(+), 50 deletions(-)
base-commit: 044c2d99d9f43c6d6fde8bed00672517dd9a5a57
--
2.33.0
@@ -210,7 +210,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)/* Now build the prologue, body code & epilogue for real. */cgctx.idx=0;bpf_jit_build_prologue(code_base,&cgctx);-bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);+if(bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass)){+bpf_jit_binary_free(bpf_hdr);+fp=org_fp;+gotoout_addrs;+}bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
Add a helper to check if a given offset is within the branch range for a
powerpc conditional branch instruction, and update some sites to use the
new helper.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/include/asm/code-patching.h | 1 +
arch/powerpc/lib/code-patching.c | 7 ++++++-
arch/powerpc/net/bpf_jit.h | 7 +------
3 files changed, 8 insertions(+), 7 deletions(-)
Would be better without capital letters in numbers, in extenso 0x7fff
instead of 0x7FFF
quoted hunk
+
/*
* Helper to check if a given instruction is a conditional branch
* Derived from the conditional checks in analyse_instr()
@@ -280,7 +285,7 @@ int create_cond_branch(struct ppc_inst *instr, const u32 *addr, offset = offset - (unsigned long)addr; /* Check we can represent the target in the instruction format */- if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3)+ if (!is_offset_in_cond_branch_range(offset)) return 1; /* Mask out the flags and target, so they don't step on each other. */
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/net/bpf_jit.h | 3 +++
arch/powerpc/net/bpf_jit_comp.c | 22 +++++++++++++++++++++-
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
@@ -761,7 +761,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context **we'lljustfallthroughtotheepilogue.*/if(i!=flen-1)-PPC_JMP(exit_addr);+bpf_jit_emit_exit_insn(image,ctx,b2p[TMP_REG_1],exit_addr);/* else fall through to the epilogue */break;
There is now so few code common to both BPF_ADD and BPF_SUB that you
should make them different cases.
While at it, why not also use ADDIS if imm is 32 bits ? That would be an
ADDIS/ADDI instead of LIS/ORI/ADD
From: Naveen N. Rao <hidden> Date: 2021-10-04 18:02:40
Hi Song,
Thanks for the reviews.
Song Liu wrote:
On Fri, Oct 1, 2021 at 2:16 PM Naveen N. Rao
[off-list ref] wrote:
quoted
Add a helper to check if a given offset is within the branch range for a
powerpc conditional branch instruction, and update some sites to use the
new helper.
Signed-off-by: Naveen N. Rao <redacted>
Good point. This was modeled after the existing
is_offset_in_branch_range(), and I guess both of those helpers can be
inlined. I'll do a separate patch for that.
- Naveen
From: Naveen N. Rao <hidden> Date: 2021-10-04 18:03:55
Hi Christophe,
Thanks for the reviews.
Christophe Leroy wrote:
Le 01/10/2021 à 23:14, Naveen N. Rao a écrit :
quoted
Add a helper to check if a given offset is within the branch range for a
powerpc conditional branch instruction, and update some sites to use the
new helper.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/include/asm/code-patching.h | 1 +
arch/powerpc/lib/code-patching.c | 7 ++++++-
arch/powerpc/net/bpf_jit.h | 7 +------
3 files changed, 8 insertions(+), 7 deletions(-)
@@ -24,16 +24,30 @@#define EMIT(instr) PLANT_INSTR(image, ctx->idx, instr)/* Long jump; (unconditional 'branch') */-#define PPC_JMP(dest) EMIT(PPC_INST_BRANCH | \-(((dest)-(ctx->idx*4))&0x03fffffc))+#define PPC_JMP(dest) \+do{\+longoffset=(long)(dest)-(ctx->idx*4);\+if(!is_offset_in_branch_range(offset)){\+pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n",offset,ctx->idx);\
Does it really deserves a KERN_ERR ?
The intent is to ensure that we handle this when JIT'ing the BPF
instruction. One of the subsequent patches fixes the only scenario where
we can hit this today. In practice, we should never hit this and if we
do see this, then it is a bug with the JIT.
Isn't that something that can trigger with a userland request ?
This can't be triggered by unprivileged BPF programs since those are
limited to 4096 BPF instructions. You need root privileges to load large
enough BPF programs that can trigger out of range branches.
- Naveen
There is now so few code common to both BPF_ADD and BPF_SUB that you
should make them different cases.
While at it, why not also use ADDIS if imm is 32 bits ? That would be an
ADDIS/ADDI instead of LIS/ORI/ADD
Sure. I wanted to limit the change for this fix. We can do a separate
patch to optimize code generation for BPF_ADD.
- Naveen
From: Naveen N. Rao <hidden> Date: 2021-10-04 18:19:50
Hi Johan,
Johan Almbladh wrote:
On Fri, Oct 1, 2021 at 11:15 PM Naveen N. Rao
[off-list ref] wrote:
quoted
Various fixes to the eBPF JIT for powerpc, thanks to some new tests
added by Johan. This series fixes all failures in test_bpf on powerpc64.
There are still some failures on powerpc32 to be looked into.
Great work! I have tested it on powerpc64 in QEMU, which is the same
setup that previously triggered an illegal instruction, and all tests
pass now. On powerpc32 there are still some issues left as you say.
From: Naveen N. Rao <hidden> Date: 2021-10-04 18:25:23
Christophe Leroy wrote:
Le 01/10/2021 à 23:14, Naveen N. Rao a écrit :
quoted
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/net/bpf_jit.h | 3 +++
arch/powerpc/net/bpf_jit_comp.c | 22 +++++++++++++++++++++-
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
On ppc32, if you use tmp_reg you must flag it. But I think you could use
r0 instead.
Indeed. Can we drop tracking of the temp registers and using them while
remapping registers? Are you seeing significant benefits with re-use of
those temp registers?
- Naveen
There is now so few code common to both BPF_ADD and BPF_SUB that you
should make them different cases.
While at it, why not also use ADDIS if imm is 32 bits ? That would be
an ADDIS/ADDI instead of LIS/ORI/ADD
Sure. I wanted to limit the change for this fix. We can do a separate
patch to optimize code generation for BPF_ADD.
Sure, this second part was just a thought, I agree it should be another
patch.
My main comment here is to split stuff and make it a different case, I
don't think it increases the change much, and IMO it is easier to read:
diff --git a/arch/powerpc/net/bpf_jit_comp64.c
b/arch/powerpc/net/bpf_jit_comp64.c
index ffb7a2877a84..39226d88c558 100644
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/net/bpf_jit.h | 3 +++
arch/powerpc/net/bpf_jit_comp.c | 22 +++++++++++++++++++++-
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
bpf_prog *fp)
goto out_addrs;
}
+ if (!is_offset_in_branch_range((long)cgctx.idx * 4))
+ cgctx.seen |= SEEN_BIG_PROG;
+
/*
* If we have seen a tail call, we need a second pass.
* This is because bpf_jit_emit_common_epilogue() is called
* from bpf_jit_emit_tail_call() with a not yet stable ctx->seen.
+ * We also need a second pass if we ended up with too large
+ * a program so as to fix branches.
*/
- if (cgctx.seen & SEEN_TAILCALL) {
+ if (cgctx.seen & (SEEN_TAILCALL | SEEN_BIG_PROG)) {
cgctx.idx = 0;
if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) {
fp = org_fp;
diff --git a/arch/powerpc/net/bpf_jit_comp32.c
b/arch/powerpc/net/bpf_jit_comp32.c
index a74d52204f8da2..d2a67574a23066 100644
@@ -852,7 +852,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32
*image, struct codegen_context *
* we'll just fall through to the epilogue.
*/
if (i != flen - 1)
- PPC_JMP(exit_addr);
+ bpf_jit_emit_exit_insn(image, ctx, tmp_reg, exit_addr);
On ppc32, if you use tmp_reg you must flag it. But I think you could
use r0 instead.
Indeed. Can we drop tracking of the temp registers and using them while
remapping registers? Are you seeing significant benefits with re-use of
those temp registers?
I'm not sure to follow you.
On ppc32, all volatile registers are used for function arguments, so
temp registers are necessarily non-volatile so we track them as all
non-volatile registers we use.
I think saving on stack only the non-volatile registers we use provides
real benefit, otherwise you wouldn't have implemented it would you ?
Anyway here you should use _R0 instead of tmp_reg.
Christophe
From: Ravi Bangoria <redacted>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Why change SEEN_TAILCALL ? Would it be a problem to leave it as is ?
quoted
Signed-off-by: Ravi Bangoria <redacted>
Reviewed-by: Christophe Leroy <redacted>
I prefer the bit usage to be contiguous. Changing SEEN_TAILCALL isn't a
problem either.
Well you are adding SEEN_BIG_PROG in following patch so it would still
be contiguous at the end.
I don't really mind but I thought it would be less churn to just leave
SEEN_TAILCALL as is and re-use 0x40000000 for SEEN_BIG_PROG.
Anyway
Reviewed-by: Christophe Leroy <redacted>
From: Naveen N. Rao <hidden> Date: 2021-10-05 20:22:35
Christophe Leroy wrote:
Le 04/10/2021 à 20:11, Naveen N. Rao a écrit :
quoted
Christophe Leroy wrote:
quoted
Le 01/10/2021 à 23:14, Naveen N. Rao a écrit :
quoted
From: Ravi Bangoria <redacted>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Why change SEEN_TAILCALL ? Would it be a problem to leave it as is ?
quoted
Signed-off-by: Ravi Bangoria <redacted>
Reviewed-by: Christophe Leroy <redacted>
I prefer the bit usage to be contiguous. Changing SEEN_TAILCALL isn't a
problem either.
Well you are adding SEEN_BIG_PROG in following patch so it would still
be contiguous at the end.
I don't really mind but I thought it would be less churn to just leave
SEEN_TAILCALL as is and re-use 0x40000000 for SEEN_BIG_PROG.
Ah ok. This patch was from a different series and it made more sense to
change the bit number there. I have reused the patch here as-is since
the change is fairly trivial.
- Naveen
From: Naveen N. Rao <hidden> Date: 2022-01-07 11:46:35
Christophe Leroy wrote:
Le 04/10/2021 à 20:24, Naveen N. Rao a écrit :
quoted
Christophe Leroy wrote:
quoted
Le 01/10/2021 à 23:14, Naveen N. Rao a écrit :
quoted
In some scenarios, it is possible that the program epilogue is outside
the branch range for a BPF_EXIT instruction. Instead of rejecting such
programs, emit an indirect branch. We track the size of the bpf program
emitted after the initial run and do a second pass since BPF_EXIT can
end up emitting different number of instructions depending on the
program size.
Suggested-by: Jordan Niethe <redacted>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/net/bpf_jit.h | 3 +++
arch/powerpc/net/bpf_jit_comp.c | 22 +++++++++++++++++++++-
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
bpf_prog *fp)
goto out_addrs;
}
+ if (!is_offset_in_branch_range((long)cgctx.idx * 4))
+ cgctx.seen |= SEEN_BIG_PROG;
+
/*
* If we have seen a tail call, we need a second pass.
* This is because bpf_jit_emit_common_epilogue() is called
* from bpf_jit_emit_tail_call() with a not yet stable ctx->seen.
+ * We also need a second pass if we ended up with too large
+ * a program so as to fix branches.
*/
- if (cgctx.seen & SEEN_TAILCALL) {
+ if (cgctx.seen & (SEEN_TAILCALL | SEEN_BIG_PROG)) {
cgctx.idx = 0;
if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) {
fp = org_fp;
diff --git a/arch/powerpc/net/bpf_jit_comp32.c
b/arch/powerpc/net/bpf_jit_comp32.c
index a74d52204f8da2..d2a67574a23066 100644
@@ -852,7 +852,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32
*image, struct codegen_context *
* we'll just fall through to the epilogue.
*/
if (i != flen - 1)
- PPC_JMP(exit_addr);
+ bpf_jit_emit_exit_insn(image, ctx, tmp_reg, exit_addr);
On ppc32, if you use tmp_reg you must flag it. But I think you could
use r0 instead.
Indeed. Can we drop tracking of the temp registers and using them while
remapping registers? Are you seeing significant benefits with re-use of
those temp registers?
I'm not sure to follow you.
On ppc32, all volatile registers are used for function arguments, so
temp registers are necessarily non-volatile so we track them as all
non-volatile registers we use.
I think saving on stack only the non-volatile registers we use provides
real benefit, otherwise you wouldn't have implemented it would you ?
You're right. I was wary of having to track temporary register usage,
which is a bit harder and prone to mistakes like the above. A related
concern was that the register remapping is only used if there are no
helper calls, which looks like a big limitation.
But, I do agree that it is worth the trouble for ppc32 given the
register usage.
Anyway here you should use _R0 instead of tmp_reg.