0066-x86-cpuid-Add-generic-table-for-CPUID-dependencies.patch 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. From d637e8b6db21d282cfb1fd789ae60807cc87c867 Mon Sep 17 00:00:00 2001
  2. From: Andi Kleen <[email protected]>
  3. Date: Fri, 13 Oct 2017 14:56:42 -0700
  4. Subject: [PATCH 066/242] x86/cpuid: Add generic table for CPUID dependencies
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. CVE-2017-5754
  9. Some CPUID features depend on other features. Currently it's
  10. possible to to clear dependent features, but not clear the base features,
  11. which can cause various interesting problems.
  12. This patch implements a generic table to describe dependencies
  13. between CPUID features, to be used by all code that clears
  14. CPUID.
  15. Some subsystems (like XSAVE) had an own implementation of this,
  16. but it's better to do it all in a single place for everyone.
  17. Then clear_cpu_cap and setup_clear_cpu_cap always look up
  18. this table and clear all dependencies too.
  19. This is intended to be a practical table: only for features
  20. that make sense to clear. If someone for example clears FPU,
  21. or other features that are essentially part of the required
  22. base feature set, not much is going to work. Handling
  23. that is right now out of scope. We're only handling
  24. features which can be usefully cleared.
  25. Signed-off-by: Andi Kleen <[email protected]>
  26. Reviewed-by: Thomas Gleixner <[email protected]>
  27. Cc: Jonathan McDowell <[email protected]>
  28. Cc: Linus Torvalds <[email protected]>
  29. Cc: Peter Zijlstra <[email protected]>
  30. Link: http://lkml.kernel.org/r/[email protected]
  31. Signed-off-by: Ingo Molnar <[email protected]>
  32. (cherry picked from commit 0b00de857a648dafe7020878c7a27cf776f5edf4)
  33. Signed-off-by: Andy Whitcroft <[email protected]>
  34. Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
  35. (cherry picked from commit 35672522f2fc9a2e116ed1766f190bc08ef5582a)
  36. Signed-off-by: Fabian Grünbichler <[email protected]>
  37. ---
  38. arch/x86/kernel/cpu/Makefile | 1 +
  39. arch/x86/include/asm/cpufeature.h | 9 ++-
  40. arch/x86/include/asm/cpufeatures.h | 5 ++
  41. arch/x86/kernel/cpu/cpuid-deps.c | 113 +++++++++++++++++++++++++++++++++++++
  42. 4 files changed, 123 insertions(+), 5 deletions(-)
  43. create mode 100644 arch/x86/kernel/cpu/cpuid-deps.c
  44. diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
  45. index e17942c131c8..de260fae1017 100644
  46. --- a/arch/x86/kernel/cpu/Makefile
  47. +++ b/arch/x86/kernel/cpu/Makefile
  48. @@ -22,6 +22,7 @@ obj-y += rdrand.o
  49. obj-y += match.o
  50. obj-y += bugs.o
  51. obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
  52. +obj-y += cpuid-deps.o
  53. obj-$(CONFIG_PROC_FS) += proc.o
  54. obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
  55. diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
  56. index d59c15c3defd..225fd8374fae 100644
  57. --- a/arch/x86/include/asm/cpufeature.h
  58. +++ b/arch/x86/include/asm/cpufeature.h
  59. @@ -125,11 +125,10 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
  60. #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
  61. #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability))
  62. -#define clear_cpu_cap(c, bit) clear_bit(bit, (unsigned long *)((c)->x86_capability))
  63. -#define setup_clear_cpu_cap(bit) do { \
  64. - clear_cpu_cap(&boot_cpu_data, bit); \
  65. - set_bit(bit, (unsigned long *)cpu_caps_cleared); \
  66. -} while (0)
  67. +
  68. +extern void setup_clear_cpu_cap(unsigned int bit);
  69. +extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
  70. +
  71. #define setup_force_cpu_cap(bit) do { \
  72. set_cpu_cap(&boot_cpu_data, bit); \
  73. set_bit(bit, (unsigned long *)cpu_caps_set); \
  74. diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
  75. index 5a28e8e55e36..f4e145c4b06f 100644
  76. --- a/arch/x86/include/asm/cpufeatures.h
  77. +++ b/arch/x86/include/asm/cpufeatures.h
  78. @@ -21,6 +21,11 @@
  79. * this feature bit is not displayed in /proc/cpuinfo at all.
  80. */
  81. +/*
  82. + * When adding new features here that depend on other features,
  83. + * please update the table in kernel/cpu/cpuid-deps.c
  84. + */
  85. +
  86. /* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
  87. #define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */
  88. #define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */
  89. diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
  90. new file mode 100644
  91. index 000000000000..e48eb7313120
  92. --- /dev/null
  93. +++ b/arch/x86/kernel/cpu/cpuid-deps.c
  94. @@ -0,0 +1,113 @@
  95. +/* Declare dependencies between CPUIDs */
  96. +#include <linux/kernel.h>
  97. +#include <linux/init.h>
  98. +#include <linux/module.h>
  99. +#include <asm/cpufeature.h>
  100. +
  101. +struct cpuid_dep {
  102. + unsigned int feature;
  103. + unsigned int depends;
  104. +};
  105. +
  106. +/*
  107. + * Table of CPUID features that depend on others.
  108. + *
  109. + * This only includes dependencies that can be usefully disabled, not
  110. + * features part of the base set (like FPU).
  111. + *
  112. + * Note this all is not __init / __initdata because it can be
  113. + * called from cpu hotplug. It shouldn't do anything in this case,
  114. + * but it's difficult to tell that to the init reference checker.
  115. + */
  116. +const static struct cpuid_dep cpuid_deps[] = {
  117. + { X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE },
  118. + { X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE },
  119. + { X86_FEATURE_XSAVES, X86_FEATURE_XSAVE },
  120. + { X86_FEATURE_AVX, X86_FEATURE_XSAVE },
  121. + { X86_FEATURE_PKU, X86_FEATURE_XSAVE },
  122. + { X86_FEATURE_MPX, X86_FEATURE_XSAVE },
  123. + { X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE },
  124. + { X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR },
  125. + { X86_FEATURE_XMM, X86_FEATURE_FXSR },
  126. + { X86_FEATURE_XMM2, X86_FEATURE_XMM },
  127. + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 },
  128. + { X86_FEATURE_XMM4_1, X86_FEATURE_XMM2 },
  129. + { X86_FEATURE_XMM4_2, X86_FEATURE_XMM2 },
  130. + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 },
  131. + { X86_FEATURE_PCLMULQDQ, X86_FEATURE_XMM2 },
  132. + { X86_FEATURE_SSSE3, X86_FEATURE_XMM2, },
  133. + { X86_FEATURE_F16C, X86_FEATURE_XMM2, },
  134. + { X86_FEATURE_AES, X86_FEATURE_XMM2 },
  135. + { X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 },
  136. + { X86_FEATURE_FMA, X86_FEATURE_AVX },
  137. + { X86_FEATURE_AVX2, X86_FEATURE_AVX, },
  138. + { X86_FEATURE_AVX512F, X86_FEATURE_AVX, },
  139. + { X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F },
  140. + { X86_FEATURE_AVX512PF, X86_FEATURE_AVX512F },
  141. + { X86_FEATURE_AVX512ER, X86_FEATURE_AVX512F },
  142. + { X86_FEATURE_AVX512CD, X86_FEATURE_AVX512F },
  143. + { X86_FEATURE_AVX512DQ, X86_FEATURE_AVX512F },
  144. + { X86_FEATURE_AVX512BW, X86_FEATURE_AVX512F },
  145. + { X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F },
  146. + { X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F },
  147. + { X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F },
  148. + { X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
  149. + { X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
  150. + {}
  151. +};
  152. +
  153. +static inline void __clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit)
  154. +{
  155. + clear_bit32(bit, c->x86_capability);
  156. +}
  157. +
  158. +static inline void __setup_clear_cpu_cap(unsigned int bit)
  159. +{
  160. + clear_cpu_cap(&boot_cpu_data, bit);
  161. + set_bit32(bit, cpu_caps_cleared);
  162. +}
  163. +
  164. +static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature)
  165. +{
  166. + if (!c)
  167. + __setup_clear_cpu_cap(feature);
  168. + else
  169. + __clear_cpu_cap(c, feature);
  170. +}
  171. +
  172. +static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
  173. +{
  174. + bool changed;
  175. + DECLARE_BITMAP(disable, NCAPINTS * sizeof(u32) * 8);
  176. + const struct cpuid_dep *d;
  177. +
  178. + clear_feature(c, feature);
  179. +
  180. + /* Collect all features to disable, handling dependencies */
  181. + memset(disable, 0, sizeof(disable));
  182. + __set_bit(feature, disable);
  183. +
  184. + /* Loop until we get a stable state. */
  185. + do {
  186. + changed = false;
  187. + for (d = cpuid_deps; d->feature; d++) {
  188. + if (!test_bit(d->depends, disable))
  189. + continue;
  190. + if (__test_and_set_bit(d->feature, disable))
  191. + continue;
  192. +
  193. + changed = true;
  194. + clear_feature(c, d->feature);
  195. + }
  196. + } while (changed);
  197. +}
  198. +
  199. +void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
  200. +{
  201. + do_clear_cpu_cap(c, feature);
  202. +}
  203. +
  204. +void setup_clear_cpu_cap(unsigned int feature)
  205. +{
  206. + do_clear_cpu_cap(NULL, feature);
  207. +}
  208. --
  209. 2.14.2