Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Muchun Song" <songmuchun@bytedance.com>,
	"Oscar Salvador" <osalvador@suse.de>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Mike Rapoport" <rppt@kernel.org>
Cc: "Qi Zheng" <qi.zheng@linux.dev>,
	"Lance Yang" <lance.yang@linux.dev>,
	"James Houghton" <jthoughton@google.com>,
	"David Hildenbrand" <david@kernel.org>,
	"Muchun Song" <muchun.song@linux.dev>,
	linux-mm@kvack.org
Subject: Re: [PATCH v2 07/12] mm: hugetlb_vmemmap: simplify shared tail page handling
Date: Mon, 02 Nov 2026 03:52:34 +0000	[thread overview]
Message-ID: <sashiko-outbox-192874@kernel.org> (raw)
In-Reply-To: <20261102032525.3597743-8-songmuchun@bytedance.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mm: hugetlb_vmemmap: uninitialized tail page read in vmemmap_optimize_pte()
--

commit 32511c4a4d8ec3d45e0f629f89666a78dc9372ee
Author: Muchun Song <muchun.song@linux.dev>

mm: hugetlb_vmemmap: simplify shared tail page handling

This commit removes the vmemmap_tail field from struct vmemmap_remap_walk and
updates vmemmap_optimize_pte() and vmemmap_restore_pte() to derive the shared
tail page directly from the folio being processed.

> diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
> index 5e84004db4b87..d0af251aa533c 100644
> --- a/mm/hugetlb_vmemmap.c
> +++ b/mm/hugetlb_vmemmap.c

[ ... ]

