aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/include/asm
diff options
context:
space:
mode:
authorHong H. Pham <hong.pham@windriver.com>2013-12-07 09:06:33 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-20 10:45:09 -0500
commit21261e510cfb5d807fb827b6c01330daa7e0c330 (patch)
tree4e7525df0699168bc83c406bc6a1ed6ca5532c2d /arch/powerpc/include/asm
parentb96e6f2b02fd5e07a972242c0f2ddf1ccb9882f1 (diff)
powerpc: Fix PTE page address mismatch in pgtable ctor/dtor
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/powerpc/include/asm')
-rw-r--r--arch/powerpc/include/asm/pgalloc-32.h6
-rw-r--r--arch/powerpc/include/asm/pgalloc-64.h6
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 27b2386f738a..842846c1b711 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,
84static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table, 84static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
85 unsigned long address) 85 unsigned long address)
86{ 86{
87 struct page *page = page_address(table);
88
89 tlb_flush_pgtable(tlb, address); 87 tlb_flush_pgtable(tlb, address);
90 pgtable_page_dtor(page); 88 pgtable_page_dtor(table);
91 pgtable_free_tlb(tlb, page, 0); 89 pgtable_free_tlb(tlb, page_address(table), 0);
92} 90}
93#endif /* _ASM_POWERPC_PGALLOC_32_H */ 91#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 b66ae722a8e9..64aaf016b478 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,
144static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table, 144static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
145 unsigned long address) 145 unsigned long address)
146{ 146{
147 struct page *page = page_address(table);
148
149 tlb_flush_pgtable(tlb, address); 147 tlb_flush_pgtable(tlb, address);
150 pgtable_page_dtor(page); 148 pgtable_page_dtor(table);
151 pgtable_free_tlb(tlb, page, 0); 149 pgtable_free_tlb(tlb, page_address(table), 0);
152} 150}
153 151
154#else /* if CONFIG_PPC_64K_PAGES */ 152#else /* if CONFIG_PPC_64K_PAGES */