0038-x86-ldt-64-Refresh-DS-and-ES-when-modify_ldt-changes.patch 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. From 34aa933a9bce5fb9c88e6ed98b268cbf058e51eb Mon Sep 17 00:00:00 2001
  2. From: Andy Lutomirski <[email protected]>
  3. Date: Wed, 26 Jul 2017 07:16:30 -0700
  4. Subject: [PATCH 038/242] x86/ldt/64: Refresh DS and ES when modify_ldt changes
  5. an entry
  6. MIME-Version: 1.0
  7. Content-Type: text/plain; charset=UTF-8
  8. Content-Transfer-Encoding: 8bit
  9. CVE-2017-5754
  10. On x86_32, modify_ldt() implicitly refreshes the cached DS and ES
  11. segments because they are refreshed on return to usermode.
  12. On x86_64, they're not refreshed on return to usermode. To improve
  13. determinism and match x86_32's behavior, refresh them when we update
  14. the LDT.
  15. This avoids a situation in which the DS points to a descriptor that is
  16. changed but the old cached segment persists until the next reschedule.
  17. If this happens, then the user-visible state will change
  18. nondeterministically some time after modify_ldt() returns, which is
  19. unfortunate.
  20. Signed-off-by: Andy Lutomirski <[email protected]>
  21. Cc: Borislav Petkov <[email protected]>
  22. Cc: Chang Seok <[email protected]>
  23. Cc: Linus Torvalds <[email protected]>
  24. Cc: Peter Zijlstra <[email protected]>
  25. Cc: Thomas Gleixner <[email protected]>
  26. Signed-off-by: Ingo Molnar <[email protected]>
  27. (cherry picked from commit a632375764aa25c97b78beb56c71b0ba59d1cf83)
  28. Signed-off-by: Andy Whitcroft <[email protected]>
  29. Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
  30. (cherry picked from commit 295cb0b06150958ec84ee4b8844ef7e389e22c4e)
  31. Signed-off-by: Fabian Grünbichler <[email protected]>
  32. ---
  33. arch/x86/kernel/ldt.c | 21 +++++++++++++++++++++
  34. 1 file changed, 21 insertions(+)
  35. diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
  36. index a870910c8565..f0e64db18ac8 100644
  37. --- a/arch/x86/kernel/ldt.c
  38. +++ b/arch/x86/kernel/ldt.c
  39. @@ -21,6 +21,25 @@
  40. #include <asm/mmu_context.h>
  41. #include <asm/syscalls.h>
  42. +static void refresh_ldt_segments(void)
  43. +{
  44. +#ifdef CONFIG_X86_64
  45. + unsigned short sel;
  46. +
  47. + /*
  48. + * Make sure that the cached DS and ES descriptors match the updated
  49. + * LDT.
  50. + */
  51. + savesegment(ds, sel);
  52. + if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT)
  53. + loadsegment(ds, sel);
  54. +
  55. + savesegment(es, sel);
  56. + if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT)
  57. + loadsegment(es, sel);
  58. +#endif
  59. +}
  60. +
  61. /* context.lock is held for us, so we don't need any locking. */
  62. static void flush_ldt(void *__mm)
  63. {
  64. @@ -32,6 +51,8 @@ static void flush_ldt(void *__mm)
  65. pc = &mm->context;
  66. set_ldt(pc->ldt->entries, pc->ldt->nr_entries);
  67. +
  68. + refresh_ldt_segments();
  69. }
  70. /* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
  71. --
  72. 2.14.2