linux/arch/mips
James Hogan 39148e94e3 MIPS: fork: Fix MSA/FPU/DSP context duplication race
There is a race in the MIPS fork code which allows the child to get a
stale copy of parent MSA/FPU/DSP state that is active in hardware
registers when the fork() is called. This is because copy_thread() saves
the live register state into the child context only if the hardware is
currently in use, apparently on the assumption that the hardware state
cannot have been saved and disabled since the initial duplication of the
task_struct. However preemption is certainly possible during this
window.

An example sequence of events is as follows:

1) The parent userland process puts important data into saved floating
   point registers ($f20-$f31), which are then dirty compared to the
   process' stored context.

2) The parent process calls fork() which does a clone system call.

3) In the kernel, do_fork() -> copy_process() -> dup_task_struct() ->
   arch_dup_task_struct() (which uses the weakly defined default
   implementation). This duplicates the parent process' task context,
   which includes a stale version of its FP context from when it was
   last saved, probably some time before (1).

4) At some point before copy_process() calls copy_thread(), such as when
   duplicating the memory map, the process is desceduled. Perhaps it is
   preempted asynchronously, or perhaps it sleeps while blocked on a
   mutex. The dirty FP state in the FP registers is saved to the parent
   process' context and the FPU is disabled.

5) When the process is rescheduled again it continues copying state
   until it gets to copy_thread(), which checks whether the FPU is in
   use, so that it can copy that dirty state to the child process' task
   context. Because of the deschedule however the FPU is not in use, so
   the child process' context is left with stale FP context from the
   last time the parent saved it (some time before (1)).

6) When the new child process is scheduled it reads the important data
   from the saved floating point register, and ends up doing a NULL
   pointer dereference as a result of the stale data.

This use of saved floating point registers across function calls can be
triggered fairly easily by explicitly using inline asm with a current
(MIPS R2) compiler, but is far more likely to happen unintentionally
with a MIPS R6 compiler where the FP registers are more likely to get
used as scratch registers for storing non-fp data.

