Skip to content

Commit 0c95cba

Browse files
npiggintorvalds
authored andcommitted
mm: apply_to_pte_range warn and fail if a large pte is encountered
apply_to_pte_range might mistake a large pte for bad, or treat it as a page table, resulting in a crash or corruption. Add a test to warn and return error if large entries are found. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Nicholas Piggin <[email protected]> Reviewed-by: Miaohe Lin <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Ding Tianhong <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Russell King <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Uladzislau Rezki (Sony) <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent c0eb315 commit 0c95cba

File tree

1 file changed

+49
-17
lines changed

1 file changed

+49
-17
lines changed

mm/memory.c

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,13 +2457,21 @@ static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
24572457
}
24582458
do {
24592459
next = pmd_addr_end(addr, end);
2460-
if (create || !pmd_none_or_clear_bad(pmd)) {
2461-
err = apply_to_pte_range(mm, pmd, addr, next, fn, data,
2462-
create, mask);
2463-
if (err)
2464-
break;
2460+
if (pmd_none(*pmd) && !create)
2461+
continue;
2462+
if (WARN_ON_ONCE(pmd_leaf(*pmd)))
2463+
return -EINVAL;
2464+
if (!pmd_none(*pmd) && WARN_ON_ONCE(pmd_bad(*pmd))) {
2465+
if (!create)
2466+
continue;
2467+
pmd_clear_bad(pmd);
24652468
}
2469+
err = apply_to_pte_range(mm, pmd, addr, next,
2470+
fn, data, create, mask);
2471+
if (err)
2472+
break;
24662473
} while (pmd++, addr = next, addr != end);
2474+
24672475
return err;
24682476
}
24692477

@@ -2485,13 +2493,21 @@ static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d,
24852493
}
24862494
do {
24872495
next = pud_addr_end(addr, end);
2488-
if (create || !pud_none_or_clear_bad(pud)) {
2489-
err = apply_to_pmd_range(mm, pud, addr, next, fn, data,
2490-
create, mask);
2491-
if (err)
2492-
break;
2496+
if (pud_none(*pud) && !create)
2497+
continue;
2498+
if (WARN_ON_ONCE(pud_leaf(*pud)))
2499+
return -EINVAL;
2500+
if (!pud_none(*pud) && WARN_ON_ONCE(pud_bad(*pud))) {
2501+
if (!create)
2502+
continue;
2503+
pud_clear_bad(pud);
24932504
}
2505+
err = apply_to_pmd_range(mm, pud, addr, next,
2506+
fn, data, create, mask);
2507+
if (err)
2508+
break;
24942509
} while (pud++, addr = next, addr != end);
2510+
24952511
return err;
24962512
}
24972513

@@ -2513,13 +2529,21 @@ static int apply_to_p4d_range(struct mm_struct *mm, pgd_t *pgd,
25132529
}
25142530
do {
25152531
next = p4d_addr_end(addr, end);
2516-
if (create || !p4d_none_or_clear_bad(p4d)) {
2517-
err = apply_to_pud_range(mm, p4d, addr, next, fn, data,
2518-
create, mask);
2519-
if (err)
2520-
break;
2532+
if (p4d_none(*p4d) && !create)
2533+
continue;
2534+
if (WARN_ON_ONCE(p4d_leaf(*p4d)))
2535+
return -EINVAL;
2536+
if (!p4d_none(*p4d) && WARN_ON_ONCE(p4d_bad(*p4d))) {
2537+
if (!create)
2538+
continue;
2539+
p4d_clear_bad(p4d);
25212540
}
2541+
err = apply_to_pud_range(mm, p4d, addr, next,
2542+
fn, data, create, mask);
2543+
if (err)
2544+
break;
25222545
} while (p4d++, addr = next, addr != end);
2546+
25232547
return err;
25242548
}
25252549

@@ -2539,9 +2563,17 @@ static int __apply_to_page_range(struct mm_struct *mm, unsigned long addr,
25392563
pgd = pgd_offset(mm, addr);
25402564
do {
25412565
next = pgd_addr_end(addr, end);
2542-
if (!create && pgd_none_or_clear_bad(pgd))
2566+
if (pgd_none(*pgd) && !create)
25432567
continue;
2544-
err = apply_to_p4d_range(mm, pgd, addr, next, fn, data, create, &mask);
2568+
if (WARN_ON_ONCE(pgd_leaf(*pgd)))
2569+
return -EINVAL;
2570+
if (!pgd_none(*pgd) && WARN_ON_ONCE(pgd_bad(*pgd))) {
2571+
if (!create)
2572+
continue;
2573+
pgd_clear_bad(pgd);
2574+
}
2575+
err = apply_to_p4d_range(mm, pgd, addr, next,
2576+
fn, data, create, &mask);
25452577
if (err)
25462578
break;
25472579
} while (pgd++, addr = next, addr != end);

0 commit comments

Comments
 (0)