0170-x86-ldt-Prevent-LDT-inheritance-on-exec.patch 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. From ac21d052bf1fbdb4162b1fa522703f4f003f37c1 Mon Sep 17 00:00:00 2001
  2. From: Thomas Gleixner <[email protected]>
  3. Date: Thu, 14 Dec 2017 12:27:31 +0100
  4. Subject: [PATCH 170/242] x86/ldt: Prevent LDT inheritance on exec
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. CVE-2017-5754
  9. The LDT is inherited across fork() or exec(), but that makes no sense
  10. at all because exec() is supposed to start the process clean.
  11. The reason why this happens is that init_new_context_ldt() is called from
  12. init_new_context() which obviously needs to be called for both fork() and
  13. exec().
  14. It would be surprising if anything relies on that behaviour, so it seems to
  15. be safe to remove that misfeature.
  16. Split the context initialization into two parts. Clear the LDT pointer and
  17. initialize the mutex from the general context init and move the LDT
  18. duplication to arch_dup_mmap() which is only called on fork().
  19. Signed-off-by: Thomas Gleixner <[email protected]>
  20. Signed-off-by: Peter Zijlstra <[email protected]>
  21. Cc: Andy Lutomirski <[email protected]>
  22. Cc: Andy Lutomirsky <[email protected]>
  23. Cc: Boris Ostrovsky <[email protected]>
  24. Cc: Borislav Petkov <[email protected]>
  25. Cc: Borislav Petkov <[email protected]>
  26. Cc: Brian Gerst <[email protected]>
  27. Cc: Dave Hansen <[email protected]>
  28. Cc: Dave Hansen <[email protected]>
  29. Cc: David Laight <[email protected]>
  30. Cc: Denys Vlasenko <[email protected]>
  31. Cc: Eduardo Valentin <[email protected]>
  32. Cc: Greg KH <[email protected]>
  33. Cc: H. Peter Anvin <[email protected]>
  34. Cc: Josh Poimboeuf <[email protected]>
  35. Cc: Juergen Gross <[email protected]>
  36. Cc: Linus Torvalds <[email protected]>
  37. Cc: Will Deacon <[email protected]>
  38. Cc: [email protected]
  39. Cc: [email protected]
  40. Cc: [email protected]
  41. Cc: [email protected]
  42. Cc: [email protected]
  43. Cc: [email protected]
  44. Signed-off-by: Ingo Molnar <[email protected]>
  45. (cherry picked from commit a4828f81037f491b2cc986595e3a969a6eeb2fb5)
  46. Signed-off-by: Andy Whitcroft <[email protected]>
  47. Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
  48. (cherry picked from commit f90d254204df4b336731f23bb5417226f51e8651)
  49. Signed-off-by: Fabian Grünbichler <[email protected]>
  50. ---
  51. arch/x86/include/asm/mmu_context.h | 21 ++++++++++++++-------
  52. arch/x86/kernel/ldt.c | 18 +++++-------------
  53. tools/testing/selftests/x86/ldt_gdt.c | 9 +++------
  54. 3 files changed, 22 insertions(+), 26 deletions(-)
  55. diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
  56. index dd865c2acb9d..47ec51a821e8 100644
  57. --- a/arch/x86/include/asm/mmu_context.h
  58. +++ b/arch/x86/include/asm/mmu_context.h
  59. @@ -56,11 +56,17 @@ struct ldt_struct {
  60. /*
  61. * Used for LDT copy/destruction.
  62. */
  63. -int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm);
  64. +static inline void init_new_context_ldt(struct mm_struct *mm)
  65. +{
  66. + mm->context.ldt = NULL;
  67. + init_rwsem(&mm->context.ldt_usr_sem);
  68. +}
  69. +int ldt_dup_context(struct mm_struct *oldmm, struct mm_struct *mm);
  70. void destroy_context_ldt(struct mm_struct *mm);
  71. #else /* CONFIG_MODIFY_LDT_SYSCALL */
  72. -static inline int init_new_context_ldt(struct task_struct *tsk,
  73. - struct mm_struct *mm)
  74. +static inline void init_new_context_ldt(struct mm_struct *mm) { }
  75. +static inline int ldt_dup_context(struct mm_struct *oldmm,
  76. + struct mm_struct *mm)
  77. {
  78. return 0;
  79. }
  80. @@ -136,15 +142,16 @@ static inline int init_new_context(struct task_struct *tsk,
  81. mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id);
  82. atomic64_set(&mm->context.tlb_gen, 0);
  83. - #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
  84. +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
  85. if (cpu_feature_enabled(X86_FEATURE_OSPKE)) {
  86. /* pkey 0 is the default and always allocated */
  87. mm->context.pkey_allocation_map = 0x1;
  88. /* -1 means unallocated or invalid */
  89. mm->context.execute_only_pkey = -1;
  90. }
  91. - #endif
  92. - return init_new_context_ldt(tsk, mm);
  93. +#endif
  94. + init_new_context_ldt(mm);
  95. + return 0;
  96. }
  97. static inline void destroy_context(struct mm_struct *mm)
  98. {
  99. @@ -180,7 +187,7 @@ do { \
  100. static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
  101. {
  102. paravirt_arch_dup_mmap(oldmm, mm);
  103. - return 0;
  104. + return ldt_dup_context(oldmm, mm);
  105. }
  106. static inline void arch_exit_mmap(struct mm_struct *mm)
  107. diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
  108. index 3e7208f0c350..74a5aaf13f3c 100644
  109. --- a/arch/x86/kernel/ldt.c
  110. +++ b/arch/x86/kernel/ldt.c
  111. @@ -130,28 +130,20 @@ static void free_ldt_struct(struct ldt_struct *ldt)
  112. }
  113. /*
  114. - * we do not have to muck with descriptors here, that is
  115. - * done in switch_mm() as needed.
  116. + * Called on fork from arch_dup_mmap(). Just copy the current LDT state,
  117. + * the new task is not running, so nothing can be installed.
  118. */
  119. -int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm)
  120. +int ldt_dup_context(struct mm_struct *old_mm, struct mm_struct *mm)
  121. {
  122. struct ldt_struct *new_ldt;
  123. - struct mm_struct *old_mm;
  124. int retval = 0;
  125. - init_rwsem(&mm->context.ldt_usr_sem);
  126. -
  127. - old_mm = current->mm;
  128. - if (!old_mm) {
  129. - mm->context.ldt = NULL;
  130. + if (!old_mm)
  131. return 0;
  132. - }
  133. mutex_lock(&old_mm->context.lock);
  134. - if (!old_mm->context.ldt) {
  135. - mm->context.ldt = NULL;
  136. + if (!old_mm->context.ldt)
  137. goto out_unlock;
  138. - }
  139. new_ldt = alloc_ldt_struct(old_mm->context.ldt->nr_entries);
  140. if (!new_ldt) {
  141. diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
  142. index 8e290c9b2c3f..783e1a754b78 100644
  143. --- a/tools/testing/selftests/x86/ldt_gdt.c
  144. +++ b/tools/testing/selftests/x86/ldt_gdt.c
  145. @@ -626,13 +626,10 @@ static void do_multicpu_tests(void)
  146. static int finish_exec_test(void)
  147. {
  148. /*
  149. - * In a sensible world, this would be check_invalid_segment(0, 1);
  150. - * For better or for worse, though, the LDT is inherited across exec.
  151. - * We can probably change this safely, but for now we test it.
  152. + * Older kernel versions did inherit the LDT on exec() which is
  153. + * wrong because exec() starts from a clean state.
  154. */
  155. - check_valid_segment(0, 1,
  156. - AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB,
  157. - 42, true);
  158. + check_invalid_segment(0, 1);
  159. return nerrs ? 1 : 0;
  160. }
  161. --
  162. 2.14.2