Skip to content

Commit 9e798e9

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/fpu: Prepare fpu_clone() for dynamically enabled features
The default portion of the parent's FPU state is saved in a child task. With dynamic features enabled, the non-default portion is not saved in a child's fpstate because these register states are defined to be caller-saved. The new task's fpstate is therefore the default buffer. Fork inherits the permission of the parent. Also, do not use memcpy() when TIF_NEED_FPU_LOAD is set because it is invalid when the parent has dynamic features. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Chang S. Bae <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 53599b4 commit 9e798e9

File tree

3 files changed

+27
-12
lines changed

3 files changed

+27
-12
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
extern void save_fpregs_to_fpstate(struct fpu *fpu);
1313
extern void fpu__drop(struct fpu *fpu);
14-
extern int fpu_clone(struct task_struct *dst);
14+
extern int fpu_clone(struct task_struct *dst, unsigned long clone_flags);
1515
extern void fpu_flush_thread(void);
1616

1717
/*

arch/x86/kernel/fpu/core.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,8 +423,20 @@ void fpstate_reset(struct fpu *fpu)
423423
fpu->perm.__user_state_size = fpu_user_cfg.default_size;
424424
}
425425

426+
static inline void fpu_inherit_perms(struct fpu *dst_fpu)
427+
{
428+
if (fpu_state_size_dynamic()) {
429+
struct fpu *src_fpu = &current->group_leader->thread.fpu;
430+
431+
spin_lock_irq(&current->sighand->siglock);
432+
/* Fork also inherits the permissions of the parent */
433+
dst_fpu->perm = src_fpu->perm;
434+
spin_unlock_irq(&current->sighand->siglock);
435+
}
436+
}
437+
426438
/* Clone current's FPU state on fork */
427-
int fpu_clone(struct task_struct *dst)
439+
int fpu_clone(struct task_struct *dst, unsigned long clone_flags)
428440
{
429441
struct fpu *src_fpu = &current->thread.fpu;
430442
struct fpu *dst_fpu = &dst->thread.fpu;
@@ -455,17 +467,20 @@ int fpu_clone(struct task_struct *dst)
455467
}
456468

457469
/*
458-
* If the FPU registers are not owned by current just memcpy() the
459-
* state. Otherwise save the FPU registers directly into the
460-
* child's FPU context, without any memory-to-memory copying.
470+
* Save the default portion of the current FPU state into the
471+
* clone. Assume all dynamic features to be defined as caller-
472+
* saved, which enables skipping both the expansion of fpstate
473+
* and the copying of any dynamic state.
474+
*
475+
* Do not use memcpy() when TIF_NEED_FPU_LOAD is set because
476+
* copying is not valid when current uses non-default states.
461477
*/
462478
fpregs_lock();
463-
if (test_thread_flag(TIF_NEED_FPU_LOAD)) {
464-
memcpy(&dst_fpu->fpstate->regs, &src_fpu->fpstate->regs,
465-
dst_fpu->fpstate->size);
466-
} else {
467-
save_fpregs_to_fpstate(dst_fpu);
468-
}
479+
if (test_thread_flag(TIF_NEED_FPU_LOAD))
480+
fpregs_restore_userregs();
481+
save_fpregs_to_fpstate(dst_fpu);
482+
if (!(clone_flags & CLONE_THREAD))
483+
fpu_inherit_perms(dst_fpu);
469484
fpregs_unlock();
470485

471486
trace_x86_fpu_copy_src(src_fpu);

arch/x86/kernel/process.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
157157
frame->flags = X86_EFLAGS_FIXED;
158158
#endif
159159

160-
fpu_clone(p);
160+
fpu_clone(p, clone_flags);
161161

162162
/* Kernel thread ? */
163163
if (unlikely(p->flags & PF_KTHREAD)) {

0 commit comments

Comments
 (0)