Skip to content

Commit b860eb8

Browse files
Fenghua Yusuryasaimadhu
authored andcommitted
x86/fpu/xstate: Define new functions for clearing fpregs and xstates
Currently, fpu__clear() clears all fpregs and xstates. Once XSAVES supervisor states are introduced, supervisor settings (e.g. CET xstates) must remain active for signals; It is necessary to have separate functions: - Create fpu__clear_user_states(): clear only user settings for signals; - Create fpu__clear_all(): clear both user and supervisor settings in flush_thread(). Also modify copy_init_fpstate_to_fpregs() to take a mask from above two functions. Remove obvious side-comment in fpu__clear(), while at it. [ bp: Make the second argument of fpu__clear() bool after requesting it a bunch of times during review. - Add a comment about copy_init_fpstate_to_fpregs() locking needs. ] Co-developed-by: Yu-cheng Yu <[email protected]> Signed-off-by: Fenghua Yu <[email protected]> Signed-off-by: Yu-cheng Yu <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Reviewed-by: Dave Hansen <[email protected]> Reviewed-by: Tony Luck <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 71581ee commit b860eb8

File tree

5 files changed

+41
-23
lines changed

5 files changed

+41
-23
lines changed

arch/x86/include/asm/fpu/internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ extern void fpu__save(struct fpu *fpu);
3131
extern int fpu__restore_sig(void __user *buf, int ia32_frame);
3232
extern void fpu__drop(struct fpu *fpu);
3333
extern int fpu__copy(struct task_struct *dst, struct task_struct *src);
34-
extern void fpu__clear(struct fpu *fpu);
34+
extern void fpu__clear_user_states(struct fpu *fpu);
35+
extern void fpu__clear_all(struct fpu *fpu);
3536
extern int fpu__exception_code(struct fpu *fpu, int trap_nr);
3637
extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);
3738

arch/x86/kernel/fpu/core.c

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -291,25 +291,20 @@ void fpu__drop(struct fpu *fpu)
291291
}
292292

293293
/*
294-
* Clear FPU registers by setting them up from
295-
* the init fpstate:
294+
* Clear FPU registers by setting them up from the init fpstate.
295+
* Caller must do fpregs_[un]lock() around it.
296296
*/
297-
static inline void copy_init_fpstate_to_fpregs(void)
297+
static inline void copy_init_fpstate_to_fpregs(u64 features_mask)
298298
{
299-
fpregs_lock();
300-
301299
if (use_xsave())
302-
copy_kernel_to_xregs(&init_fpstate.xsave, -1);
300+
copy_kernel_to_xregs(&init_fpstate.xsave, features_mask);
303301
else if (static_cpu_has(X86_FEATURE_FXSR))
304302
copy_kernel_to_fxregs(&init_fpstate.fxsave);
305303
else
306304
copy_kernel_to_fregs(&init_fpstate.fsave);
307305

308306
if (boot_cpu_has(X86_FEATURE_OSPKE))
309307
copy_init_pkru_to_fpregs();
310-
311-
fpregs_mark_activate();
312-
fpregs_unlock();
313308
}
314309

315310
/*
@@ -318,18 +313,40 @@ static inline void copy_init_fpstate_to_fpregs(void)
318313
* Called by sys_execve(), by the signal handler code and by various
319314
* error paths.
320315
*/
321-
void fpu__clear(struct fpu *fpu)
316+
static void fpu__clear(struct fpu *fpu, bool user_only)
322317
{
323-
WARN_ON_FPU(fpu != &current->thread.fpu); /* Almost certainly an anomaly */
318+
WARN_ON_FPU(fpu != &current->thread.fpu);
324319

325-
fpu__drop(fpu);
320+
if (!static_cpu_has(X86_FEATURE_FPU)) {
321+
fpu__drop(fpu);
322+
fpu__initialize(fpu);
323+
return;
324+
}
326325

327-
/*
328-
* Make sure fpstate is cleared and initialized.
329-
*/
330-
fpu__initialize(fpu);
331-
if (static_cpu_has(X86_FEATURE_FPU))
332-
copy_init_fpstate_to_fpregs();
326+
fpregs_lock();
327+
328+
if (user_only) {
329+
if (!fpregs_state_valid(fpu, smp_processor_id()) &&
330+
xfeatures_mask_supervisor())
331+
copy_kernel_to_xregs(&fpu->state.xsave,
332+
xfeatures_mask_supervisor());
333+
copy_init_fpstate_to_fpregs(xfeatures_mask_user());
334+
} else {
335+
copy_init_fpstate_to_fpregs(xfeatures_mask_all);
336+
}
337+
338+
fpregs_mark_activate();
339+
fpregs_unlock();
340+
}
341+
342+
void fpu__clear_user_states(struct fpu *fpu)
343+
{
344+
fpu__clear(fpu, true);
345+
}
346+
347+
void fpu__clear_all(struct fpu *fpu)
348+
{
349+
fpu__clear(fpu, false);
333350
}
334351

335352
/*

arch/x86/kernel/fpu/signal.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
289289
IS_ENABLED(CONFIG_IA32_EMULATION));
290290

291291
if (!buf) {
292-
fpu__clear(fpu);
292+
fpu__clear_user_states(fpu);
293293
return 0;
294294
}
295295

@@ -416,7 +416,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
416416

417417
err_out:
418418
if (ret)
419-
fpu__clear(fpu);
419+
fpu__clear_user_states(fpu);
420420
return ret;
421421
}
422422

arch/x86/kernel/process.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ void flush_thread(void)
191191
flush_ptrace_hw_breakpoint(tsk);
192192
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
193193

194-
fpu__clear(&tsk->thread.fpu);
194+
fpu__clear_all(&tsk->thread.fpu);
195195
}
196196

197197
void disable_TSC(void)

arch/x86/kernel/signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
732732
/*
733733
* Ensure the signal handler starts with the new fpu state.
734734
*/
735-
fpu__clear(fpu);
735+
fpu__clear_user_states(fpu);
736736
}
737737
signal_setup_done(failed, ksig, stepping);
738738
}

0 commit comments

Comments
 (0)