Commit 80eb5fea authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-spectre-rsb' of powerpc-CVE-2019-18660.bundle

Pull powerpc Spectre-RSB fixes from Michael Ellerman:
 "We failed to activate the mitigation for Spectre-RSB (Return Stack
  Buffer, aka. ret2spec) on context switch, on CPUs prior to Power9
  DD2.3.

  That allows a process to poison the RSB (called Link Stack on Power
  CPUs) and possibly misdirect speculative execution of another process.
  If the victim process can be induced to execute a leak gadget then it
  may be possible to extract information from the victim via a side
  channel.

  The fix is to correctly activate the link stack flush mitigation on
  all CPUs that have any mitigation of Spectre v2 in userspace enabled.

  There's a second commit which adds a link stack flush in the KVM guest
  exit path. A leak via that path has not been demonstrated, but we
  believe it's at least theoretically possible.

  This is the fix for CVE-2019-18660"

* tag 'powerpc-spectre-rsb' of /home/torvalds/Downloads/powerpc-CVE-2019-18660.bundle:
  KVM: PPC: Book3S HV: Flush link stack on guest exit to host kernel
  powerpc/book3s64: Fix link stack flush on context switch
parents 9a3d7fd2 af2e8c68
...@@ -152,9 +152,12 @@ void _kvmppc_save_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr); ...@@ -152,9 +152,12 @@ void _kvmppc_save_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr);
/* Patch sites */ /* Patch sites */
extern s32 patch__call_flush_count_cache; extern s32 patch__call_flush_count_cache;
extern s32 patch__flush_count_cache_return; extern s32 patch__flush_count_cache_return;
extern s32 patch__flush_link_stack_return;
extern s32 patch__call_kvm_flush_link_stack;
extern s32 patch__memset_nocache, patch__memcpy_nocache; extern s32 patch__memset_nocache, patch__memcpy_nocache;
extern long flush_count_cache; extern long flush_count_cache;
extern long kvm_flush_link_stack;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
void kvmppc_save_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv); void kvmppc_save_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv);
......
...@@ -81,6 +81,9 @@ static inline bool security_ftr_enabled(unsigned long feature) ...@@ -81,6 +81,9 @@ static inline bool security_ftr_enabled(unsigned long feature)
// Software required to flush count cache on context switch // Software required to flush count cache on context switch
#define SEC_FTR_FLUSH_COUNT_CACHE 0x0000000000000400ull #define SEC_FTR_FLUSH_COUNT_CACHE 0x0000000000000400ull
// Software required to flush link stack on context switch
#define SEC_FTR_FLUSH_LINK_STACK 0x0000000000001000ull
// Features enabled by default // Features enabled by default
#define SEC_FTR_DEFAULT \ #define SEC_FTR_DEFAULT \
......
...@@ -537,6 +537,7 @@ flush_count_cache: ...@@ -537,6 +537,7 @@ flush_count_cache:
/* Save LR into r9 */ /* Save LR into r9 */
mflr r9 mflr r9
// Flush the link stack
.rept 64 .rept 64
bl .+4 bl .+4
.endr .endr
...@@ -546,6 +547,11 @@ flush_count_cache: ...@@ -546,6 +547,11 @@ flush_count_cache:
.balign 32 .balign 32
/* Restore LR */ /* Restore LR */
1: mtlr r9 1: mtlr r9
// If we're just flushing the link stack, return here
3: nop
patch_site 3b patch__flush_link_stack_return
li r9,0x7fff li r9,0x7fff
mtctr r9 mtctr r9
......
...@@ -24,6 +24,7 @@ enum count_cache_flush_type { ...@@ -24,6 +24,7 @@ enum count_cache_flush_type {
COUNT_CACHE_FLUSH_HW = 0x4, COUNT_CACHE_FLUSH_HW = 0x4,
}; };
static enum count_cache_flush_type count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; static enum count_cache_flush_type count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
static bool link_stack_flush_enabled;
bool barrier_nospec_enabled; bool barrier_nospec_enabled;
static bool no_nospec; static bool no_nospec;
...@@ -212,11 +213,19 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c ...@@ -212,11 +213,19 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c
if (ccd) if (ccd)
seq_buf_printf(&s, "Indirect branch cache disabled"); seq_buf_printf(&s, "Indirect branch cache disabled");
if (link_stack_flush_enabled)
seq_buf_printf(&s, ", Software link stack flush");
} else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) { } else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) {
seq_buf_printf(&s, "Mitigation: Software count cache flush"); seq_buf_printf(&s, "Mitigation: Software count cache flush");
if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW) if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW)
seq_buf_printf(&s, " (hardware accelerated)"); seq_buf_printf(&s, " (hardware accelerated)");
if (link_stack_flush_enabled)
seq_buf_printf(&s, ", Software link stack flush");
} else if (btb_flush_enabled) { } else if (btb_flush_enabled) {
seq_buf_printf(&s, "Mitigation: Branch predictor state flush"); seq_buf_printf(&s, "Mitigation: Branch predictor state flush");
} else { } else {
...@@ -377,18 +386,49 @@ static __init int stf_barrier_debugfs_init(void) ...@@ -377,18 +386,49 @@ static __init int stf_barrier_debugfs_init(void)
device_initcall(stf_barrier_debugfs_init); device_initcall(stf_barrier_debugfs_init);
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
static void no_count_cache_flush(void)
{
count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
pr_info("count-cache-flush: software flush disabled.\n");
}
static void toggle_count_cache_flush(bool enable) static void toggle_count_cache_flush(bool enable)
{ {
if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) { if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE) &&
!security_ftr_enabled(SEC_FTR_FLUSH_LINK_STACK))
enable = false;
if (!enable) {
patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP); patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP);
count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
pr_info("count-cache-flush: software flush disabled.\n"); 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();
return; return;
} }
// This enables the branch from _switch to flush_count_cache
patch_branch_site(&patch__call_flush_count_cache, patch_branch_site(&patch__call_flush_count_cache,
(u64)&flush_count_cache, BRANCH_SET_LINK); (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;
// If we just need to flush the link stack, patch an early return
if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {
patch_instruction_site(&patch__flush_link_stack_return, PPC_INST_BLR);
no_count_cache_flush();
return;
}
if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) { if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) {
count_cache_flush_type = COUNT_CACHE_FLUSH_SW; count_cache_flush_type = COUNT_CACHE_FLUSH_SW;
pr_info("count-cache-flush: full software flush sequence enabled.\n"); pr_info("count-cache-flush: full software flush sequence enabled.\n");
...@@ -407,11 +447,20 @@ void setup_count_cache_flush(void) ...@@ -407,11 +447,20 @@ void setup_count_cache_flush(void)
if (no_spectrev2 || cpu_mitigations_off()) { if (no_spectrev2 || cpu_mitigations_off()) {
if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) || if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) ||
security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED)) security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED))
pr_warn("Spectre v2 mitigations not under software control, can't disable\n"); pr_warn("Spectre v2 mitigations not fully under software control, can't disable\n");
enable = false; enable = false;
} }
/*
* There's no firmware feature flag/hypervisor bit to tell us we need to
* flush the link stack on context switch. So we set it here if we see
* either of the Spectre v2 mitigations that aim to protect userspace.
*/
if (security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED) ||
security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE))
security_ftr_set(SEC_FTR_FLUSH_LINK_STACK);
toggle_count_cache_flush(enable); toggle_count_cache_flush(enable);
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <asm/ppc_asm.h> #include <asm/ppc_asm.h>
#include <asm/code-patching-asm.h>
#include <asm/kvm_asm.h> #include <asm/kvm_asm.h>
#include <asm/reg.h> #include <asm/reg.h>
#include <asm/mmu.h> #include <asm/mmu.h>
...@@ -1487,6 +1488,13 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ ...@@ -1487,6 +1488,13 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
1: 1:
#endif /* CONFIG_KVM_XICS */ #endif /* CONFIG_KVM_XICS */
/*
* Possibly flush the link stack here, before we do a blr in
* guest_exit_short_path.
*/
1: nop
patch_site 1b patch__call_kvm_flush_link_stack
/* If we came in through the P9 short path, go back out to C now */ /* If we came in through the P9 short path, go back out to C now */
lwz r0, STACK_SLOT_SHORT_PATH(r1) lwz r0, STACK_SLOT_SHORT_PATH(r1)
cmpwi r0, 0 cmpwi r0, 0
...@@ -1963,6 +1971,28 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) ...@@ -1963,6 +1971,28 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
mtlr r0 mtlr r0
blr 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
kvmppc_guest_external: kvmppc_guest_external:
/* External interrupt, first check for host_ipi. If this is /* External interrupt, first check for host_ipi. If this is
* set, we know the host wants us out so let's do it now * set, we know the host wants us out so let's do it now
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment