1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Security related flags and so on. 4 // 5 // Copyright 2018, Michael Ellerman, IBM Corporation. 6 7 #include <linux/kernel.h> 8 #include <linux/device.h> 9 #include <linux/seq_buf.h> 10 11 #include <asm/debugfs.h> 12 #include <asm/security_features.h> 13 14 15 unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; 16 17 ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) 18 { 19 bool thread_priv; 20 21 thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); 22 23 if (rfi_flush || thread_priv) { 24 struct seq_buf s; 25 seq_buf_init(&s, buf, PAGE_SIZE - 1); 26 27 seq_buf_printf(&s, "Mitigation: "); 28 29 if (rfi_flush) 30 seq_buf_printf(&s, "RFI Flush"); 31 32 if (rfi_flush && thread_priv) 33 seq_buf_printf(&s, ", "); 34 35 if (thread_priv) 36 seq_buf_printf(&s, "L1D private per thread"); 37 38 seq_buf_printf(&s, "\n"); 39 40 return s.len; 41 } 42 43 if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 44 !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 45 return sprintf(buf, "Not affected\n"); 46 47 return sprintf(buf, "Vulnerable\n"); 48 } 49 50 ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) 51 { 52 if (!security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) 53 return sprintf(buf, "Not affected\n"); 54 55 return sprintf(buf, "Vulnerable\n"); 56 } 57 58 ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) 59 { 60 bool bcs, ccd, ori; 61 struct seq_buf s; 62 63 seq_buf_init(&s, buf, PAGE_SIZE - 1); 64 65 bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); 66 ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); 67 ori = security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31); 68 69 if (bcs || ccd) { 70 seq_buf_printf(&s, "Mitigation: "); 71 72 if (bcs) 73 seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); 74 75 if (bcs && ccd) 76 seq_buf_printf(&s, ", "); 77 78 if (ccd) 79 seq_buf_printf(&s, "Indirect branch cache disabled"); 80 } else 81 seq_buf_printf(&s, "Vulnerable"); 82 83 if (ori) 84 seq_buf_printf(&s, ", ori31 speculation barrier enabled"); 85 86 seq_buf_printf(&s, "\n"); 87 88 return s.len; 89 } 90 91 /* 92 * Store-forwarding barrier support. 93 */ 94 95 static enum stf_barrier_type stf_enabled_flush_types; 96 static bool no_stf_barrier; 97 bool stf_barrier; 98 99 static int __init handle_no_stf_barrier(char *p) 100 { 101 pr_info("stf-barrier: disabled on command line."); 102 no_stf_barrier = true; 103 return 0; 104 } 105 106 early_param("no_stf_barrier", handle_no_stf_barrier); 107 108 /* This is the generic flag used by other architectures */ 109 static int __init handle_ssbd(char *p) 110 { 111 if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { 112 /* Until firmware tells us, we have the barrier with auto */ 113 return 0; 114 } else if (strncmp(p, "off", 3) == 0) { 115 handle_no_stf_barrier(NULL); 116 return 0; 117 } else 118 return 1; 119 120 return 0; 121 } 122 early_param("spec_store_bypass_disable", handle_ssbd); 123 124 /* This is the generic flag used by other architectures */ 125 static int __init handle_no_ssbd(char *p) 126 { 127 handle_no_stf_barrier(NULL); 128 return 0; 129 } 130 early_param("nospec_store_bypass_disable", handle_no_ssbd); 131 132 static void stf_barrier_enable(bool enable) 133 { 134 if (enable) 135 do_stf_barrier_fixups(stf_enabled_flush_types); 136 else 137 do_stf_barrier_fixups(STF_BARRIER_NONE); 138 139 stf_barrier = enable; 140 } 141 142 void setup_stf_barrier(void) 143 { 144 enum stf_barrier_type type; 145 bool enable, hv; 146 147 hv = cpu_has_feature(CPU_FTR_HVMODE); 148 149 /* Default to fallback in case fw-features are not available */ 150 if (cpu_has_feature(CPU_FTR_ARCH_300)) 151 type = STF_BARRIER_EIEIO; 152 else if (cpu_has_feature(CPU_FTR_ARCH_207S)) 153 type = STF_BARRIER_SYNC_ORI; 154 else if (cpu_has_feature(CPU_FTR_ARCH_206)) 155 type = STF_BARRIER_FALLBACK; 156 else 157 type = STF_BARRIER_NONE; 158 159 enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 160 (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || 161 (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); 162 163 if (type == STF_BARRIER_FALLBACK) { 164 pr_info("stf-barrier: fallback barrier available\n"); 165 } else if (type == STF_BARRIER_SYNC_ORI) { 166 pr_info("stf-barrier: hwsync barrier available\n"); 167 } else if (type == STF_BARRIER_EIEIO) { 168 pr_info("stf-barrier: eieio barrier available\n"); 169 } 170 171 stf_enabled_flush_types = type; 172 173 if (!no_stf_barrier) 174 stf_barrier_enable(enable); 175 } 176 177 ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) 178 { 179 if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { 180 const char *type; 181 switch (stf_enabled_flush_types) { 182 case STF_BARRIER_EIEIO: 183 type = "eieio"; 184 break; 185 case STF_BARRIER_SYNC_ORI: 186 type = "hwsync"; 187 break; 188 case STF_BARRIER_FALLBACK: 189 type = "fallback"; 190 break; 191 default: 192 type = "unknown"; 193 } 194 return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); 195 } 196 197 if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 198 !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 199 return sprintf(buf, "Not affected\n"); 200 201 return sprintf(buf, "Vulnerable\n"); 202 } 203 204 #ifdef CONFIG_DEBUG_FS 205 static int stf_barrier_set(void *data, u64 val) 206 { 207 bool enable; 208 209 if (val == 1) 210 enable = true; 211 else if (val == 0) 212 enable = false; 213 else 214 return -EINVAL; 215 216 /* Only do anything if we're changing state */ 217 if (enable != stf_barrier) 218 stf_barrier_enable(enable); 219 220 return 0; 221 } 222 223 static int stf_barrier_get(void *data, u64 *val) 224 { 225 *val = stf_barrier ? 1 : 0; 226 return 0; 227 } 228 229 DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); 230 231 static __init int stf_barrier_debugfs_init(void) 232 { 233 debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); 234 return 0; 235 } 236 device_initcall(stf_barrier_debugfs_init); 237 #endif /* CONFIG_DEBUG_FS */ 238