Exception callback reuses the stack frame of exception boundary. When
exception boundary and exception callback programs have different BPF
stack depth, the current stack unwind in exception callback will fail.
Adjust the stack frame size of exception callback, in its prologue,
if its BPF stack depth is different from that of exception boundary.

Reported-by: [email protected]
Closes: 
https://lore.kernel.org/bpf/2a310e86a59eb4c44c3ac9e5647814469d9c955580c9c0f1b3d9ca4a44717...@mail.kernel.org/
Fixes: 11d45eee9f42 ("powerpc64/bpf: Additional NVR handling for bpf_throw")
Signed-off-by: Hari Bathini <[email protected]>
---
 arch/powerpc/net/bpf_jit_comp64.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/arch/powerpc/net/bpf_jit_comp64.c 
b/arch/powerpc/net/bpf_jit_comp64.c
index 5d4d2bb23cef..640b84409687 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -32,14 +32,15 @@
  *
  *             [       prev sp         ] <-------------
  *             [    tail_call_info     ] 8             |
- *             [   nv gpr save area    ] 6*8 + (12*8)  |
+ *             [   nv gpr save area    ] 6*8           |
+ *             [ addl. nv gpr save area] (12*8)        | <--- exception 
boundary/callback program
  *             [    local_tmp_var      ] 24            |
  * fp (r31) -->        [   ebpf stack space    ] upto 512      |
  *             [     frame header      ] 32/112        |
  * sp (r1) --->        [    stack pointer      ] --------------
  *
  * Additional (12*8) in 'nv gpr save area' only in case of
- * exception boundary.
+ * exception boundary/callback.
  */
 
 /* BPF non-volatile registers save area size */
@@ -128,12 +129,13 @@ static inline bool bpf_has_stack_frame(struct 
codegen_context *ctx)
  *             [         ...           ]               |
  * sp (r1) --->        [    stack pointer      ] --------------
  *             [    tail_call_info     ] 8
- *             [   nv gpr save area    ] 6*8 + (12*8)
+ *             [   nv gpr save area    ] 6*8
+ *             [ addl. nv gpr save area] (12*8) <--- exception 
boundary/callback program
  *             [    local_tmp_var      ] 24
  *             [   unused red zone     ] 224
  *
  * Additional (12*8) in 'nv gpr save area' only in case of
- * exception boundary.
+ * exception boundary/callback.
  */
 static int bpf_jit_stack_local(struct codegen_context *ctx)
 {
@@ -240,10 +242,6 @@ void bpf_jit_build_prologue(u32 *image, struct 
codegen_context *ctx)
 
        if (bpf_has_stack_frame(ctx) && !ctx->exception_cb) {
                /*
-                * exception_cb uses boundary frame after stack walk.
-                * It can simply use redzone, this optimization reduces
-                * stack walk loop by one level.
-                *
                 * We need a stack frame, but we don't necessarily need to
                 * save/restore LR unless we call other functions
                 */
@@ -287,6 +285,22 @@ void bpf_jit_build_prologue(u32 *image, struct 
codegen_context *ctx)
                 * program(main prog) as third arg
                 */
                EMIT(PPC_RAW_MR(_R1, _R5));
+               /*
+                * Exception callback reuses the stack frame of exception 
boundary.
+                * But BPF stack depth of exception callback and exception 
boundary
+                * don't have to be same. If BPF stack depth is different, 
adjust the
+                * stack frame size considering BPF stack depth of exception 
callback.
+                * The non-volatile register save area remains unchanged. These 
non-
+                * volatile registers are restored in exception callback's 
epilogue.
+                */
+               EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), _R5, 0));
+               EMIT(PPC_RAW_SUB(bpf_to_ppc(TMP_REG_2), _R1, 
bpf_to_ppc(TMP_REG_1)));
+               EMIT(PPC_RAW_ADDI(bpf_to_ppc(TMP_REG_2), bpf_to_ppc(TMP_REG_2),
+                       -BPF_PPC_EXC_STACKFRAME));
+               EMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_2), ctx->stack_size));
+               PPC_BCC_CONST_SHORT(COND_EQ, 12);
+               EMIT(PPC_RAW_MR(_R1, bpf_to_ppc(TMP_REG_1)));
+               EMIT(PPC_RAW_STDU(_R1, _R1, -(BPF_PPC_EXC_STACKFRAME + 
ctx->stack_size)));
        }
 
        /*
-- 
2.53.0


Reply via email to