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 >