| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- From ac21d052bf1fbdb4162b1fa522703f4f003f37c1 Mon Sep 17 00:00:00 2001
- From: Thomas Gleixner <[email protected]>
- Date: Thu, 14 Dec 2017 12:27:31 +0100
- Subject: [PATCH 170/242] x86/ldt: Prevent LDT inheritance on exec
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- CVE-2017-5754
- The LDT is inherited across fork() or exec(), but that makes no sense
- at all because exec() is supposed to start the process clean.
- The reason why this happens is that init_new_context_ldt() is called from
- init_new_context() which obviously needs to be called for both fork() and
- exec().
- It would be surprising if anything relies on that behaviour, so it seems to
- be safe to remove that misfeature.
- Split the context initialization into two parts. Clear the LDT pointer and
- initialize the mutex from the general context init and move the LDT
- duplication to arch_dup_mmap() which is only called on fork().
- Signed-off-by: Thomas Gleixner <[email protected]>
- Signed-off-by: Peter Zijlstra <[email protected]>
- Cc: Andy Lutomirski <[email protected]>
- Cc: Andy Lutomirsky <[email protected]>
- Cc: Boris Ostrovsky <[email protected]>
- Cc: Borislav Petkov <[email protected]>
- Cc: Borislav Petkov <[email protected]>
- Cc: Brian Gerst <[email protected]>
- Cc: Dave Hansen <[email protected]>
- Cc: Dave Hansen <[email protected]>
- Cc: David Laight <[email protected]>
- Cc: Denys Vlasenko <[email protected]>
- Cc: Eduardo Valentin <[email protected]>
- Cc: Greg KH <[email protected]>
- Cc: H. Peter Anvin <[email protected]>
- Cc: Josh Poimboeuf <[email protected]>
- Cc: Juergen Gross <[email protected]>
- Cc: Linus Torvalds <[email protected]>
- Cc: Will Deacon <[email protected]>
- Cc: [email protected]
- Cc: [email protected]
- Cc: [email protected]
- Cc: [email protected]
- Cc: [email protected]
- Cc: [email protected]
- Signed-off-by: Ingo Molnar <[email protected]>
- (cherry picked from commit a4828f81037f491b2cc986595e3a969a6eeb2fb5)
- Signed-off-by: Andy Whitcroft <[email protected]>
- Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
- (cherry picked from commit f90d254204df4b336731f23bb5417226f51e8651)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- arch/x86/include/asm/mmu_context.h | 21 ++++++++++++++-------
- arch/x86/kernel/ldt.c | 18 +++++-------------
- tools/testing/selftests/x86/ldt_gdt.c | 9 +++------
- 3 files changed, 22 insertions(+), 26 deletions(-)
- diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
- index dd865c2acb9d..47ec51a821e8 100644
- --- a/arch/x86/include/asm/mmu_context.h
- +++ b/arch/x86/include/asm/mmu_context.h
- @@ -56,11 +56,17 @@ struct ldt_struct {
- /*
- * Used for LDT copy/destruction.
- */
- -int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm);
- +static inline void init_new_context_ldt(struct mm_struct *mm)
- +{
- + mm->context.ldt = NULL;
- + init_rwsem(&mm->context.ldt_usr_sem);
- +}
- +int ldt_dup_context(struct mm_struct *oldmm, struct mm_struct *mm);
- void destroy_context_ldt(struct mm_struct *mm);
- #else /* CONFIG_MODIFY_LDT_SYSCALL */
- -static inline int init_new_context_ldt(struct task_struct *tsk,
- - struct mm_struct *mm)
- +static inline void init_new_context_ldt(struct mm_struct *mm) { }
- +static inline int ldt_dup_context(struct mm_struct *oldmm,
- + struct mm_struct *mm)
- {
- return 0;
- }
- @@ -136,15 +142,16 @@ static inline int init_new_context(struct task_struct *tsk,
- mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id);
- atomic64_set(&mm->context.tlb_gen, 0);
-
- - #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
- +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
- if (cpu_feature_enabled(X86_FEATURE_OSPKE)) {
- /* pkey 0 is the default and always allocated */
- mm->context.pkey_allocation_map = 0x1;
- /* -1 means unallocated or invalid */
- mm->context.execute_only_pkey = -1;
- }
- - #endif
- - return init_new_context_ldt(tsk, mm);
- +#endif
- + init_new_context_ldt(mm);
- + return 0;
- }
- static inline void destroy_context(struct mm_struct *mm)
- {
- @@ -180,7 +187,7 @@ do { \
- static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
- {
- paravirt_arch_dup_mmap(oldmm, mm);
- - return 0;
- + return ldt_dup_context(oldmm, mm);
- }
-
- static inline void arch_exit_mmap(struct mm_struct *mm)
- diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
- index 3e7208f0c350..74a5aaf13f3c 100644
- --- a/arch/x86/kernel/ldt.c
- +++ b/arch/x86/kernel/ldt.c
- @@ -130,28 +130,20 @@ static void free_ldt_struct(struct ldt_struct *ldt)
- }
-
- /*
- - * we do not have to muck with descriptors here, that is
- - * done in switch_mm() as needed.
- + * Called on fork from arch_dup_mmap(). Just copy the current LDT state,
- + * the new task is not running, so nothing can be installed.
- */
- -int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm)
- +int ldt_dup_context(struct mm_struct *old_mm, struct mm_struct *mm)
- {
- struct ldt_struct *new_ldt;
- - struct mm_struct *old_mm;
- int retval = 0;
-
- - init_rwsem(&mm->context.ldt_usr_sem);
- -
- - old_mm = current->mm;
- - if (!old_mm) {
- - mm->context.ldt = NULL;
- + if (!old_mm)
- return 0;
- - }
-
- mutex_lock(&old_mm->context.lock);
- - if (!old_mm->context.ldt) {
- - mm->context.ldt = NULL;
- + if (!old_mm->context.ldt)
- goto out_unlock;
- - }
-
- new_ldt = alloc_ldt_struct(old_mm->context.ldt->nr_entries);
- if (!new_ldt) {
- diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
- index 8e290c9b2c3f..783e1a754b78 100644
- --- a/tools/testing/selftests/x86/ldt_gdt.c
- +++ b/tools/testing/selftests/x86/ldt_gdt.c
- @@ -626,13 +626,10 @@ static void do_multicpu_tests(void)
- static int finish_exec_test(void)
- {
- /*
- - * In a sensible world, this would be check_invalid_segment(0, 1);
- - * For better or for worse, though, the LDT is inherited across exec.
- - * We can probably change this safely, but for now we test it.
- + * Older kernel versions did inherit the LDT on exec() which is
- + * wrong because exec() starts from a clean state.
- */
- - check_valid_segment(0, 1,
- - AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB,
- - 42, true);
- + check_invalid_segment(0, 1);
-
- return nerrs ? 1 : 0;
- }
- --
- 2.14.2
|