aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>2019-01-23 01:21:38 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2019-01-31 04:10:15 -0500
commit579b9239c1f38665b21e8d0e6ee83ecc96dbd6bb (patch)
treef42a19c9877dcd2c0f2cc0204ec2b64b99587000
parent7bea7ac0ca0121798f3618d16201ca4dc4e67a00 (diff)
powerpc/radix: Fix kernel crash with mremap()
With support for split pmd lock, we use pmd page pmd_huge_pte pointer to store the deposited page table. In those config when we move page tables we need to make sure we move the deposited page table to the correct pmd page. Otherwise this can result in crash when we withdraw of deposited page table because we can find the pmd_huge_pte NULL. eg: __split_huge_pmd+0x1070/0x1940 __split_huge_pmd+0xe34/0x1940 (unreliable) vma_adjust_trans_huge+0x110/0x1c0 __vma_adjust+0x2b4/0x9b0 __split_vma+0x1b8/0x280 __do_munmap+0x13c/0x550 sys_mremap+0x220/0x7e0 system_call+0x5c/0x70 Fixes: 675d995297d4 ("powerpc/book3s64: Enable split pmd ptlock.") Cc: stable@vger.kernel.org # v4.18+ Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h22
-rw-r--r--arch/powerpc/mm/pgtable-book3s64.c22
2 files changed, 29 insertions, 15 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 2e6ada28da64..c9bfe526ca9d 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1258,21 +1258,13 @@ extern pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
1258 1258
1259#define pmd_move_must_withdraw pmd_move_must_withdraw 1259#define pmd_move_must_withdraw pmd_move_must_withdraw
1260struct spinlock; 1260struct spinlock;
1261static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, 1261extern int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
1262 struct spinlock *old_pmd_ptl, 1262 struct spinlock *old_pmd_ptl,
1263 struct vm_area_struct *vma) 1263 struct vm_area_struct *vma);
1264{ 1264/*
1265 if (radix_enabled()) 1265 * Hash translation mode use the deposited table to store hash pte
1266 return false; 1266 * slot information.
1267 /* 1267 */
1268 * Archs like ppc64 use pgtable to store per pmd
1269 * specific information. So when we switch the pmd,
1270 * we should also withdraw and deposit the pgtable
1271 */
1272 return true;
1273}
1274
1275
1276#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit 1268#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit
1277static inline bool arch_needs_pgtable_deposit(void) 1269static inline bool arch_needs_pgtable_deposit(void)
1278{ 1270{
diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c
index f3c31f5e1026..ecd31569a120 100644
--- a/arch/powerpc/mm/pgtable-book3s64.c
+++ b/arch/powerpc/mm/pgtable-book3s64.c
@@ -400,3 +400,25 @@ void arch_report_meminfo(struct seq_file *m)
400 atomic_long_read(&direct_pages_count[MMU_PAGE_1G]) << 20); 400 atomic_long_read(&direct_pages_count[MMU_PAGE_1G]) << 20);
401} 401}
402#endif /* CONFIG_PROC_FS */ 402#endif /* CONFIG_PROC_FS */
403
404/*
405 * For hash translation mode, we use the deposited table to store hash slot
406 * information and they are stored at PTRS_PER_PMD offset from related pmd
407 * location. Hence a pmd move requires deposit and withdraw.
408 *
409 * For radix translation with split pmd ptl, we store the deposited table in the
410 * pmd page. Hence if we have different pmd page we need to withdraw during pmd
411 * move.
412 *
413 * With hash we use deposited table always irrespective of anon or not.
414 * With radix we use deposited table only for anonymous mapping.
415 */
416int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
417 struct spinlock *old_pmd_ptl,
418 struct vm_area_struct *vma)
419{
420 if (radix_enabled())
421 return (new_pmd_ptl != old_pmd_ptl) && vma_is_anonymous(vma);
422
423 return true;
424}