0107-x86-entry-64-Remove-thread_struct-sp0.patch 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Andy Lutomirski <[email protected]>
  3. Date: Thu, 2 Nov 2017 00:59:16 -0700
  4. Subject: [PATCH] x86/entry/64: Remove thread_struct::sp0
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. CVE-2017-5754
  9. On x86_64, we can easily calculate sp0 when needed instead of
  10. storing it in thread_struct.
  11. On x86_32, a similar cleanup would be possible, but it would require
  12. cleaning up the vm86 code first, and that can wait for a later
  13. cleanup series.
  14. Signed-off-by: Andy Lutomirski <[email protected]>
  15. Cc: Borislav Petkov <[email protected]>
  16. Cc: Brian Gerst <[email protected]>
  17. Cc: Dave Hansen <[email protected]>
  18. Cc: Linus Torvalds <[email protected]>
  19. Cc: Peter Zijlstra <[email protected]>
  20. Cc: Thomas Gleixner <[email protected]>
  21. Link: http://lkml.kernel.org/r/719cd9c66c548c4350d98a90f050aee8b17f8919.1509609304.git.luto@kernel.org
  22. Signed-off-by: Ingo Molnar <[email protected]>
  23. (cherry picked from commit d375cf1530595e33961a8844192cddab913650e3)
  24. Signed-off-by: Andy Whitcroft <[email protected]>
  25. Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
  26. (cherry picked from commit 4910af19c69a87e9432467f4d7cb78da5fbcc30a)
  27. Signed-off-by: Fabian Grünbichler <[email protected]>
  28. ---
  29. arch/x86/include/asm/compat.h | 1 +
  30. arch/x86/include/asm/processor.h | 28 +++++++++-------------------
  31. arch/x86/include/asm/switch_to.h | 6 ++++++
  32. arch/x86/kernel/process_64.c | 1 -
  33. 4 files changed, 16 insertions(+), 20 deletions(-)
  34. diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
  35. index 5343c19814b3..948b6d8ec46f 100644
  36. --- a/arch/x86/include/asm/compat.h
  37. +++ b/arch/x86/include/asm/compat.h
  38. @@ -6,6 +6,7 @@
  39. */
  40. #include <linux/types.h>
  41. #include <linux/sched.h>
  42. +#include <linux/sched/task_stack.h>
  43. #include <asm/processor.h>
  44. #include <asm/user32.h>
  45. #include <asm/unistd.h>
  46. diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
  47. index f83fbf1b6dd9..cec9a329c0f1 100644
  48. --- a/arch/x86/include/asm/processor.h
  49. +++ b/arch/x86/include/asm/processor.h
  50. @@ -423,7 +423,9 @@ typedef struct {
  51. struct thread_struct {
  52. /* Cached TLS descriptors: */
  53. struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
  54. +#ifdef CONFIG_X86_32
  55. unsigned long sp0;
  56. +#endif
  57. unsigned long sp;
  58. #ifdef CONFIG_X86_32
  59. unsigned long sysenter_cs;
  60. @@ -790,6 +792,13 @@ static inline void spin_lock_prefetch(const void *x)
  61. #define task_top_of_stack(task) ((unsigned long)(task_pt_regs(task) + 1))
  62. +#define task_pt_regs(task) \
  63. +({ \
  64. + unsigned long __ptr = (unsigned long)task_stack_page(task); \
  65. + __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING; \
  66. + ((struct pt_regs *)__ptr) - 1; \
  67. +})
  68. +
  69. #ifdef CONFIG_X86_32
  70. /*
  71. * User space process size: 3GB (default).
  72. @@ -807,23 +816,6 @@ static inline void spin_lock_prefetch(const void *x)
  73. .addr_limit = KERNEL_DS, \
  74. }
  75. -/*
  76. - * TOP_OF_KERNEL_STACK_PADDING reserves 8 bytes on top of the ring0 stack.
  77. - * This is necessary to guarantee that the entire "struct pt_regs"
  78. - * is accessible even if the CPU haven't stored the SS/ESP registers
  79. - * on the stack (interrupt gate does not save these registers
  80. - * when switching to the same priv ring).
  81. - * Therefore beware: accessing the ss/esp fields of the
  82. - * "struct pt_regs" is possible, but they may contain the
  83. - * completely wrong values.
  84. - */
  85. -#define task_pt_regs(task) \
  86. -({ \
  87. - unsigned long __ptr = (unsigned long)task_stack_page(task); \
  88. - __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING; \
  89. - ((struct pt_regs *)__ptr) - 1; \
  90. -})
  91. -
  92. #define KSTK_ESP(task) (task_pt_regs(task)->sp)
  93. #else
  94. @@ -853,11 +845,9 @@ static inline void spin_lock_prefetch(const void *x)
  95. #define STACK_TOP_MAX TASK_SIZE_MAX
  96. #define INIT_THREAD { \
  97. - .sp0 = TOP_OF_INIT_STACK, \
  98. .addr_limit = KERNEL_DS, \
  99. }
  100. -#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.sp0 - 1)
  101. extern unsigned long KSTK_ESP(struct task_struct *task);
  102. #endif /* CONFIG_X86_64 */
  103. diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
  104. index 54e64d909725..010cd6e4eafc 100644
  105. --- a/arch/x86/include/asm/switch_to.h
  106. +++ b/arch/x86/include/asm/switch_to.h
  107. @@ -1,6 +1,8 @@
  108. #ifndef _ASM_X86_SWITCH_TO_H
  109. #define _ASM_X86_SWITCH_TO_H
  110. +#include <linux/sched/task_stack.h>
  111. +
  112. struct task_struct; /* one of the stranger aspects of C forward declarations */
  113. struct task_struct *__switch_to_asm(struct task_struct *prev,
  114. @@ -87,7 +89,11 @@ static inline void refresh_sysenter_cs(struct thread_struct *thread)
  115. /* This is used when switching tasks or entering/exiting vm86 mode. */
  116. static inline void update_sp0(struct task_struct *task)
  117. {
  118. +#ifdef CONFIG_X86_32
  119. load_sp0(task->thread.sp0);
  120. +#else
  121. + load_sp0(task_top_of_stack(task));
  122. +#endif
  123. }
  124. #endif /* _ASM_X86_SWITCH_TO_H */
  125. diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
  126. index 8a748e17bf6e..b08b9b6c40eb 100644
  127. --- a/arch/x86/kernel/process_64.c
  128. +++ b/arch/x86/kernel/process_64.c
  129. @@ -275,7 +275,6 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
  130. struct inactive_task_frame *frame;
  131. struct task_struct *me = current;
  132. - p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE;
  133. childregs = task_pt_regs(p);
  134. fork_frame = container_of(childregs, struct fork_frame, regs);
  135. frame = &fork_frame->frame;
  136. --
  137. 2.14.2