From: Ingo Molnar Date: Wed, 27 May 2015 10:22:29 +0000 (+0200) Subject: x86/fpu/math-emu: Fix crash in fork() X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=827409b2f5b58573ae3774fe6bd2d6daeb335878;p=linux-beck.git x86/fpu/math-emu: Fix crash in fork() During later stages of math-emu bootup the following crash triggers: math_emulate: 0060:c100d0a8 Kernel panic - not syncing: Math emulation needed in kernel CPU: 0 PID: 1511 Comm: login Not tainted 4.2.0-rc7+ #1012 [...] Call Trace: [] dump_stack+0x41/0x52 [] panic+0x77/0x189 [] ? math_error+0x140/0x140 [] math_emulate+0xba7/0xbd0 [] ? fpu__copy+0x138/0x1c0 [] ? __alloc_pages_nodemask+0x12c/0x870 [] ? proc_clear_tty+0x40/0x70 [] ? session_clear_tty+0x1e/0x30 [] ? math_error+0x140/0x140 [] do_device_not_available+0x45/0x70 [] ? fpu__copy+0x138/0x1c0 [] error_code+0x5a/0x60 [] ? math_error+0x140/0x140 [] ? fpu__copy+0x138/0x1c0 [] arch_dup_task_struct+0x25/0x30 [] copy_process.part.51+0xea/0x1480 [] ? dput+0x175/0x200 [] ? no_tty+0x30/0x30 [] ? do_vfs_ioctl+0x322/0x540 [] _do_fork+0xca/0x340 [] ? SyS_rt_sigaction+0x66/0x90 [] SyS_clone+0x27/0x30 [] sysenter_do_call+0x12/0x12 The reason is the incorrect assumption in fpu_copy(), that FNSAVE can be executed from math-emu kernels as well. Don't try to copy the registers, the soft state will be copied by fork anyway, so the child task inherits the parent task's soft math state. With this fix applied math-emu kernels boot up fine on modern hardware and the 'no387 nofxsr' boot options. Cc: Andy Lutomirski Cc: Bobby Powers Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Thomas Gleixner Signed-off-by: Ingo Molnar --- diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 79de954626fd..d25097c3fc1d 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -270,7 +270,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) dst_fpu->fpregs_active = 0; dst_fpu->last_cpu = -1; - if (src_fpu->fpstate_active) + if (src_fpu->fpstate_active && cpu_has_fpu) fpu_copy(dst_fpu, src_fpu); return 0;