powerpc/security: Allow for processors that flush the link stack using the special...
authorNicholas Piggin <npiggin@gmail.com>
Tue, 9 Jun 2020 07:06:09 +0000 (17:06 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 16 Jul 2020 03:12:32 +0000 (13:12 +1000)
If both count cache and link stack are to be flushed, and can be flushed
with the special bcctr, patch that in directly to the flush/branch nop
site.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200609070610.846703-7-npiggin@gmail.com
arch/powerpc/include/asm/security_features.h
arch/powerpc/kernel/security.c

index 7c05e95..fbb8fa3 100644 (file)
@@ -63,6 +63,8 @@ static inline bool security_ftr_enabled(u64 feature)
 // bcctr 2,0,0 triggers a hardware assisted count cache flush
 #define SEC_FTR_BCCTR_FLUSH_ASSIST     0x0000000000000800ull
 
+// bcctr 2,0,0 triggers a hardware assisted link stack flush
+#define SEC_FTR_BCCTR_LINK_FLUSH_ASSIST        0x0000000000002000ull
 
 // Features indicating need for Spectre/Meltdown mitigations
 
index 05eeb22..c9876aa 100644 (file)
@@ -219,24 +219,25 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c
                if (ccd)
                        seq_buf_printf(&s, "Indirect branch cache disabled");
 
-               if (link_stack_flush_type == BRANCH_CACHE_FLUSH_SW)
-                       seq_buf_printf(&s, ", Software link stack flush");
-
        } else if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {
                seq_buf_printf(&s, "Mitigation: Software count cache flush");
 
                if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW)
                        seq_buf_printf(&s, " (hardware accelerated)");
 
-               if (link_stack_flush_type == BRANCH_CACHE_FLUSH_SW)
-                       seq_buf_printf(&s, ", Software link stack flush");
-
        } else if (btb_flush_enabled) {
                seq_buf_printf(&s, "Mitigation: Branch predictor state flush");
        } else {
                seq_buf_printf(&s, "Vulnerable");
        }
 
+       if (bcs || ccd || count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {
+               if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE)
+                       seq_buf_printf(&s, ", Software link stack flush");
+               if (link_stack_flush_type == BRANCH_CACHE_FLUSH_HW)
+                       seq_buf_printf(&s, " (hardware accelerated)");
+       }
+
        seq_buf_printf(&s, "\n");
 
        return s.len;
@@ -435,6 +436,7 @@ static void update_branch_cache_flush(void)
                patch_instruction_site(&patch__call_kvm_flush_link_stack,
                                       ppc_inst(PPC_INST_NOP));
        } else {
+               // Could use HW flush, but that could also flush count cache
                patch_branch_site(&patch__call_kvm_flush_link_stack,
                                  (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
        }
@@ -445,6 +447,10 @@ static void update_branch_cache_flush(void)
            link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
                patch_instruction_site(&patch__call_flush_branch_caches,
                                       ppc_inst(PPC_INST_NOP));
+       } else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW &&
+                  link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) {
+               patch_instruction_site(&patch__call_flush_branch_caches,
+                                      ppc_inst(PPC_INST_BCCTR_FLUSH));
        } else {
                patch_branch_site(&patch__call_flush_branch_caches,
                                  (u64)&flush_branch_caches, BRANCH_SET_LINK);
@@ -485,8 +491,13 @@ static void toggle_branch_cache_flush(bool enable)
 
                pr_info("link-stack-flush: flush disabled.\n");
        } else {
-               link_stack_flush_type = BRANCH_CACHE_FLUSH_SW;
-               pr_info("link-stack-flush: software flush enabled.\n");
+               if (security_ftr_enabled(SEC_FTR_BCCTR_LINK_FLUSH_ASSIST)) {
+                       link_stack_flush_type = BRANCH_CACHE_FLUSH_HW;
+                       pr_info("link-stack-flush: hardware flush enabled.\n");
+               } else {
+                       link_stack_flush_type = BRANCH_CACHE_FLUSH_SW;
+                       pr_info("link-stack-flush: software flush enabled.\n");
+               }
        }
 
        update_branch_cache_flush();