Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/64/bpf: fix tail calls for PCREL addressing

With PCREL addressing, there is no kernel TOC. So, it is not setup in
prologue when PCREL addressing is used. But the number of instructions
to skip on a tail call was not adjusted accordingly. That resulted in
not so obvious failures while using tailcalls. 'tailcalls' selftest
crashed the system with the below call trace:

bpf_test_run+0xe8/0x3cc (unreliable)
bpf_prog_test_run_skb+0x348/0x778
__sys_bpf+0xb04/0x2b00
sys_bpf+0x28/0x38
system_call_exception+0x168/0x340
system_call_vectored_common+0x15c/0x2ec

Also, as bpf programs are always module addresses and a bpf helper in
general is a core kernel text address, using PC relative addressing
often fails with "out of range of pcrel address" error. Switch to
using kernel base for relative addressing to handle this better.

Fixes: 7e3a68be42e1 ("powerpc/64: vmlinux support building with PCREL addresing")
Cc: stable@vger.kernel.org # v6.4+
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240502173205.142794-1-hbathini@linux.ibm.com

authored by

Hari Bathini and committed by
Michael Ellerman
2ecfe59c fae57306

+16 -14
+16 -14
arch/powerpc/net/bpf_jit_comp64.c
··· 202 202 EMIT(PPC_RAW_BLR()); 203 203 } 204 204 205 - static int bpf_jit_emit_func_call_hlp(u32 *image, struct codegen_context *ctx, u64 func) 205 + static int 206 + bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func) 206 207 { 207 208 unsigned long func_addr = func ? ppc_function_entry((void *)func) : 0; 208 209 long reladdr; ··· 212 211 return -EINVAL; 213 212 214 213 if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { 215 - reladdr = func_addr - CTX_NIA(ctx); 214 + reladdr = func_addr - local_paca->kernelbase; 216 215 217 216 if (reladdr >= (long)SZ_8G || reladdr < -(long)SZ_8G) { 218 - pr_err("eBPF: address of %ps out of range of pcrel address.\n", 219 - (void *)func); 217 + pr_err("eBPF: address of %ps out of range of 34-bit relative address.\n", 218 + (void *)func); 220 219 return -ERANGE; 221 220 } 222 - /* pla r12,addr */ 223 - EMIT(PPC_PREFIX_MLS | __PPC_PRFX_R(1) | IMM_H18(reladdr)); 224 - EMIT(PPC_INST_PADDI | ___PPC_RT(_R12) | IMM_L(reladdr)); 225 - EMIT(PPC_RAW_MTCTR(_R12)); 226 - EMIT(PPC_RAW_BCTR()); 227 - 221 + EMIT(PPC_RAW_LD(_R12, _R13, offsetof(struct paca_struct, kernelbase))); 222 + /* Align for subsequent prefix instruction */ 223 + if (!IS_ALIGNED((unsigned long)fimage + CTX_NIA(ctx), 8)) 224 + EMIT(PPC_RAW_NOP()); 225 + /* paddi r12,r12,addr */ 226 + EMIT(PPC_PREFIX_MLS | __PPC_PRFX_R(0) | IMM_H18(reladdr)); 227 + EMIT(PPC_INST_PADDI | ___PPC_RT(_R12) | ___PPC_RA(_R12) | IMM_L(reladdr)); 228 228 } else { 229 229 reladdr = func_addr - kernel_toc_addr(); 230 230 if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { ··· 235 233 236 234 EMIT(PPC_RAW_ADDIS(_R12, _R2, PPC_HA(reladdr))); 237 235 EMIT(PPC_RAW_ADDI(_R12, _R12, PPC_LO(reladdr))); 238 - EMIT(PPC_RAW_MTCTR(_R12)); 239 - EMIT(PPC_RAW_BCTRL()); 240 236 } 237 + EMIT(PPC_RAW_MTCTR(_R12)); 238 + EMIT(PPC_RAW_BCTRL()); 241 239 242 240 return 0; 243 241 } ··· 287 285 int b2p_index = bpf_to_ppc(BPF_REG_3); 288 286 int bpf_tailcall_prologue_size = 8; 289 287 290 - if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2)) 288 + if (!IS_ENABLED(CONFIG_PPC_KERNEL_PCREL) && IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2)) 291 289 bpf_tailcall_prologue_size += 4; /* skip past the toc load */ 292 290 293 291 /* ··· 995 993 return ret; 996 994 997 995 if (func_addr_fixed) 998 - ret = bpf_jit_emit_func_call_hlp(image, ctx, func_addr); 996 + ret = bpf_jit_emit_func_call_hlp(image, fimage, ctx, func_addr); 999 997 else 1000 998 ret = bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr); 1001 999