On Sun, Aug 30, 2026 at 08:24:30PM +0530, Ritesh Harjani (IBM) wrote:
> KUAP means kernel cannot touch user memory unless it explicitly is
> enabled. In the kernel it should stay AMR_KUAP_BLOCKED. While returning
> to userspace just before RFI, kernel should restore the user AMR value
> back.
> 
> Looks like GENERIC_ENTRY might be treating arch_exit_to_user_mode_prepare()
> as the last architecture step before returning to userspace.
> commit bee25f97ad24 ("powerpc: Enable GENERIC_ENTRY feature")
> therefore called kuap_user_restore() from that hook. But on PowerPC that
> is too early. After irqentry_exit() / syscall_exit_to_user_mode() we
> still run platform specific exit routines.
> 
> e.g. code snippets showing both exception handling and system call
> handling as the callers of function arch_exit_to_user_mode_prepare()
> which does kuap_user_restore(). The below path shows that calling
> kuap_user_restore() is too early when called from
> arch_exit_to_user_mode_prepare().
> 
> Exception handling in exceptions-64s.S
> =======================================
> 
> bl    CFUNC(do_page_fault)
>         ..DEFINE_INTERRUPT_HANDLER_ASYNC(do_page_fault)
>             arch_interrupt_async_enter_prepare(regs);
>             state = irqentry_enter(regs);
>             instrumentation_begin();
>             irq_enter_rcu();
>             handler(regs);
>             nap_adjust_return(regs);
>             irq_exit_rcu();
>             instrumentation_end();
>             arch_interrupt_async_exit_prepare(regs);
>             irqentry_exit(regs, state);                  <<< too early
>               irqentry_exit_to_user_mode()
>                 __exit_to_user_mode_prepare(regs, EXIT_TO_USER_MODE_WORK_IRQ);
>                   arch_exit_to_user_mode_prepare(regs, ti_work);  <<< too 
> early
> b     interrupt_return_srr
>               .. bl   CFUNC(interrupt_exit_user_prepare) <<< already calls 
> kuap_user_restore
> 
> prep_irq_for_enabled_exit() retry can run kernel code with IRQs on. So
> only when that routine is fully finished is when the user KUAP should be
> fully restored which interrupt_exit_user_prepare() already takes care of
> before returning.
> 
> Similarly for system call handling in interrupt_64.S
> ======================================================
> 
>       bl      CFUNC(system_call_exception)
> 
> .Lsyscall_exit:
>       addi    r4,r1,STACK_INT_FRAME_REGS
>       li      r5,0 /* !scv */
>       bl      CFUNC(syscall_exit_prepare)
>                 .. kuap_assert_locked();
>                    syscall_exit_to_user_mode(regs); <<< too early
>                      syscall_exit_to_user_mode_prepare(regs);  <<< too early
>                    kuap_user_restore(regs);         <<< already calls
> 
> syscall_exit_prepare(), which can enable IRQs, replay a pending
> interrupt, and only then rfi. Those functions already restore KUAP
> immediately before rfi.
> 
> Note that if we restore the user AMR too early like in the current code
> as shown from the code snippets above, then we get the following warning
> when CONFIG_PPC_KUAP_DEBUG is enabled:
>   WARNING: arch/powerpc/include/asm/book3s/64/kup.h:293 at 
> interrupt_exit_user_prepare+0x1a0/0x1c0
>   Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected)
>   TRAP: 0700
>   LR: c00000000000d8d4 CTR: c0000000021fe500
>   MSR: <SF,EE,ME,IR,DR,RI,LE>  CR: 44000804  XER: 20040000
>   interrupt_exit_user_prepare+0x1a0/0x1c0
>   interrupt_return_srr_user+0x8/0x12c
> 
> Fixes: bee25f97ad24 ("powerpc: Enable GENERIC_ENTRY feature")
> Fixes: 02565a782c1ee ("powerpc: Introduce syscall exit arch functions")
> Signed-off-by: Ritesh Harjani (IBM) <[email protected]>
> ---
>  arch/powerpc/include/asm/entry-common.h | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/entry-common.h 
> b/arch/powerpc/include/asm/entry-common.h
> index c5adb5006361..94083516df57 100644
> --- a/arch/powerpc/include/asm/entry-common.h
> +++ b/arch/powerpc/include/asm/entry-common.h
> @@ -515,8 +515,14 @@ static inline void arch_exit_to_user_mode_prepare(struct 
> pt_regs *regs,
>  #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>       local_paca->tm_scratch = regs->msr;
>  #endif
> -     /* Restore user access locks last */
> -     kuap_user_restore(regs);
> +     /*
> +      * Do not restore KUAP here. Generic entry might treat this as the last
> +      * arch step before userspace but PowerPC still has kernel work after
> +      * irqentry_exit()/syscall_exit_to_user_mode() i.e. in
> +      * interrupt_exit_user_prepare() / syscall_exit_prepare() may enable
> +      * IRQs and retry. Those functions restore KUAP immediately before rfi,
> +      * which is where it should belong.
> +      */
>  }
> 
>  #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
> --
> 2.39.5
> 
> 
Yeah, KUAP access should be restored last.

Reviewed-by: Mukesh Kumar Chaurasiya (IBM) <[email protected]>

Reply via email to