> @@ -213,53 +211,53 @@ static struct page *vmemmap_dup_page_from_list(const struct page *src,
>  	return dst;
>  }
>  
> -static void vmemmap_optimize_pte(pte_t *pte, unsigned long addr,
> -				 struct vmemmap_remap_walk *walk)
> +static inline struct page *folio_vmemmap_shared_tail_page(const struct folio *folio)
>  {
> -	struct page *page = pte_page(ptep_get(pte));
> -	pte_t entry;
> -
> -	/* Remapping the head page requires r/w */
> -	if (unlikely(walk->nr_walked == 0)) {
> -		struct page *head;
> +	return vmemmap_shared_tail_page(folio_order(folio), folio_zone(folio));
> +}
>  
> -		VM_WARN_ON_ONCE(!PageHead((const struct page *)addr));
> +static int vmemmap_optimize_pte(pte_t *pte, unsigned long addr,
> +				struct vmemmap_remap_walk *walk)
> +{
> +	const struct page *page = (const struct page *)addr;
> +	const struct folio *folio = page_folio(page);
> +	struct page *src = pte_page(ptep_get(pte)), *dst;
>  
> -		head = vmemmap_dup_page_from_list(page, walk->vmemmap_pages);
> -		entry = mk_pte(head, PAGE_KERNEL);
> +	if (likely(vmemmap_optimizable_pfn(page_to_pfn(page), folio_order(folio)))) {
> +		dst = folio_vmemmap_shared_tail_page(folio);
> +		if (!dst)
> +			return -ENOMEM;
>  	} else {
> -		VM_WARN_ON_ONCE(!PageTail((const struct page *)addr));
> -
> -		/*
> -		 * Map the shared tail page writable. A lockless get that read
> -		 * a non-zero refcount before the remap can still do its
> -		 * cmpxchg after it. The refcount is zero, so the cmpxchg
> -		 * fails and leaves the page unchanged.
> -		 */
> -		entry = mk_pte(walk->vmemmap_tail, PAGE_KERNEL);
> +		dst = vmemmap_dup_page_from_list(src, walk->vmemmap_pages);
>  	}

[Severity: High]
Can calling page_folio(page), folio_order(folio), and
folio_vmemmap_shared_tail_page(folio) on every PTE in vmemmap_optimize_pte()
read uninitialized tail struct pages for bootmem gigantic hugepages?

During early boot in alloc_bootmem_huge_page(), gigantic hugepages mark all
tail pages [pfn + 1, pfn + nr_pages) with memblock_reserved_mark_noinit(), so
memmap_init_reserved_pages() skips initializing their struct pages:

mm/hugetlb.c:alloc_bootmem_huge_page() {
    ...
	if (hugetlb_vmemmap_optimizable(h))
		hugetlb_vmemmap_optimize_bootmem_page(pfn, huge_page_order(h));
    ...
	memblock_reserved_mark_noinit(PFN_PHYS(pfn + 1),
				      (nr_pages - 1) * PAGE_SIZE);
}

When a bootmem gigantic hugepage is not aligned to PAGES_PER_SECTION (for
example, when nr_pages < PAGES_PER_SECTION, such as on 64-bit LoongArch with
16KB base pages where SECTION_SIZE_BITS is 29 and PMD_SHIFT is 25 with
CONFIG_ARCH_FORCE_MAX_ORDER=10), section_set_compound_order_range() returns
early without setting section->compound_page_order:

include/linux/vmemmap-optimization.h:section_set_compound_order_range() {
	unsigned long section_nr = pfn_to_section_nr(pfn);

	if (!IS_ALIGNED(pfn | nr_pages, PAGES_PER_SECTION))
		return;
    ...
}

In that case, sparse_init() allocates regular vmemmap pages via
memmap_alloc(), leaving them uninitialized (or filled with 0xff under
CONFIG_DEBUG_VM).

Later, gather_bootmem_prealloc_node() initializes only the first
VMEMMAP_OPTIMIZATION_NR_STRUCT_PAGES struct pages (covering only the first
vmemmap PTE), and prep_and_add_bootmem_folios() defers initializing the
remaining tail struct pages until after hugetlb_vmemmap_optimize_folios()
runs and fails:

mm/hugetlb.c:gather_bootmem_prealloc_node() {
    ...
		hugetlb_folio_init_vmemmap(folio, h,
					   VMEMMAP_OPTIMIZATION_NR_STRUCT_PAGES);
		init_new_hugetlb_folio(folio);

		if (vmemmap_optimizable_order(pfn_to_section_compound_order(pfn)))
			folio_set_hugetlb_vmemmap_optimized(folio);
    ...
}

mm/hugetlb.c:prep_and_add_bootmem_folios() {
	/* Send list for bulk vmemmap optimization processing */
	hugetlb_vmemmap_optimize_folios(h, folio_list);

	list_for_each_entry_safe(folio, tmp_f, folio_list, lru) {
		if (!folio_test_hugetlb_vmemmap_optimized(folio)) {
			hugetlb_folio_init_tail_vmemmap(folio, h,
					VMEMMAP_OPTIMIZATION_NR_STRUCT_PAGES,
					pages_per_huge_page(h));
		}
    ...
}

Previously, __hugetlb_vmemmap_optimize_folio() derived vmemmap_tail upfront
from the initialized head folio, and vmemmap_optimize_pte() checked
walk->nr_walked == 0 without inspecting tail struct pages.

With this change, on the second and subsequent PTEs (where addr >=
vmemmap_start + VMEMMAP_OPTIMIZATION_SIZE), page->compound_info in the tail
struct page at addr has not been initialized by prep_compound_tail() yet:

1. If the raw vmemmap backing pages are zeroed, page_folio(page) returns page
itself rather than the head folio, folio_order(folio) returns 0, and
vmemmap_optimizable_pfn() returns false. vmemmap_optimize_pte() then falls
back to vmemmap_dup_page_from_list(src, walk->vmemmap_pages) for every tail
PTE, rotating the displaced vmemmap pages across the tail PTEs instead of
mapping the shared tail page, while leaving HPG_vmemmap_optimized set so
prep_and_add_bootmem_folios() skips hugetlb_folio_init_tail_vmemmap().

2. If CONFIG_DEBUG_VM is enabled, page_init_poison() fills the uninitialized
tail struct pages with 0xff. _compound_head(page) then evaluates to the
poisoned tail page itself, and folio_order(folio) reads 0xff, leading to an
out-of-bounds shift in vmemmap_optimizable_pfn() and an out-of-bounds
node_zones access in folio_zone(folio).

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102032525.3597743-1-songmuchun@bytedance.com?part=7


  reply	other threads:[~2026-11-02  3:52 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02  3:25 [PATCH v2 00/12] mm: Decouple folio-based vmemmap optimization from HugeTLB Muchun Song
2026-11-02  3:25 ` [PATCH v2 01/12] mm: hugetlb_vmemmap: remove HugeTLB-specific vmemmap optimization macros Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 02/12] mm: hugetlb_vmemmap: unify VMEMMAP_{SPLIT,REMAP}_NO_TLB_FLUSH Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02 11:30     ` Muchun Song
2026-11-02 12:28     ` Muchun Song
2026-11-02  3:25 ` [PATCH v2 03/12] mm: hugetlb_vmemmap: simplify vmemmap head page handling Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 04/12] mm: hugetlb_vmemmap: generalize vmemmap page allocation Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02 12:08     ` Muchun Song
2026-11-02 12:34     ` Muchun Song
2026-11-02 17:57       ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 05/12] mm: hugetlb_vmemmap: unify writable vmemmap page preparation Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 06/12] mm: hugetlb_vmemmap: rename vmemmap_remap_pte() to vmemmap_optimize_pte() Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 07/12] mm: hugetlb_vmemmap: simplify shared tail page handling Muchun Song
2026-11-02  3:52   ` sashiko-bot [this message]
2026-11-02  6:12     ` Muchun Song
2026-11-02 13:48       ` Huacai Chen
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 08/12] mm: hugetlb_vmemmap: move alloc_vmemmap_page_list() next to its free helper Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 09/12] mm: hugetlb_vmemmap: make vmemmap optimization folio-oriented Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 10/12] mm: hugetlb_vmemmap: make vmemmap restoration folio-oriented Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 11/12] mm: hugetlb_vmemmap: unify vmemmap range restoration Muchun Song
2026-11-02 10:18   ` Mike Rapoport
2026-11-02  3:25 ` [PATCH v2 12/12] mm: hugetlb_vmemmap: make vmemmap PTE conversion folio-oriented Muchun Song
2026-11-02 10:18   ` Mike Rapoport

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-192874@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=david@kernel.org \
    --cc=jthoughton@google.com \
    --cc=lance.yang@linux.dev \
    --cc=linux-mm@kvack.org \
    --cc=muchun.song@linux.dev \
    --cc=osalvador@suse.de \
    --cc=qi.zheng@linux.dev \
    --cc=rppt@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=songmuchun@bytedance.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox