Commit f35d2f24 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/64s: Fix copy-paste data exposure into newly created tasks



copy-paste contains implicit "copy buffer" state that can contain
arbitrary user data (if the user process executes a copy instruction).
This could be snooped by another process if a context switch hits while
the state is live. So cp_abort is executed on context switch to clear
out possible sensitive data and prevent the leak.

cp_abort is done after the low level _switch(), which means it is never
reached by newly created tasks, so they could snoop on this buffer
between their first and second context switch.

Fix this by doing the cp_abort before calling _switch. Add some
comments which should make the issue harder to miss.

Fixes: 07d2a628 ("powerpc/64s: Avoid cpabort in context switch when possible")
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210622053036.474678-1-npiggin@gmail.com
parent a27755d5
Loading
Loading
Loading
Loading
+32 −16
Original line number Diff line number Diff line
@@ -1223,6 +1223,19 @@ struct task_struct *__switch_to(struct task_struct *prev,
			__flush_tlb_pending(batch);
		batch->active = 0;
	}

	/*
	 * On POWER9 the copy-paste buffer can only paste into
	 * foreign real addresses, so unprivileged processes can not
	 * see the data or use it in any way unless they have
	 * foreign real mappings. If the new process has the foreign
	 * real address mappings, we must issue a cp_abort to clear
	 * any state and prevent snooping, corruption or a covert
	 * channel. ISA v3.1 supports paste into local memory.
	 */
	if (new->mm && (cpu_has_feature(CPU_FTR_ARCH_31) ||
			atomic_read(&new->mm->context.vas_windows)))
		asm volatile(PPC_CP_ABORT);
#endif /* CONFIG_PPC_BOOK3S_64 */

#ifdef CONFIG_PPC_ADV_DEBUG_REGS
@@ -1273,30 +1286,33 @@ struct task_struct *__switch_to(struct task_struct *prev,
#endif
	last = _switch(old_thread, new_thread);

	/*
	 * Nothing after _switch will be run for newly created tasks,
	 * because they switch directly to ret_from_fork/ret_from_kernel_thread
	 * etc. Code added here should have a comment explaining why that is
	 * okay.
	 */

#ifdef CONFIG_PPC_BOOK3S_64
	/*
	 * This applies to a process that was context switched while inside
	 * arch_enter_lazy_mmu_mode(), to re-activate the batch that was
	 * deactivated above, before _switch(). This will never be the case
	 * for new tasks.
	 */
	if (current_thread_info()->local_flags & _TLF_LAZY_MMU) {
		current_thread_info()->local_flags &= ~_TLF_LAZY_MMU;
		batch = this_cpu_ptr(&ppc64_tlb_batch);
		batch->active = 1;
	}

	if (current->thread.regs) {
		restore_math(current->thread.regs);

	/*
		 * On POWER9 the copy-paste buffer can only paste into
		 * foreign real addresses, so unprivileged processes can not
		 * see the data or use it in any way unless they have
		 * foreign real mappings. If the new process has the foreign
		 * real address mappings, we must issue a cp_abort to clear
		 * any state and prevent snooping, corruption or a covert
		 * channel. ISA v3.1 supports paste into local memory.
	 * Math facilities are masked out of the child MSR in copy_thread.
	 * A new task does not need to restore_math because it will
	 * demand fault them.
	 */
		if (current->mm &&
			(cpu_has_feature(CPU_FTR_ARCH_31) ||
			atomic_read(&current->mm->context.vas_windows)))
			asm volatile(PPC_CP_ABORT);
	}
	if (current->thread.regs)
		restore_math(current->thread.regs);
#endif /* CONFIG_PPC_BOOK3S_64 */

	return last;