Re: [PATCH RFC 1/3] fpu/x86: add make_fpregs_active(_newstate) helper functions
From: Andy Lutomirski
Date: Mon Oct 17 2016 - 16:58:23 EST
On Mon, Oct 17, 2016 at 1:09 PM, <riel@xxxxxxxxxx> wrote:
> From: Rik van Riel <riel@xxxxxxxxxx>
>
> Add helper functions that ensure a task's floating point registers are
> set up the way they need to be - either with the task's floating point
> state loaded in, or ready to accept a task's new floating point state.
>
> These helpers can be called from code that accesses the floating point
> state from a preemptible state, in preparation for the lazier floating
> point loading code, using loops like this:
>
> do {
> make_fpregs_active();
> ...
> } while (unlikely(!fpregs_active()));
>
> This way a task can safely do things like saving the floating point
> state of a task to user space memory (the signal handling code does
> this), without requiring that the floating point state is restored
> at every context switch.
Sadly, I think this model is problematic. An attacker can set up some
memory that causes writes to block in a controlled manner (using
userfaultfd, FUSE, madvise() hammering, etc). The attacker can
arrange for the uaccess write in the "..." to block and then for some
privileged target task to be scheduled. The attacker then gets their
task to be scheduled next and the privileged xstate gets written to
the attacker's memory. Then the attacker either reads it back from a
different thread or arranges for the next iteration of the loop to
fail outright. Now the attacker has read another task's xstate.
Dave and/or Yu-cheng: didn't one of you have some code to allow a user
xstate buffer to be filled from the copy in kernel memory? If we did
that, we could avoid this mess entirely.
Alternatively, there could be flag that causes FPU loads to be
temporarily eager. Maybe the sequence would look like:
pin_fpregs_active();
...
unpin_fpregs_active();
or maybe get_fpregs() / put_fpregs().
--Andy