powerpc/64s: Fix copy-paste data exposure into newly created tasks
authorNicholas Piggin <npiggin@gmail.com>
Tue, 22 Jun 2021 05:30:36 +0000 (15:30 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Jul 2021 14:56:49 +0000 (16:56 +0200)
[ Upstream commit f35d2f249ef05b9671e7898f09ad89aa78f99122 ]

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: 07d2a628bc000 ("powerpc/64s: Avoid cpabort in context switch when possible")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210622053036.474678-1-npiggin@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/powerpc/kernel/process.c

index 1a1d265..3064694 100644 (file)
@@ -1227,6 +1227,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
@@ -1272,30 +1285,33 @@ struct task_struct *__switch_to(struct task_struct *prev,
 
        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) {
+       /*
+        * 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->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.
-                */
-               if (current->mm &&
-                       (cpu_has_feature(CPU_FTR_ARCH_31) ||
-                       atomic_read(&current->mm->context.vas_windows)))
-                       asm volatile(PPC_CP_ABORT);
-       }
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
        return last;