security.c 5.5 KB

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