linux/arch/arm64/kernel
Dave Martin 0b6433856a arm64: fpsimd: Prevent registers leaking from dead tasks
commit 071b6d4a5d upstream.

Currently, loading of a task's fpsimd state into the CPU registers
is skipped if that task's state is already present in the registers
of that CPU.

However, the code relies on the struct fpsimd_state * (and by
extension struct task_struct *) to unambiguously identify a task.

There is a particular case in which this doesn't work reliably:
when a task exits, its task_struct may be recycled to describe a
new task.

Consider the following scenario:

 1) Task P loads its fpsimd state onto cpu C.
        per_cpu(fpsimd_last_state, C) := P;
        P->thread.fpsimd_state.cpu := C;

 2) Task X is scheduled onto C and loads its fpsimd state on C.
        per_cpu(fpsimd_last_state, C) := X;
        X->thread.fpsimd_state.cpu := C;

 3) X exits, causing X's task_struct to be freed.

 4) P forks a new child T, which obtains X's recycled task_struct.
	T == X.
	T->thread.fpsimd_state.cpu == C (inherited from P).

 5) T is scheduled on C.
	T's fpsimd state is not loaded, because
	per_cpu(fpsimd_last_state, C) == T (== X) &&
	T->thread.fpsimd_state.cpu == C.

        (This is the check performed by fpsimd_thread_switch().)

So, T gets X's registers because the last registers loaded onto C
were those of X, in (2).

This patch fixes the problem by ensuring that the sched-in check
fails in (5): fpsimd_flush_task_state(T) is called when T is
forked, so that T->thread.fpsimd_state.cpu == C cannot be true.
This relies on the fact that T is not schedulable until after
copy_thread() completes.

Once T's fpsimd state has been loaded on some CPU C there may still
be other cpus D for which per_cpu(fpsimd_last_state, D) ==
&X->thread.fpsimd_state.  But D is necessarily != C in this case,
and the check in (5) must fail.

An alternative fix would be to do refcounting on task_struct.  This
would result in each CPU holding a reference to the last task whose
fpsimd state was loaded there.  It's not clear whether this is
preferable, and it involves higher overhead than the fix proposed
in this patch.  It would also move all the task_struct freeing
work into the context switch critical section, or otherwise some
deferred cleanup mechanism would need to be introduced, neither of
which seems obviously justified.

