0032-x86-mm-64-Initialize-CR4.PCIDE-early.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. From d9fd6653e5dd9d80c7c75065329250529281e02d Mon Sep 17 00:00:00 2001
  2. From: Andy Lutomirski <[email protected]>
  3. Date: Sun, 10 Sep 2017 17:48:27 -0700
  4. Subject: [PATCH 032/242] x86/mm/64: Initialize CR4.PCIDE early
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. CVE-2017-5754
  9. cpu_init() is weird: it's called rather late (after early
  10. identification and after most MMU state is initialized) on the boot
  11. CPU but is called extremely early (before identification) on secondary
  12. CPUs. It's called just late enough on the boot CPU that its CR4 value
  13. isn't propagated to mmu_cr4_features.
  14. Even if we put CR4.PCIDE into mmu_cr4_features, we'd hit two
  15. problems. First, we'd crash in the trampoline code. That's
  16. fixable, and I tried that. It turns out that mmu_cr4_features is
  17. totally ignored by secondary_start_64(), though, so even with the
  18. trampoline code fixed, it wouldn't help.
  19. This means that we don't currently have CR4.PCIDE reliably initialized
  20. before we start playing with cpu_tlbstate. This is very fragile and
  21. tends to cause boot failures if I make even small changes to the TLB
  22. handling code.
  23. Make it more robust: initialize CR4.PCIDE earlier on the boot CPU
  24. and propagate it to secondary CPUs in start_secondary().
  25. ( Yes, this is ugly. I think we should have improved mmu_cr4_features
  26. to actually control CR4 during secondary bootup, but that would be
  27. fairly intrusive at this stage. )
  28. Signed-off-by: Andy Lutomirski <[email protected]>
  29. Reported-by: Sai Praneeth Prakhya <[email protected]>
  30. Tested-by: Sai Praneeth Prakhya <[email protected]>
  31. Cc: Borislav Petkov <[email protected]>
  32. Cc: Linus Torvalds <[email protected]>
  33. Cc: Peter Zijlstra <[email protected]>
  34. Cc: Thomas Gleixner <[email protected]>
  35. Cc: [email protected]
  36. Fixes: 660da7c9228f ("x86/mm: Enable CR4.PCIDE on supported systems")
  37. Signed-off-by: Ingo Molnar <[email protected]>
  38. (cherry picked from commit c7ad5ad297e644601747d6dbee978bf85e14f7bc)
  39. Signed-off-by: Andy Whitcroft <[email protected]>
  40. Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
  41. (cherry picked from commit 0e6a37a43aa876327e7d21881c09977da2d5c270)
  42. Signed-off-by: Fabian Grünbichler <[email protected]>
  43. ---
  44. arch/x86/kernel/cpu/common.c | 49 +++++++-------------------------------------
  45. arch/x86/kernel/setup.c | 5 ++++-
  46. arch/x86/kernel/smpboot.c | 8 +++++---
  47. arch/x86/mm/init.c | 34 ++++++++++++++++++++++++++++++
  48. 4 files changed, 50 insertions(+), 46 deletions(-)
  49. diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
  50. index 0b80ed14ff52..4be7b209a3d6 100644
  51. --- a/arch/x86/kernel/cpu/common.c
  52. +++ b/arch/x86/kernel/cpu/common.c
  53. @@ -169,21 +169,21 @@ static int __init x86_mpx_setup(char *s)
  54. __setup("nompx", x86_mpx_setup);
  55. #ifdef CONFIG_X86_64
  56. -static int __init x86_pcid_setup(char *s)
  57. +static int __init x86_nopcid_setup(char *s)
  58. {
  59. - /* require an exact match without trailing characters */
  60. - if (strlen(s))
  61. - return 0;
  62. + /* nopcid doesn't accept parameters */
  63. + if (s)
  64. + return -EINVAL;
  65. /* do not emit a message if the feature is not present */
  66. if (!boot_cpu_has(X86_FEATURE_PCID))
  67. - return 1;
  68. + return 0;
  69. setup_clear_cpu_cap(X86_FEATURE_PCID);
  70. pr_info("nopcid: PCID feature disabled\n");
  71. - return 1;
  72. + return 0;
  73. }
  74. -__setup("nopcid", x86_pcid_setup);
  75. +early_param("nopcid", x86_nopcid_setup);
  76. #endif
  77. static int __init x86_noinvpcid_setup(char *s)
  78. @@ -329,38 +329,6 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
  79. }
  80. }
  81. -static void setup_pcid(struct cpuinfo_x86 *c)
  82. -{
  83. - if (cpu_has(c, X86_FEATURE_PCID)) {
  84. - if (cpu_has(c, X86_FEATURE_PGE)) {
  85. - /*
  86. - * We'd like to use cr4_set_bits_and_update_boot(),
  87. - * but we can't. CR4.PCIDE is special and can only
  88. - * be set in long mode, and the early CPU init code
  89. - * doesn't know this and would try to restore CR4.PCIDE
  90. - * prior to entering long mode.
  91. - *
  92. - * Instead, we rely on the fact that hotplug, resume,
  93. - * etc all fully restore CR4 before they write anything
  94. - * that could have nonzero PCID bits to CR3. CR4.PCIDE
  95. - * has no effect on the page tables themselves, so we
  96. - * don't need it to be restored early.
  97. - */
  98. - cr4_set_bits(X86_CR4_PCIDE);
  99. - } else {
  100. - /*
  101. - * flush_tlb_all(), as currently implemented, won't
  102. - * work if PCID is on but PGE is not. Since that
  103. - * combination doesn't exist on real hardware, there's
  104. - * no reason to try to fully support it, but it's
  105. - * polite to avoid corrupting data if we're on
  106. - * an improperly configured VM.
  107. - */
  108. - clear_cpu_cap(c, X86_FEATURE_PCID);
  109. - }
  110. - }
  111. -}
  112. -
  113. /*
  114. * Protection Keys are not available in 32-bit mode.
  115. */
  116. @@ -1175,9 +1143,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
  117. setup_smep(c);
  118. setup_smap(c);
  119. - /* Set up PCID */
  120. - setup_pcid(c);
  121. -
  122. /*
  123. * The vendor-specific functions might have changed features.
  124. * Now we do "generic changes."
  125. diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
  126. index d7e8b983aa72..f964bfddfefd 100644
  127. --- a/arch/x86/kernel/setup.c
  128. +++ b/arch/x86/kernel/setup.c
  129. @@ -1174,8 +1174,11 @@ void __init setup_arch(char **cmdline_p)
  130. * with the current CR4 value. This may not be necessary, but
  131. * auditing all the early-boot CR4 manipulation would be needed to
  132. * rule it out.
  133. + *
  134. + * Mask off features that don't work outside long mode (just
  135. + * PCIDE for now).
  136. */
  137. - mmu_cr4_features = __read_cr4();
  138. + mmu_cr4_features = __read_cr4() & ~X86_CR4_PCIDE;
  139. memblock_set_current_limit(get_max_mapped());
  140. diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
  141. index 893fd8c849e2..d05006f6c31c 100644
  142. --- a/arch/x86/kernel/smpboot.c
  143. +++ b/arch/x86/kernel/smpboot.c
  144. @@ -227,10 +227,12 @@ static int enable_start_cpu0;
  145. static void notrace start_secondary(void *unused)
  146. {
  147. /*
  148. - * Don't put *anything* before cpu_init(), SMP booting is too
  149. - * fragile that we want to limit the things done here to the
  150. - * most necessary things.
  151. + * Don't put *anything* except direct CPU state initialization
  152. + * before cpu_init(), SMP booting is too fragile that we want to
  153. + * limit the things done here to the most necessary things.
  154. */
  155. + if (boot_cpu_has(X86_FEATURE_PCID))
  156. + __write_cr4(__read_cr4() | X86_CR4_PCIDE);
  157. cpu_init();
  158. x86_cpuinit.early_percpu_clock_init();
  159. preempt_disable();
  160. diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
  161. index bf3f1065d6ad..df2624b091a7 100644
  162. --- a/arch/x86/mm/init.c
  163. +++ b/arch/x86/mm/init.c
  164. @@ -19,6 +19,7 @@
  165. #include <asm/microcode.h>
  166. #include <asm/kaslr.h>
  167. #include <asm/hypervisor.h>
  168. +#include <asm/cpufeature.h>
  169. /*
  170. * We need to define the tracepoints somewhere, and tlb.c
  171. @@ -193,6 +194,38 @@ static void __init probe_page_size_mask(void)
  172. }
  173. }
  174. +static void setup_pcid(void)
  175. +{
  176. +#ifdef CONFIG_X86_64
  177. + if (boot_cpu_has(X86_FEATURE_PCID)) {
  178. + if (boot_cpu_has(X86_FEATURE_PGE)) {
  179. + /*
  180. + * This can't be cr4_set_bits_and_update_boot() --
  181. + * the trampoline code can't handle CR4.PCIDE and
  182. + * it wouldn't do any good anyway. Despite the name,
  183. + * cr4_set_bits_and_update_boot() doesn't actually
  184. + * cause the bits in question to remain set all the
  185. + * way through the secondary boot asm.
  186. + *
  187. + * Instead, we brute-force it and set CR4.PCIDE
  188. + * manually in start_secondary().
  189. + */
  190. + cr4_set_bits(X86_CR4_PCIDE);
  191. + } else {
  192. + /*
  193. + * flush_tlb_all(), as currently implemented, won't
  194. + * work if PCID is on but PGE is not. Since that
  195. + * combination doesn't exist on real hardware, there's
  196. + * no reason to try to fully support it, but it's
  197. + * polite to avoid corrupting data if we're on
  198. + * an improperly configured VM.
  199. + */
  200. + setup_clear_cpu_cap(X86_FEATURE_PCID);
  201. + }
  202. + }
  203. +#endif
  204. +}
  205. +
  206. #ifdef CONFIG_X86_32
  207. #define NR_RANGE_MR 3
  208. #else /* CONFIG_X86_64 */
  209. @@ -592,6 +625,7 @@ void __init init_mem_mapping(void)
  210. unsigned long end;
  211. probe_page_size_mask();
  212. + setup_pcid();
  213. #ifdef CONFIG_X86_64
  214. end = max_pfn << PAGE_SHIFT;
  215. --
  216. 2.14.2