]> git.baikalelectronics.ru Git - kernel.git/commitdiff
powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
authorNaveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Tue, 5 Oct 2021 20:25:25 +0000 (01:55 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 7 Oct 2021 08:52:58 +0000 (19:52 +1100)
Emit similar instruction sequences to commit f11c9fdd95bda5
("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 <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/956570cbc191cd41f8274bed48ee757a86dac62a.1633464148.git.naveen.n.rao@linux.vnet.ibm.com
arch/powerpc/net/bpf_jit64.h
arch/powerpc/net/bpf_jit_comp64.c

index 7b713edfa7e2617a9681a135233f078377b90e43..b63b35e45e558cbbff353893121171c69b1c925a 100644 (file)
  * with our redzone usage.
  *
  *             [       prev sp         ] <-------------
- *             [   nv gpr save area    ] 6*8           |
+ *             [   nv gpr save area    ] 5*8           |
  *             [    tail_call_cnt      ] 8             |
- *             [    local_tmp_var      ]             |
+ *             [    local_tmp_var      ] 16            |
  * fp (r31) -->        [   ebpf stack space    ] upto 512      |
  *             [     frame header      ] 32/112        |
  * sp (r1) --->        [    stack pointer      ] --------------
  */
 
 /* for gpr non volatile registers BPG_REG_6 to 10 */
-#define BPF_PPC_STACK_SAVE     (6*8)
+#define BPF_PPC_STACK_SAVE     (5*8)
 /* for bpf JIT code internal usage */
-#define BPF_PPC_STACK_LOCALS   16
+#define BPF_PPC_STACK_LOCALS   24
 /* stack frame excluding BPF stack, ensure this is quadword aligned */
 #define BPF_PPC_STACKFRAME     (STACK_FRAME_MIN_SIZE + \
                                 BPF_PPC_STACK_LOCALS + BPF_PPC_STACK_SAVE)
index 2ea1c3f6e287d4ecd877ce83d15bdaa7d14ac339..8b5157ccfebae55e9a6e0e2e42a05497d661be38 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/if_vlan.h>
 #include <asm/kprobes.h>
 #include <linux/bpf.h>
+#include <asm/security_features.h>
 
 #include "bpf_jit64.h"
 
@@ -35,9 +36,9 @@ static inline bool bpf_has_stack_frame(struct codegen_context *ctx)
  *             [       prev sp         ] <-------------
  *             [         ...           ]               |
  * sp (r1) --->        [    stack pointer      ] --------------
- *             [   nv gpr save area    ] 6*8
+ *             [   nv gpr save area    ] 5*8
  *             [    tail_call_cnt      ] 8
- *             [    local_tmp_var      ] 8
+ *             [    local_tmp_var      ] 16
  *             [   unused red zone     ] 208 bytes protected
  */
 static int bpf_jit_stack_local(struct codegen_context *ctx)
@@ -45,12 +46,12 @@ static int bpf_jit_stack_local(struct codegen_context *ctx)
        if (bpf_has_stack_frame(ctx))
                return STACK_FRAME_MIN_SIZE + ctx->stack_size;
        else
-               return -(BPF_PPC_STACK_SAVE + 16);
+               return -(BPF_PPC_STACK_SAVE + 24);
 }
 
 static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx)
 {
-       return bpf_jit_stack_local(ctx) + 8;
+       return bpf_jit_stack_local(ctx) + 16;
 }
 
 static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg)
@@ -272,10 +273,33 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
        return 0;
 }
 
+/*
+ * We spill into the redzone always, even if the bpf program has its own stackframe.
+ * Offsets hardcoded based on BPF_PPC_STACK_SAVE -- see bpf_jit_stack_local()
+ */
+void bpf_stf_barrier(void);
+
+asm (
+"              .global bpf_stf_barrier         ;"
+"      bpf_stf_barrier:                        ;"
+"              std     21,-64(1)               ;"
+"              std     22,-56(1)               ;"
+"              sync                            ;"
+"              ld      21,-64(1)               ;"
+"              ld      22,-56(1)               ;"
+"              ori     31,31,0                 ;"
+"              .rept 14                        ;"
+"              b       1f                      ;"
+"      1:                                      ;"
+"              .endr                           ;"
+"              blr                             ;"
+);
+
 /* Assemble the body code between the prologue & epilogue */
 int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
                       u32 *addrs, bool extra_pass)
 {
+       enum stf_barrier_type stf_barrier = stf_barrier_type_get();
        const struct bpf_insn *insn = fp->insnsi;
        int flen = fp->len;
        int i, ret;
@@ -646,6 +670,29 @@ emit_clear:
                 * BPF_ST NOSPEC (speculation barrier)
                 */
                case BPF_ST | BPF_NOSPEC:
+                       if (!security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) ||
+                                       !security_ftr_enabled(SEC_FTR_STF_BARRIER))
+                               break;
+
+                       switch (stf_barrier) {
+                       case STF_BARRIER_EIEIO:
+                               EMIT(PPC_RAW_EIEIO() | 0x02000000);
+                               break;
+                       case STF_BARRIER_SYNC_ORI:
+                               EMIT(PPC_RAW_SYNC());
+                               EMIT(PPC_RAW_LD(b2p[TMP_REG_1], _R13, 0));
+                               EMIT(PPC_RAW_ORI(_R31, _R31, 0));
+                               break;
+                       case STF_BARRIER_FALLBACK:
+                               EMIT(PPC_RAW_MFLR(b2p[TMP_REG_1]));
+                               PPC_LI64(12, dereference_kernel_function_descriptor(bpf_stf_barrier));
+                               EMIT(PPC_RAW_MTCTR(12));
+                               EMIT(PPC_RAW_BCTRL());
+                               EMIT(PPC_RAW_MTLR(b2p[TMP_REG_1]));
+                               break;
+                       case STF_BARRIER_NONE:
+                               break;
+                       }
                        break;
 
                /*