Fixes: 005f78cd88 ("arm64: defer reloading a task's FPSIMD state to userland resume")
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
[will: word-smithed the comment so it makes more sense]
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
History 2018-03-03 15:51:45 +00:00
..
vdso arm64: vdso: fix clock_getres for 4GiB-aligned res 2018-02-13 18:42:12 +00:00
.gitignore arm64: Build infrastructure 2012-09-17 13:42:21 +01:00
arm64ksyms.c arm64: Add ftrace support 2014-05-29 09:08:08 +01:00
asm-offsets.c arm64: kernel: cpu_{suspend/resume} implementation 2013-12-16 17:17:31 +00:00
cpu_ops.c arm64: Slightly improve the warning on CPU0 enable-method 2013-10-31 16:37:26 +00:00
cputable.c arm64: add CPU_HOTPLUG infrastructure 2013-10-25 11:33:21 +01:00
debug-monitors.c arm64: debug: avoid resetting stepping state machine when TIF_SINGLESTEP 2017-02-23 03:53:56 +00:00
efi-entry.S arm64: efi: Fix stub cache maintenance 2014-11-27 11:21:47 +00:00
efi-stub.c efi/arm64: efistub: remove local copy of linux_banner 2014-07-07 07:26:02 +01:00
efi.c arm64/efi: map the entire UEFI vendor string before reading it 2015-08-25 10:13:40 +01:00
entry-fpsimd.S arm64: add support for kernel mode NEON in interrupt context 2014-05-08 11:31:57 +02:00
entry-ftrace.S arm64: ftrace: Fix comment typo 'CONFIG_FUNCTION_GRAPH_FP_TEST' 2014-06-18 12:40:52 +01:00
entry.S arm64: avoid returning from bad_mode 2017-03-16 02:27:02 +00:00
fpsimd.c arm64: fpsimd: Prevent registers leaking across exec 2017-11-11 13:33:24 +00:00
ftrace.c arm64: ftrace: Add dynamic ftrace support 2014-05-29 09:08:33 +01:00
head.S arm64: Make sure SPsel is always set 2018-01-01 20:51:42 +00:00
hw_breakpoint.c arm64: is_compat_task is defined both in asm/compat.h and linux/compat.h 2014-05-12 16:43:29 +01:00
hyp-stub.S arm64: add hypervisor stub 2012-12-05 11:26:49 +00:00
insn.c Correct the race condition in aarch64_insn_patch_text_sync() 2014-11-27 11:21:48 +00:00
io.c arm64: Device specific operations 2012-09-17 13:42:04 +01:00
irq.c arm64: use irq_set_affinity with force=false when migrating irqs 2014-10-05 13:40:52 -07:00
jump_label.c arm64, jump label: optimize jump label implementation 2014-01-08 15:23:53 +00:00
kgdb.c arm64: KGDB: Add step debugging support 2014-02-26 11:16:25 +00:00
kuser32.S arm64: atomics: fix use of acquire + release for full barrier semantics 2014-02-07 16:45:43 +00:00
Makefile arm64: psci: move psci firmware calls out of line 2016-06-15 21:29:35 +01:00
module.c arm64: errata: add module build workaround for erratum #843419 2015-10-06 11:52:29 +01:00
perf_event.c arm64: perf: reject groups spanning multiple HW PMUs 2016-11-20 01:17:36 +00:00
perf_regs.c arm64: fix !CONFIG_COMPAT build failures 2014-04-06 23:25:04 +01:00
process.c arm64: fpsimd: Prevent registers leaking from dead tasks 2018-03-03 15:51:45 +00:00
psci-call.S arm64: psci: move psci firmware calls out of line 2016-06-15 21:29:35 +01:00
psci.c arm64: psci: move psci firmware calls out of line 2016-06-15 21:29:35 +01:00
ptrace.c arm64: Rework valid_user_regs 2017-10-12 15:28:18 +01:00
return_address.c arm64: ftrace: Add CALLER_ADDRx macros 2014-05-29 09:08:33 +01:00
setup.c arm64: Provide "model name" in /proc/cpuinfo for PER_LINUX32 tasks 2016-08-22 22:38:07 +01:00
signal.c arm64: Rework valid_user_regs 2017-10-12 15:28:18 +01:00
signal32.c arm64: Rework valid_user_regs 2017-10-12 15:28:18 +01:00
sleep.S arm64: Move cpu_resume into the text section 2015-01-15 10:44:45 +00:00
smp.c arm64: debug: unmask PSTATE.D earlier 2016-11-20 01:16:54 +00:00
smp_spin_table.c arm64: Remove boot thread synchronisation for spin-table release method 2014-05-09 15:47:46 +01:00
stacktrace.c Revert "ARM64: unwind: Fix PC calculation" 2015-11-16 11:27:13 +00:00
suspend.c arm64: kernel: pause/unpause function graph tracer in cpu_suspend() 2015-12-14 10:17:09 +00:00
sys.c arm64: switch to generic sigaltstack 2013-02-14 09:17:29 -05:00
sys32.S arm64: compat: correct register concatenation for syscall wrappers 2013-10-25 15:59:36 +01:00
sys_compat.c arm64: flush TLS registers during exec 2014-10-05 13:40:52 -07:00
time.c arm64: kernel: initialize broadcast hrtimer based clock event device 2014-05-30 17:48:13 +01:00
topology.c arm64: topology: Add support for topology DT bindings 2014-05-16 17:12:41 +01:00
traps.c arm64: ensure __dump_instr() checks addr_limit 2018-01-01 20:52:04 +00:00
vdso.c arm64: vdso: clean up vdso_pagelist initialization 2014-02-26 11:16:30 +00:00
vmlinux.lds.S arm64: Fix linker script entry point 2014-05-23 15:32:03 +01:00