On Fri, Oct 14, 2022 at 01:16:47AM +1000, Nicholas Piggin wrote:
> schedule must not be explicitly called while KUAP is unlocked, because
> the AMR register will not be saved across the context switch on 64s
> (preemption is allowed because that is driven by interrupts which do
> save the AMR).
> 
> exit_vmx_usercopy() runs inside an unlocked user access region, and it
> calls preempt_enable() which will call schedule() if need_resched() was
> set while non-preemptible. This can cause tasks to run unprotected when
> the should not, and can cause the user copy to be improperly blocked
> when scheduling back to it.
> 
> Fix this by avoiding the explicit resched for preempt kernels by
> generating an interrupt to reschedule the context if need_resched() got
> set.
> 
> Signed-off-by: Nicholas Piggin <npig...@gmail.com>

Tested-by: Guenter Roeck <li...@roeck-us.net>

> ---
>  arch/powerpc/lib/vmx-helper.c | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/lib/vmx-helper.c b/arch/powerpc/lib/vmx-helper.c
> index f76a50291fd7..d491da8d1838 100644
> --- a/arch/powerpc/lib/vmx-helper.c
> +++ b/arch/powerpc/lib/vmx-helper.c
> @@ -36,7 +36,17 @@ int exit_vmx_usercopy(void)
>  {
>       disable_kernel_altivec();
>       pagefault_enable();
> -     preempt_enable();
> +     preempt_enable_no_resched();
> +     /*
> +      * Must never explicitly call schedule (including preempt_enable())
> +      * while in a kuap-unlocked user copy, because the AMR register will
> +      * not be saved and restored across context switch. However preempt
> +      * kernels need to be preempted as soon as possible if need_resched is
> +      * set and we are preemptible. The hack here is to schedule a
> +      * decrementer to fire here and reschedule for us if necessary.
> +      */
> +     if (IS_ENABLED(CONFIG_PREEMPT) && need_resched())
> +             set_dec(1);
>       return 0;
>  }
>  
> -- 
> 2.37.2
> 

Reply via email to