lkml.org 
[lkml]   [2017]   [May]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.10 029/129] arm64: Improve detection of user/non-user mappings in set_pte(_at)
    Date
    4.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Catalin Marinas <catalin.marinas@arm.com>

    commit ec663d967b2276448a416406ca59ff247c0c80c5 upstream.

    Commit cab15ce604e5 ("arm64: Introduce execute-only page access
    permissions") allowed a valid user PTE to have the PTE_USER bit clear.
    As a consequence, the pte_valid_not_user() macro in set_pte() was
    replaced with pte_valid_global() under the assumption that only user
    pages have the nG bit set. EFI mappings, however, also have the nG bit
    set and set_pte() wrongly ignores issuing the DSB+ISB.

    This patch reinstates the pte_valid_not_user() macro and adds the
    PTE_UXN bit check since all kernel mappings have this bit set. For
    clarity, pte_exec() is renamed to pte_user_exec() as it only checks for
    the absence of PTE_UXN. Consequently, the user executable check in
    set_pte_at() drops the pte_ng() test since pte_user_exec() is
    sufficient.

    Fixes: cab15ce604e5 ("arm64: Introduce execute-only page access permissions")
    Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
    Signed-off-by: Will Deacon <will.deacon@arm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/arm64/include/asm/pgtable.h | 15 +++++++++------
    1 file changed, 9 insertions(+), 6 deletions(-)

    --- a/arch/arm64/include/asm/pgtable.h
    +++ b/arch/arm64/include/asm/pgtable.h
    @@ -71,9 +71,8 @@ extern unsigned long empty_zero_page[PAG
    #define pte_young(pte) (!!(pte_val(pte) & PTE_AF))
    #define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL))
    #define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE))
    -#define pte_exec(pte) (!(pte_val(pte) & PTE_UXN))
    +#define pte_user_exec(pte) (!(pte_val(pte) & PTE_UXN))
    #define pte_cont(pte) (!!(pte_val(pte) & PTE_CONT))
    -#define pte_ng(pte) (!!(pte_val(pte) & PTE_NG))

    #ifdef CONFIG_ARM64_HW_AFDBM
    #define pte_hw_dirty(pte) (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
    @@ -84,8 +83,12 @@ extern unsigned long empty_zero_page[PAG
    #define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte))

    #define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
    -#define pte_valid_global(pte) \
    - ((pte_val(pte) & (PTE_VALID | PTE_NG)) == PTE_VALID)
    +/*
    + * Execute-only user mappings do not have the PTE_USER bit set. All valid
    + * kernel mappings have the PTE_UXN bit set.
    + */
    +#define pte_valid_not_user(pte) \
    + ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN))
    #define pte_valid_young(pte) \
    ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))

    @@ -178,7 +181,7 @@ static inline void set_pte(pte_t *ptep,
    * Only if the new pte is valid and kernel, otherwise TLB maintenance
    * or update_mmu_cache() have the necessary barriers.
    */
    - if (pte_valid_global(pte)) {
    + if (pte_valid_not_user(pte)) {
    dsb(ishst);
    isb();
    }
    @@ -212,7 +215,7 @@ static inline void set_pte_at(struct mm_
    pte_val(pte) &= ~PTE_RDONLY;
    else
    pte_val(pte) |= PTE_RDONLY;
    - if (pte_ng(pte) && pte_exec(pte) && !pte_special(pte))
    + if (pte_user_exec(pte) && !pte_special(pte))
    __sync_icache_dcache(pte, addr);
    }


    \
     
     \ /
      Last update: 2017-05-11 17:47    [W:4.321 / U:0.268 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site