Patch "s390/mm: four page table levels vs. fork" has been added to the 4.4-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
s390/mm: four page table levels vs. fork
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
s390-mm-four-page-table-levels-vs.-fork.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
3446c13b268af86391d06611327006b059b8bab1Mon Sep 17 00:00:00 2001
From: Martin Schwidefsky <[email protected]>
Date: Mon, 15 Feb 2016 14:46:49 +0100
Subject: s390/mm: four page table levels vs. fork
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From: Martin Schwidefsky <[email protected]>
commit 3446c13b268af86391d06611327006b059b8bab1 upstream.
The fork of a process with four page table levels is broken since git commit 6252d702c5311ce9 "[S390] dynamic page tables."
All new mm contexts are created with three page table levels and an asce limit of 4TB. If the parent has four levels dup_mmap will add vmas to the new context which are outside of the asce limit. The subsequent call to copy_page_range will walk the three level page table structure of the new process with non-zero pgd and pud indexes. This leads to memory clobbers as the pgd_index *and* the pud_index is added to the mm->pgd pointer without a pgd_deref in between.
The init_new_context() function is selecting the number of page table levels for a new context. The function is used by mm_init() which in turn is called by dup_mm() and mm_alloc(). These two are used by fork() and exec(). The init_new_context() function can distinguish the two cases by looking at mm->context.asce_limit, for fork() the mm struct has been copied and the number of page table levels may not change. For exec() the mm_alloc() function set the new mm structure to zero, in this case a three-level page table is created as the temporary stack space is located at STACK_TOP_MAX = 4TB.
This fixes CVE-2016-2143.
--- arch/s390/include/asm/mmu_context.h | 16 +++++++++++----- arch/s390/include/asm/pgalloc.h | 24 +++++++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-)
arch/s390/include/asm/mmu_context.h +11 -5
@@ -15,17 +15,25 @@static inline int init_new_context (struct task_struct *tsk,struct mm_struct *mm) { +spin_lock_init (&mm->context.list_lock); +INIT_LIST_HEAD (&mm->context.pgtable_list); +INIT_LIST_HEAD (&mm->context.gmap_list);cpumask_clear (&mm->context.cpu_attach_mask);atomic_set (&mm->context.attach_count,0 ); mm->context.flush_mm =0 ; - mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; - mm->context.asce_bits |= _ASCE_TYPE_REGION3;#ifdef CONFIG_PGSTE mm->context.alloc_pgste = page_table_allocate_pgste; mm->context.has_pgste =0 ; mm->context.use_skey =0 ;#endif - mm->context.asce_limit =STACK_TOP_MAX ; +if (mm->context.asce_limit ==0 ) { +/* context created by exec, set asce limit to 4TB */ + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | _ASCE_TYPE_REGION3; + mm->context.asce_limit =STACK_TOP_MAX ; + }else if (mm->context.asce_limit == (1UL <<31 )) { +mm_inc_nr_pmds (mm); + }crst_table_init ((unsigned long *) mm->pgd,pgd_entry_type (mm));return 0 ; }
@@ -111,8 +119,6 @@ static inline void activate_mm(struct mmstatic inline void arch_dup_mmap (struct mm_struct *oldmm,struct mm_struct *mm) { -if (oldmm->context.asce_limit < mm->context.asce_limit) -crst_table_downgrade (mm, oldmm->context.asce_limit); }static inline void arch_exit_mmap (struct mm_struct *mm)
arch/s390/include/asm/pgalloc.h +19 -5
@@ -100,12 +100,26 @@ static inline void pud_populate(struct mstatic inline pgd_t *pgd_alloc (struct mm_struct *mm) { -spin_lock_init (&mm->context.list_lock); -INIT_LIST_HEAD (&mm->context.pgtable_list); -INIT_LIST_HEAD (&mm->context.gmap_list); -return (pgd_t *)crst_table_alloc (mm); +unsigned long *table =crst_table_alloc (mm); + +if (!table) +return NULL ; +if (mm->context.asce_limit == (1UL <<31 )) { +/* Forking a compat process with 2 page table levels */ +if (!pgtable_pmd_page_ctor (virt_to_page (table))) { +crst_table_free (mm, table); +return NULL ; + } + } +return (pgd_t *) table; +} + +static inline void pgd_free (struct mm_struct *mm,pgd_t *pgd) +{ +if (mm->context.asce_limit == (1UL <<31 )) +pgtable_pmd_page_dtor (virt_to_page (pgd)); +crst_table_free (mm, (unsigned long *) pgd); } -#define pgd_free (mm, pgd) crst_table_free(mm, (unsigned long *) pgd)static inline void pmd_populate (struct mm_struct *mm,pmd_t *pmd,pgtable_t pte)
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/s390-mm-four-page-table-levels-vs.-fork.patch queue-4.4/s390-dasd-fix-diag-0x250-inline-assembly.patch