KVM: PPC: Book3S HV: Flush link stack on guest exit to host kernel
authorMichael Ellerman <mpe@ellerman.id.au>
Wed, 13 Nov 2019 10:05:44 +0000 (21:05 +1100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 1 Dec 2019 08:14:36 +0000 (09:14 +0100)
commit af2e8c68b9c5403f77096969c516f742f5bb29e0 upstream.

On some systems that are vulnerable to Spectre v2, it is up to
software to flush the link stack (return address stack), in order to
protect against Spectre-RSB.

When exiting from a guest we do some house keeping and then
potentially exit to C code which is several stack frames deep in the
host kernel. We will then execute a series of returns without
preceeding calls, opening up the possiblity that the guest could have
poisoned the link stack, and direct speculative execution of the host
to a gadget of some sort.

To prevent this we add a flush of the link stack on exit from a guest.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
[dja: straightforward backport to v4.14]
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/include/asm/asm-prototypes.h
arch/powerpc/kernel/security.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index fb5f911b0d9101c98229410be8091db844974c04..2d4444981c2c93c1685970dba2031e318eb5c92d 100644 (file)
@@ -130,7 +130,9 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip);
 extern s32 patch__call_flush_count_cache;
 extern s32 patch__flush_count_cache_return;
 extern s32 patch__flush_link_stack_return;
+extern s32 patch__call_kvm_flush_link_stack;
 
 extern long flush_count_cache;
+extern long kvm_flush_link_stack;
 
 #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
index 88e582d2bad7424b98d15517126ec24c3736c49f..f5d6541bf8c279e93b9a06fb4a13ccb5b9f0c051 100644 (file)
@@ -392,6 +392,9 @@ static void toggle_count_cache_flush(bool enable)
 
        if (!enable) {
                patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP);
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+               patch_instruction_site(&patch__call_kvm_flush_link_stack, PPC_INST_NOP);
+#endif
                pr_info("link-stack-flush: software flush disabled.\n");
                link_stack_flush_enabled = false;
                no_count_cache_flush();
@@ -402,6 +405,12 @@ static void toggle_count_cache_flush(bool enable)
        patch_branch_site(&patch__call_flush_count_cache,
                          (u64)&flush_count_cache, BRANCH_SET_LINK);
 
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       // This enables the branch from guest_exit_cont to kvm_flush_link_stack
+       patch_branch_site(&patch__call_kvm_flush_link_stack,
+                         (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
+#endif
+
        pr_info("link-stack-flush: software flush enabled.\n");
        link_stack_flush_enabled = true;
 
index 663a398449b700c91b3c08e056b99254aaa9c73a..46ea42f403340980c2987ad2fa4c000ee8064339 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <asm/ppc_asm.h>
+#include <asm/code-patching-asm.h>
 #include <asm/kvm_asm.h>
 #include <asm/reg.h>
 #include <asm/mmu.h>
@@ -1445,6 +1446,10 @@ mc_cont:
 1:
 #endif /* CONFIG_KVM_XICS */
 
+       /* Possibly flush the link stack here. */
+1:     nop
+       patch_site 1b patch__call_kvm_flush_link_stack
+
        stw     r12, STACK_SLOT_TRAP(r1)
        mr      r3, r12
        /* Increment exit count, poke other threads to exit */
@@ -1957,6 +1962,28 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        mtlr    r0
        blr
 
+.balign 32
+.global kvm_flush_link_stack
+kvm_flush_link_stack:
+       /* Save LR into r0 */
+       mflr    r0
+
+       /* Flush the link stack. On Power8 it's up to 32 entries in size. */
+       .rept 32
+       bl      .+4
+       .endr
+
+       /* And on Power9 it's up to 64. */
+BEGIN_FTR_SECTION
+       .rept 32
+       bl      .+4
+       .endr
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+
+       /* Restore LR */
+       mtlr    r0
+       blr
+
 /*
  * Check whether an HDSI is an HPTE not found fault or something else.
  * If it is an HPTE not found fault that is due to the guest accessing