lkml.org 
[lkml]   [2019]   [Dec]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 062/140] s390/mm: properly clear _PAGE_NOEXEC bit when it is not supported
    Date
    From: Gerald Schaefer <gerald.schaefer@de.ibm.com>

    commit ab874f22d35a8058d8fdee5f13eb69d8867efeae upstream.

    On older HW or under a hypervisor, w/o the instruction-execution-
    protection (IEP) facility, and also w/o EDAT-1, a translation-specification
    exception may be recognized when bit 55 of a pte is one (_PAGE_NOEXEC).

    The current code tries to prevent setting _PAGE_NOEXEC in such cases,
    by removing it within set_pte_at(). However, ptep_set_access_flags()
    will modify a pte directly, w/o using set_pte_at(). There is at least
    one scenario where this can result in an active pte with _PAGE_NOEXEC
    set, which would then lead to a panic due to a translation-specification
    exception (write to swapped out page):

    do_swap_page
    pte = mk_pte (with _PAGE_NOEXEC bit)
    set_pte_at (will remove _PAGE_NOEXEC bit in page table, but keep it
    in local variable pte)
    vmf->orig_pte = pte (pte still contains _PAGE_NOEXEC bit)
    do_wp_page
    wp_page_reuse
    entry = vmf->orig_pte (still with _PAGE_NOEXEC bit)
    ptep_set_access_flags (writes entry with _PAGE_NOEXEC bit)

    Fix this by clearing _PAGE_NOEXEC already in mk_pte_phys(), where the
    pgprot value is applied, so that no pte with _PAGE_NOEXEC will ever be
    visible, if it is not supported. The check in set_pte_at() can then also
    be removed.

    Cc: <stable@vger.kernel.org> # 4.11+
    Fixes: 57d7f939e7bd ("s390: add no-execute support")
    Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
    Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/s390/include/asm/pgtable.h | 4 ++--
    1 file changed, 2 insertions(+), 2 deletions(-)

    --- a/arch/s390/include/asm/pgtable.h
    +++ b/arch/s390/include/asm/pgtable.h
    @@ -1150,8 +1150,6 @@ void gmap_pmdp_idte_global(struct mm_str
    static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
    pte_t *ptep, pte_t entry)
    {
    - if (!MACHINE_HAS_NX)
    - pte_val(entry) &= ~_PAGE_NOEXEC;
    if (pte_present(entry))
    pte_val(entry) &= ~_PAGE_UNUSED;
    if (mm_has_pgste(mm))
    @@ -1168,6 +1166,8 @@ static inline pte_t mk_pte_phys(unsigned
    {
    pte_t __pte;
    pte_val(__pte) = physpage + pgprot_val(pgprot);
    + if (!MACHINE_HAS_NX)
    + pte_val(__pte) &= ~_PAGE_NOEXEC;
    return pte_mkyoung(__pte);
    }


    \
     
     \ /
      Last update: 2019-12-16 19:04    [W:3.196 / U:0.916 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site