]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
2d6895d5bbf0df6e53051ba4f5e682e546aa7f3b
[thirdparty/kernel/stable-queue.git] /
1 From faeec8e23c10bd30e8aa759a2eb3018dae00f924 Mon Sep 17 00:00:00 2001
2 From: David Hildenbrand <david@redhat.com>
3 Date: Tue, 10 Dec 2024 10:34:37 +0100
4 Subject: mm/page_alloc: don't call pfn_to_page() on possibly non-existent PFN in split_large_buddy()
5
6 From: David Hildenbrand <david@redhat.com>
7
8 commit faeec8e23c10bd30e8aa759a2eb3018dae00f924 upstream.
9
10 In split_large_buddy(), we might call pfn_to_page() on a PFN that might
11 not exist. In corner cases, such as when freeing the highest pageblock in
12 the last memory section, this could result with CONFIG_SPARSEMEM &&
13 !CONFIG_SPARSEMEM_EXTREME in __pfn_to_section() returning NULL and and
14 __section_mem_map_addr() dereferencing that NULL pointer.
15
16 Let's fix it, and avoid doing a pfn_to_page() call for the first
17 iteration, where we already have the page.
18
19 So far this was found by code inspection, but let's just CC stable as the
20 fix is easy.
21
22 Link: https://lkml.kernel.org/r/20241210093437.174413-1-david@redhat.com
23 Fixes: fd919a85cd55 ("mm: page_isolation: prepare for hygienic freelists")
24 Signed-off-by: David Hildenbrand <david@redhat.com>
25 Reported-by: Vlastimil Babka <vbabka@suse.cz>
26 Closes: https://lkml.kernel.org/r/e1a898ba-a717-4d20-9144-29df1a6c8813@suse.cz
27 Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
28 Reviewed-by: Zi Yan <ziy@nvidia.com>
29 Acked-by: Johannes Weiner <hannes@cmpxchg.org>
30 Cc: Yu Zhao <yuzhao@google.com>
31 Cc: <stable@vger.kernel.org>
32 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
33 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
34 ---
35 mm/page_alloc.c | 6 ++++--
36 1 file changed, 4 insertions(+), 2 deletions(-)
37
38 diff --git a/mm/page_alloc.c b/mm/page_alloc.c
39 index 1cb4b8c8886d..cae7b93864c2 100644
40 --- a/mm/page_alloc.c
41 +++ b/mm/page_alloc.c
42 @@ -1238,13 +1238,15 @@ static void split_large_buddy(struct zone *zone, struct page *page,
43 if (order > pageblock_order)
44 order = pageblock_order;
45
46 - while (pfn != end) {
47 + do {
48 int mt = get_pfnblock_migratetype(page, pfn);
49
50 __free_one_page(page, pfn, zone, order, mt, fpi);
51 pfn += 1 << order;
52 + if (pfn == end)
53 + break;
54 page = pfn_to_page(pfn);
55 - }
56 + } while (1);
57 }
58
59 static void free_one_page(struct zone *zone, struct page *page,
60 --
61 2.47.1
62