It is easily fixed, in the same way that other architectures do it, by
overriding the implementation of arch_dup_task_struct() to sync the
dirty hardware state to the parent process' task context *prior* to
duplicating it, rather than copying straight to the child process' task
context in copy_thread(). Note, the FPU hardware is not disabled so the
parent process may continue executing with the live register context,
but now the child process is guaranteed to have an identical copy of it
at that point.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Reported-by: Matthew Fortune <matthew.fortune@imgtec.com>
Tested-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9075/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2015-01-31 00:44:19 +01:00
..
alchemy Please consider pulling the clk framework changes toward 3.19. It is 2014-12-20 16:42:36 -08:00
ar7 mips: Convert pr_warning to pr_warn 2014-11-24 07:44:51 +01:00
ath25 MIPS: ath25: add Wireless device support 2014-11-24 07:45:29 +01:00
ath79 MIPS: ath79: Read the initrd address from the firmware environment 2014-11-24 07:45:30 +01:00
bcm47xx MIPS: BCM47XX: Clean up nvram header 2014-11-24 07:45:08 +01:00
bcm63xx MIPS: Remove useless parentheses 2014-11-24 07:44:49 +01:00
bcm3384 MIPS: bcm3384: Initial commit of bcm3384 platform support 2014-11-24 07:45:13 +01:00
boot MIPS: bcm3384: Initial commit of bcm3384 platform support 2014-11-24 07:45:13 +01:00
cavium-octeon MIPS: OCTEON: fix kernel crash when offlining a CPU 2015-01-29 23:48:29 +01:00
cobalt MIPS: Cobalt: Move to 8250/16550 serial early printk driver 2013-10-29 21:24:38 +01:00
configs MIPS: Update malta_defconfig to something that works out of the box. 2015-01-13 15:53:08 +01:00
dec Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus 2014-06-09 18:10:34 -07:00
emma MIPS: Remove panic_timeout settings 2013-11-26 12:12:27 +01:00
fw MIPS: FW: Use kstrtoul() to parse unsigned long from the fw environment 2014-11-24 07:45:26 +01:00
include MIPS: mipsregs.h: Add write_32bit_cp1_register() 2015-01-30 23:04:59 +01:00
jazz
jz4740 MIPS: JZ4740: Fixup #include's (sparse) 2015-01-13 15:53:09 +01:00
kernel MIPS: fork: Fix MSA/FPU/DSP context duplication race 2015-01-31 00:44:19 +01:00
kvm KVM: remove garbage arg to *hardware_{en,dis}able 2014-08-29 16:35:55 +02:00
lantiq Driver core patches for 3.19-rc1 2014-12-14 16:10:09 -08:00
lasat MIPS: Lasat: Add missing CONFIG_PROC_FS dependency to PICVUE_PROC 2014-10-21 17:35:44 +02:00
lib MIPS: lib: memset: Clean up some MIPS{EL,EB} ifdefery 2014-11-24 07:45:42 +01:00
loongson Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus 2014-12-11 17:56:37 -08:00
loongson1 MIPS: Loongson1B: Add a clockevent/clocksource using PWM Timer 2014-11-24 07:45:09 +01:00
math-emu MIPS: Support for hybrid FPRs 2014-11-24 07:45:07 +01:00
mm MIPS: Fix C0_Pagegrain[IEC] support. 2015-01-31 00:44:08 +01:00
mti-malta MIPS: Replace use of phys_t with phys_addr_t. 2014-11-24 22:47:31 +01:00
mti-sead3 Driver core patches for 3.19-rc1 2014-12-14 16:10:09 -08:00
net mips: bpf: Fix broken BPF_MOD 2014-12-08 20:22:30 -05:00
netlogic MIPS: Netlogic: handle modular AHCI builds 2014-11-24 07:44:06 +01:00
oprofile MIPS: oprofile: Backtrace: don't fail on leaf functions 2014-11-24 07:45:31 +01:00
paravirt mips: Update the email address of Geert Uytterhoeven 2014-06-02 16:34:41 +02:00
pci Driver core patches for 3.19-rc1 2014-12-14 16:10:09 -08:00
pmcs-msp71xx MIPS: Remove useless parentheses 2014-11-24 07:44:49 +01:00
pnx833x MIPS: PNX833x: Remove checks for CONFIG_I2C_PNX0105 2014-05-23 15:12:39 +02:00
power nosave: consolidate __nosave_{begin,end} in <asm/sections.h> 2014-10-09 22:26:04 -04:00
ralink Driver core patches for 3.19-rc1 2014-12-14 16:10:09 -08:00
rb532 MIPS: Replace use of phys_t with phys_addr_t. 2014-11-24 22:47:31 +01:00
sgi-ip22 MIPS: Remove useless parentheses 2014-11-24 07:44:49 +01:00
sgi-ip27 MIPS: Remove useless parentheses 2014-11-24 07:44:49 +01:00
sgi-ip32
sibyte MIPS: Replace use of phys_t with phys_addr_t. 2014-11-24 22:47:31 +01:00
sni
txx9 Driver core patches for 3.19-rc1 2014-12-14 16:10:09 -08:00
vr41xx
Kbuild MIPS: net: Add BPF JIT 2014-05-30 16:10:20 +02:00
Kbuild.platforms MIPS: ath25: add common parts 2014-11-24 07:45:26 +01:00
Kconfig MIPS: Kconfig: Fix recursive dependency. 2015-01-13 15:53:09 +01:00
Kconfig.debug MIPS: Kconfig option to better exercise/debug hybrid FPRs 2014-11-24 07:45:08 +01:00
Makefile MIPS: IP22/IP32: Add line to arch/mips/Makefile archhelp about vmlinux.32 2014-11-24 07:45:33 +01:00