linux-brain/arch/s390/mm
Christian Borntraeger 215d1f3928 s390/mm: fix page table upgrade vs 2ndary address mode accesses
commit 316ec154810960052d4586b634156c54d0778f74 upstream.

A page table upgrade in a kernel section that uses secondary address
mode will mess up the kernel instructions as follows:

Consider the following scenario: two threads are sharing memory.
On CPU1 thread 1 does e.g. strnlen_user().  That gets to
        old_fs = enable_sacf_uaccess();
        len = strnlen_user_srst(src, size);
and
                "   la    %2,0(%1)\n"
                "   la    %3,0(%0,%1)\n"
                "   slgr  %0,%0\n"
                "   sacf  256\n"
                "0: srst  %3,%2\n"
in strnlen_user_srst().  At that point we are in secondary space mode,
control register 1 points to kernel page table and instruction fetching
happens via c1, rather than usual c13.  Interrupts are not disabled, for
obvious reasons.

On CPU2 thread 2 does MAP_FIXED mmap(), forcing the upgrade of page table
from 3-level to e.g. 4-level one.  We'd allocated new top-level table,
set it up and now we hit this:
                notify = 1;
                spin_unlock_bh(&mm->page_table_lock);
        }
        if (notify)
                on_each_cpu(__crst_table_upgrade, mm, 0);
OK, we need to actually change over to use of new page table and we
need that to happen in all threads that are currently running.  Which
happens to include the thread 1.  IPI is delivered and we have
static void __crst_table_upgrade(void *arg)
{
        struct mm_struct *mm = arg;

        if (current->active_mm == mm)
                set_user_asce(mm);
        __tlb_flush_local();
}
run on CPU1.  That does
static inline void set_user_asce(struct mm_struct *mm)
{
        S390_lowcore.user_asce = mm->context.asce;
OK, user page table address updated...
        __ctl_load(S390_lowcore.user_asce, 1, 1);
... and control register 1 set to it.
        clear_cpu_flag(CIF_ASCE_PRIMARY);
}

IPI is run in home space mode, so it's fine - insns are fetched
using c13, which always points to kernel page table.  But as soon
as we return from the interrupt, previous PSW is restored, putting
CPU1 back into secondary space mode, at which point we no longer
get the kernel instructions from the kernel mapping.

The fix is to only fixup the control registers that are currently in use
for user processes during the page table update.  We must also disable
interrupts in enable_sacf_uaccess to synchronize the cr and
thread.mm_segment updates against the on_each-cpu.

Fixes: 0aaba41b58 ("s390: remove all code using the access register mode")
Cc: stable@vger.kernel.org # 4.15+
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
References: CVE-2020-11884
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-04-29 16:31:35 +02:00
..
Makefile License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
cmm.c s390/cmm: fix information leak in cmm_timeout_handler() 2019-11-06 13:06:20 +01:00
dump_pagetables.c s390: unify linker symbols usage 2018-02-27 08:05:23 +01:00
extmem.c s390/extmem: fix gcc 8 stringop-overflow warning 2018-07-02 11:24:50 +02:00
fault.c s390/mm: fix address space detection in exception handling 2019-06-11 12:20:53 +02:00
gmap.c KVM: s390: vsie: Fix possible race when shadowing region 3 tables 2020-04-23 10:30:20 +02:00
gup.c mm, gup: add missing refcount overflow checks on s390 2019-12-05 09:21:25 +01:00
hugetlbpage.c s390/mm: fix dynamic pagetable upgrade for hugetlbfs 2020-02-11 04:33:58 -08:00
init.c mm/memory_hotplug: shrink zones when offlining memory 2020-01-29 16:43:27 +01:00
maccess.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
mem_detect.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
mmap.c exec: pass stack rlimit into mm layout functions 2018-04-11 10:28:37 -07:00
page-states.c s390/mm: fix addressing exception after suspend/resume 2018-08-09 08:05:48 +02:00
pageattr.c s390/mm: Clear huge page storage keys on enable_skey 2018-07-30 11:20:18 +01:00
pgalloc.c s390/mm: fix page table upgrade vs 2ndary address mode accesses 2020-04-29 16:31:35 +02:00
pgtable.c s390/mm: silence compiler warning when compiling without CONFIG_PGSTE 2019-05-31 06:46:23 -07:00
vmem.c mm: pass the vmem_altmap to vmemmap_free 2018-01-08 11:46:23 -08:00