return true;
}
+static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
+{
+ int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
+ u64 *stack_ptr;
+
+ for_each_possible_cpu(cpu) {
+ stack_ptr = per_cpu_ptr(priv_stack_ptr, cpu);
+ stack_ptr[0] = PRIV_STACK_GUARD_VAL;
+ stack_ptr[1] = PRIV_STACK_GUARD_VAL;
+ stack_ptr[underflow_idx] = PRIV_STACK_GUARD_VAL;
+ stack_ptr[underflow_idx + 1] = PRIV_STACK_GUARD_VAL;
+ }
+}
+
+static void priv_stack_check_guard(void __percpu *priv_stack_ptr, int alloc_size,
+ struct bpf_prog *fp)
+{
+ int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
+ u64 *stack_ptr;
+
+ for_each_possible_cpu(cpu) {
+ stack_ptr = per_cpu_ptr(priv_stack_ptr, cpu);
+ if (stack_ptr[0] != PRIV_STACK_GUARD_VAL ||
+ stack_ptr[1] != PRIV_STACK_GUARD_VAL ||
+ stack_ptr[underflow_idx] != PRIV_STACK_GUARD_VAL ||
+ stack_ptr[underflow_idx + 1] != PRIV_STACK_GUARD_VAL) {
+ pr_err("BPF private stack overflow/underflow detected for prog %s\n",
+ bpf_jit_get_prog_name(fp));
+ break;
+ }
+ }
+}
+
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
{
u32 proglen;
u32 alloclen;
u8 *image = NULL;
- u32 *code_base;
- u32 *addrs;
- struct powerpc_jit_data *jit_data;
+ u32 *code_base = NULL;
+ u32 *addrs = NULL;
+ struct powerpc_jit_data *jit_data = NULL;
struct codegen_context cgctx;
int pass;
int flen;
+ int priv_stack_alloc_size;
+ void __percpu *priv_stack_ptr = NULL;
struct bpf_binary_header *fhdr = NULL;
struct bpf_binary_header *hdr = NULL;
struct bpf_prog *org_fp = fp;
- struct bpf_prog *tmp_fp;
+ struct bpf_prog *tmp_fp = NULL;
bool bpf_blinded = false;
bool extra_pass = false;
u8 *fimage = NULL;
- u32 *fcode_base;
+ u32 *fcode_base = NULL;
u32 extable_len;
u32 fixup_len;
fp->aux->jit_data = jit_data;
}
+ priv_stack_ptr = fp->aux->priv_stack_ptr;
+ if (!priv_stack_ptr && fp->aux->jits_use_priv_stack) {
+ /*
+ * Allocate private stack of size equivalent to
+ * verifier-calculated stack size plus two memory
+ * guard regions to detect private stack overflow
+ * and underflow.
+ */
+ priv_stack_alloc_size = round_up(fp->aux->stack_depth, 16) +
+ 2 * PRIV_STACK_GUARD_SZ;
+ priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_size, 16, GFP_KERNEL);
+ if (!priv_stack_ptr) {
+ fp = org_fp;
+ goto out_priv_stack;
+ }
+
+ priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_size);
+ fp->aux->priv_stack_ptr = priv_stack_ptr;
+ }
+
flen = fp->len;
addrs = jit_data->addrs;
if (addrs) {
cgctx.is_subprog = bpf_is_subprog(fp);
cgctx.exception_boundary = fp->aux->exception_boundary;
cgctx.exception_cb = fp->aux->exception_cb;
+ cgctx.priv_sp = priv_stack_ptr;
+ cgctx.priv_stack_size = 0;
+ if (priv_stack_ptr) {
+ /*
+ * priv_stack_size required for setting bpf FP inside
+ * percpu allocation.
+ * stack_size is marked 0 to prevent allocation on
+ * general stack and offset calculation don't go for
+ * a toss in bpf_jit_stack_offsetof() & bpf_jit_stack_local()
+ */
+ cgctx.priv_stack_size = cgctx.stack_size;
+ cgctx.stack_size = 0;
+ }
/* Scouting faux-generate pass 0 */
if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
}
bpf_prog_fill_jited_linfo(fp, addrs);
out_addrs:
+ if (!image && priv_stack_ptr) {
+ fp->aux->priv_stack_ptr = NULL;
+ free_percpu(priv_stack_ptr);
+ }
+out_priv_stack:
kfree(addrs);
kfree(jit_data);
fp->aux->jit_data = NULL;
if (fp->jited) {
struct powerpc_jit_data *jit_data = fp->aux->jit_data;
struct bpf_binary_header *hdr;
+ void __percpu *priv_stack_ptr;
+ int priv_stack_alloc_size;
/*
* If we fail the final pass of JIT (from jit_subprogs),
}
hdr = bpf_jit_binary_pack_hdr(fp);
bpf_jit_binary_pack_free(hdr, NULL);
+ priv_stack_ptr = fp->aux->priv_stack_ptr;
+ if (priv_stack_ptr) {
+ priv_stack_alloc_size = round_up(fp->aux->stack_depth, 16) +
+ 2 * PRIV_STACK_GUARD_SZ;
+ priv_stack_check_guard(priv_stack_ptr, priv_stack_alloc_size, fp);
+ free_percpu(priv_stack_ptr);
+ }
WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(fp));
}
return IS_ENABLED(CONFIG_PPC64);
}
+bool bpf_jit_supports_private_stack(void)
+{
+ return IS_ENABLED(CONFIG_PPC64);
+}
+
bool bpf_jit_supports_arena(void)
{
return IS_ENABLED(CONFIG_PPC64);
{
}
+static void emit_fp_priv_stack(u32 *image, struct codegen_context *ctx)
+{
+ PPC_LI64(bpf_to_ppc(BPF_REG_FP), (__force long)ctx->priv_sp);
+ /*
+ * Load base percpu pointer of private stack allocation.
+ * Runtime per-cpu address = (base + data_offset) + (guard + stack_size)
+ */
+#ifdef CONFIG_SMP
+ /* Load percpu data offset */
+ EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), _R13,
+ offsetof(struct paca_struct, data_offset)));
+ EMIT(PPC_RAW_ADD(bpf_to_ppc(BPF_REG_FP),
+ bpf_to_ppc(TMP_REG_1), bpf_to_ppc(BPF_REG_FP)));
+#endif
+ EMIT(PPC_RAW_ADDI(bpf_to_ppc(BPF_REG_FP), bpf_to_ppc(BPF_REG_FP),
+ PRIV_STACK_GUARD_SZ + round_up(ctx->priv_stack_size, 16)));
+}
+
/*
* For exception boundary & exception_cb progs:
* return increased size to accommodate additional NVRs.
* Exception_cb not restricted from using stack area or arena.
* Setup frame pointer to point to the bpf stack area
*/
- if (bpf_is_seen_register(ctx, bpf_to_ppc(BPF_REG_FP)))
- EMIT(PPC_RAW_ADDI(bpf_to_ppc(BPF_REG_FP), _R1,
- STACK_FRAME_MIN_SIZE + ctx->stack_size));
+ if (bpf_is_seen_register(ctx, bpf_to_ppc(BPF_REG_FP))) {
+ if (ctx->priv_sp) {
+ /* Set up fp in private stack */
+ emit_fp_priv_stack(image, ctx);
+ } else {
+ /* Setup frame pointer to point to the bpf stack area */
+ EMIT(PPC_RAW_ADDI(bpf_to_ppc(BPF_REG_FP), _R1,
+ STACK_FRAME_MIN_SIZE + ctx->stack_size));
+ }
+ }
if (ctx->arena_vm_start)
PPC_LI64(bpf_to_ppc(ARENA_VM_START), ctx->arena_vm_start);