Re: Lazy FPU restoration / moving kernel_fpu_end() to context switch

From: Andy Lutomirski
Date: Fri Jun 15 2018 - 16:52:32 EST

> On Jun 15, 2018, at 1:42 PM, Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx> wrote:
>> On 06/15/2018 01:33 PM, Jason A. Donenfeld wrote:
>>> On Fri, Jun 15, 2018 at 8:32 PM Andy Lutomirski <luto@xxxxxxxxxx> wrote:
>>> quite in the form you imagined. The idea that we've tossed around is
>>> to restore FPU state on return to user mode. Roughly, we'd introduce
>>> a new thread flag TIF_FPU_UNLOADED (name TBD).
>>> prepare_exit_to_usermode() would notice this flag, copy the fpstate to
>>> fpregs, and clear the flag. (Or maybe exit_to_usermode_loop() -- No
>>> one has quite thought it through, but I think it should be outside the
>>> loop.) We'd update all the FPU accessors to understand the flag.
>> Yes! This is exactly what I was thinking. Then those calls to begin()
>> and end() could be placed as close to the actual FPU usage as
>> possible.
> Andy, what was the specific concern about PKRU? That we might do:
> kernel_fpu_begin(); <- Saves the first time
> something()
> kernel_fpu_end(); <- Does not XRSTOR
> copy_from_user(); <- Sees old PKRU, does the wrong thing
> prepare_exit_to_usermode(); <- Does the XRSTOR
> // only now does PKRU have the right value
> ?
> Does that *matter* unless something() modified PKRU? We could just make
> the rule that nobody is supposed to mess with it and that it's not
> covered by kernel_fpu_begin/end() semantics. We could even
> theoretically enforce that in a debug environment if we watch its value.

Indeed, this case seems highly unlikely. I was imagining we have two tasks. Task A enters the kernel and sleeps. Task B runs and gets its PKRU loaded. Then it enters the kernel and we switch back to A. Now we have Aâs FPU state in memory and Bâs PKRU in the register. If A does copy_to_user, we lose.