lkml.org 
[lkml]   [2013]   [Dec]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.11 167/208] powerpc: Fix PTE page address mismatch in pgtable ctor/dtor
    Date
    3.11.10.2 -stable review patch.  If anyone has any objections, please let me know.

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

    From: "Hong H. Pham" <hong.pham@windriver.com>

    commit cf77ee54362a245f9a01f240adce03a06c05eb68 upstream.

    In pte_alloc_one(), pgtable_page_ctor() is passed an address that has
    not been converted by page_address() to the newly allocated PTE page.

    When the PTE is freed, __pte_free_tlb() calls pgtable_page_dtor()
    with an address to the PTE page that has been converted by page_address().
    The mismatch in the PTE's page address causes pgtable_page_dtor() to access
    invalid memory, so resources for that PTE (such as the page lock) is not
    properly cleaned up.

    On PPC32, only SMP kernels are affected.

    On PPC64, only SMP kernels with 4K page size are affected.

    This bug was introduced by commit d614bb041209fd7cb5e4b35e11a7b2f6ee8f62b8
    "powerpc: Move the pte free routines from common header".

    On a preempt-rt kernel, a spinlock is dynamically allocated for each
    PTE in pgtable_page_ctor(). When the PTE is freed, calling
    pgtable_page_dtor() with a mismatched page address causes a memory leak,
    as the pointer to the PTE's spinlock is bogus.

    On mainline, there isn't any immediately obvious symptoms, but the
    problem still exists here.

    Fixes: d614bb041209fd7c "powerpc: Move the pte free routes from common header"
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Hong H. Pham <hong.pham@windriver.com>
    Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
    ---
    arch/powerpc/include/asm/pgalloc-32.h | 6 ++----
    arch/powerpc/include/asm/pgalloc-64.h | 6 ++----
    2 files changed, 4 insertions(+), 8 deletions(-)

    diff --git a/arch/powerpc/include/asm/pgalloc-32.h b/arch/powerpc/include/asm/pgalloc-32.h
    index 27b2386..842846c 100644
    --- a/arch/powerpc/include/asm/pgalloc-32.h
    +++ b/arch/powerpc/include/asm/pgalloc-32.h
    @@ -84,10 +84,8 @@ static inline void pgtable_free_tlb(struct mmu_gather *tlb,
    static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
    unsigned long address)
    {
    - struct page *page = page_address(table);
    -
    tlb_flush_pgtable(tlb, address);
    - pgtable_page_dtor(page);
    - pgtable_free_tlb(tlb, page, 0);
    + pgtable_page_dtor(table);
    + pgtable_free_tlb(tlb, page_address(table), 0);
    }
    #endif /* _ASM_POWERPC_PGALLOC_32_H */
    diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
    index f65e27b..256d6f8 100644
    --- a/arch/powerpc/include/asm/pgalloc-64.h
    +++ b/arch/powerpc/include/asm/pgalloc-64.h
    @@ -144,11 +144,9 @@ static inline void pgtable_free_tlb(struct mmu_gather *tlb,
    static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
    unsigned long address)
    {
    - struct page *page = page_address(table);
    -
    tlb_flush_pgtable(tlb, address);
    - pgtable_page_dtor(page);
    - pgtable_free_tlb(tlb, page, 0);
    + pgtable_page_dtor(table);
    + pgtable_free_tlb(tlb, page_address(table), 0);
    }

    #else /* if CONFIG_PPC_64K_PAGES */
    --
    1.8.3.2


    \
     
     \ /
      Last update: 2013-12-20 19:41    [W:3.551 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site