Skip to content

Commit 0a6c2e9

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/fpu/signal: Split out the direct restore code
Prepare for smarter failure handling of the direct restore. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent cdcec1b commit 0a6c2e9

File tree

1 file changed

+58
-54
lines changed

1 file changed

+58
-54
lines changed

arch/x86/kernel/fpu/signal.c

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,8 @@ sanitize_restored_user_xstate(union fpregs_state *state,
250250
}
251251
}
252252

253-
/*
254-
* Restore the FPU state directly from the userspace signal frame.
255-
*/
256-
static int restore_fpregs_from_user(void __user *buf, u64 xrestore, bool fx_only)
253+
static int __restore_fpregs_from_user(void __user *buf, u64 xrestore,
254+
bool fx_only)
257255
{
258256
if (use_xsave()) {
259257
u64 init_bv = xfeatures_mask_uabi() & ~xrestore;
@@ -274,6 +272,57 @@ static int restore_fpregs_from_user(void __user *buf, u64 xrestore, bool fx_only
274272
}
275273
}
276274

275+
static int restore_fpregs_from_user(void __user *buf, u64 xrestore, bool fx_only)
276+
{
277+
struct fpu *fpu = &current->thread.fpu;
278+
int ret;
279+
280+
fpregs_lock();
281+
pagefault_disable();
282+
ret = __restore_fpregs_from_user(buf, xrestore, fx_only);
283+
pagefault_enable();
284+
285+
if (unlikely(ret)) {
286+
/*
287+
* The above did an FPU restore operation, restricted to
288+
* the user portion of the registers, and failed, but the
289+
* microcode might have modified the FPU registers
290+
* nevertheless.
291+
*
292+
* If the FPU registers do not belong to current, then
293+
* invalidate the FPU register state otherwise the task
294+
* might preempt current and return to user space with
295+
* corrupted FPU registers.
296+
*
297+
* In case current owns the FPU registers then no further
298+
* action is required. The fixup in the slow path will
299+
* handle it correctly.
300+
*/
301+
if (test_thread_flag(TIF_NEED_FPU_LOAD))
302+
__cpu_invalidate_fpregs_state();
303+
fpregs_unlock();
304+
return ret;
305+
}
306+
307+
/*
308+
* Restore supervisor states: previous context switch etc has done
309+
* XSAVES and saved the supervisor states in the kernel buffer from
310+
* which they can be restored now.
311+
*
312+
* It would be optimal to handle this with a single XRSTORS, but
313+
* this does not work because the rest of the FPU registers have
314+
* been restored from a user buffer directly. The single XRSTORS
315+
* happens below, when the user buffer has been copied to the
316+
* kernel one.
317+
*/
318+
if (test_thread_flag(TIF_NEED_FPU_LOAD) && xfeatures_mask_supervisor())
319+
os_xrstor(&fpu->state.xsave, xfeatures_mask_supervisor());
320+
321+
fpregs_mark_activate();
322+
fpregs_unlock();
323+
return 0;
324+
}
325+
277326
static int __fpu_restore_sig(void __user *buf, void __user *buf_fx,
278327
bool ia32_fxstate)
279328
{
@@ -298,61 +347,16 @@ static int __fpu_restore_sig(void __user *buf, void __user *buf_fx,
298347
user_xfeatures = fx_sw_user.xfeatures;
299348
}
300349

301-
if (!ia32_fxstate) {
350+
if (likely(!ia32_fxstate)) {
302351
/*
303352
* Attempt to restore the FPU registers directly from user
304-
* memory. For that to succeed, the user access cannot cause
305-
* page faults. If it does, fall back to the slow path below,
306-
* going through the kernel buffer with the enabled pagefault
307-
* handler.
353+
* memory. For that to succeed, the user access cannot cause page
354+
* faults. If it does, fall back to the slow path below, going
355+
* through the kernel buffer with the enabled pagefault handler.
308356
*/
309-
fpregs_lock();
310-
pagefault_disable();
311357
ret = restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only);
312-
pagefault_enable();
313-
if (!ret) {
314-
315-
/*
316-
* Restore supervisor states: previous context switch
317-
* etc has done XSAVES and saved the supervisor states
318-
* in the kernel buffer from which they can be restored
319-
* now.
320-
*
321-
* We cannot do a single XRSTORS here - which would
322-
* be nice - because the rest of the FPU registers are
323-
* being restored from a user buffer directly. The
324-
* single XRSTORS happens below, when the user buffer
325-
* has been copied to the kernel one.
326-
*/
327-
if (test_thread_flag(TIF_NEED_FPU_LOAD) &&
328-
xfeatures_mask_supervisor()) {
329-
os_xrstor(&fpu->state.xsave,
330-
xfeatures_mask_supervisor());
331-
}
332-
fpregs_mark_activate();
333-
fpregs_unlock();
358+
if (likely(!ret))
334359
return 0;
335-
}
336-
337-
/*
338-
* The above did an FPU restore operation, restricted to
339-
* the user portion of the registers, and failed, but the
340-
* microcode might have modified the FPU registers
341-
* nevertheless.
342-
*
343-
* If the FPU registers do not belong to current, then
344-
* invalidate the FPU register state otherwise the task might
345-
* preempt current and return to user space with corrupted
346-
* FPU registers.
347-
*
348-
* In case current owns the FPU registers then no further
349-
* action is required. The fixup below will handle it
350-
* correctly.
351-
*/
352-
if (test_thread_flag(TIF_NEED_FPU_LOAD))
353-
__cpu_invalidate_fpregs_state();
354-
355-
fpregs_unlock();
356360
} else {
357361
/*
358362
* For 32-bit frames with fxstate, copy the fxstate so it can

0 commit comments

Comments
 (0)