All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Lorenzo Stoakes (ARM)" <ljs@kernel.org>
To: Vernon Yang <vernon2gm@gmail.com>
Cc: akpm@linux-foundation.org, david@kernel.org,
	nico.pache@linux.dev,  ryan.roberts@arm.com, dev.jain@arm.com,
	baohua@kernel.org, lance.yang@linux.dev,  usama.arif@linux.dev,
	zokeefe@google.com, linux-kernel@vger.kernel.org,
	 linux-mm@kvack.org, Vernon Yang <yanglincheng@kylinos.cn>,
	stable@vger.kernel.org
Subject: Re: [PATCH v2 1/3] mm: khugepaged: fix swap entry value to folio_pfn()
Date: Fri, 21 Aug 2026 18:09:30 +0100	[thread overview]
Message-ID: <aoiDTwCf6320fedN@gremlin> (raw)
In-Reply-To: <aedcacce-4880-41b0-a4a6-d892465fff57@gmail.com>

On Fri, Aug 21, 2026 at 04:17:55PM +0800, Vernon Yang wrote:
> On Mon, Aug 17, 2026 at 05:23:30PM +0100, Lorenzo Stoakes (ARM) wrote:
> > On Mon, Aug 17, 2026 at 05:10:39PM +0100, Lorenzo Stoakes (ARM) wrote:
> > > On Sat, Aug 15, 2026 at 01:19:22PM +0800, Vernon Yang wrote:
> > > > From: Vernon Yang <yanglincheng@kylinos.cn>
> > > >
> > > > When the swap entries found exceed max_ptes_swap, the loop is left via
> > > > break with folio still holding the xarray value that encodes the swap
> > > > entry, not valid folio pointer.
> > > >
> > > > That value is passed to trace_mm_khugepaged_scan_file(), which feeds it
> > > > to folio_pfn(). On FLATMEM and SPARSEMEM_VMEMMAP, the page_to_pfn() is
> > > > plain pointer arithmetic, so the trace event merely prints bogus
> > > > scan_pfn. On classic SPARSEMEM, the page_to_pfn() reads page->flags,
> > > > dereferencing the tiny encoded integer and oopsing khugepaged whenever
> > > > the trace event is enabled.
> > >
> > > Hmm I seem to recall that we were no longer spporting !VMEMMAP SPARSEMEM, but
> > > maybe I was imagining that :)
> >
> > OK seems some museum piece architectures are causing us issues again, fun times
> > (parisc and some mips).
> >
> > >
> > > But this needs fixing in general anyway.
> > >
> > > >
> > > > So when folio is the swap entry value, simply set pfn to -1, just like
> > > > exhausted scan naturally.
> > > >
> > > > And the folio_put() has maybe dropped the last reference of folio. The
> > > > trace_mm_khugepaged_scan_file() is left with a dangling folio pointer.
> > > > so using the folio_pfn() before dropping the reference, closing
> > > > use-after-free window.
> > > >
> > > > Fixes: d41fd2016ed0 ("mm/khugepaged: add tracepoint to hpage_collapse_scan_file()")
> > > > Cc: stable@vger.kernel.org
> > > > Signed-off-by: Vernon Yang <yanglincheng@kylinos.cn>
> > > > ---
> > > >  include/trace/events/huge_memory.h |  6 +++---
> > > >  mm/khugepaged.c                    | 14 +++++++++-----
> > > >  2 files changed, 12 insertions(+), 8 deletions(-)
> > > >
> > > > diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h
> > > > index 291fae364c62..d3572d4ef453 100644
> > > > --- a/include/trace/events/huge_memory.h
> > > > +++ b/include/trace/events/huge_memory.h
> > > > @@ -178,10 +178,10 @@ TRACE_EVENT(mm_collapse_huge_page_swapin,
> > > >
> > > >  TRACE_EVENT(mm_khugepaged_scan_file,
> > > >
> > > > -	TP_PROTO(struct mm_struct *mm, struct folio *folio, struct file *file,
> > > > +	TP_PROTO(struct mm_struct *mm, unsigned long pfn, struct file *file,
> > > >  		 int present, int swap, int result),
> > > >
> > > > -	TP_ARGS(mm, folio, file, present, swap, result),
> > > > +	TP_ARGS(mm, pfn, file, present, swap, result),
> > > >
> > > >  	TP_STRUCT__entry(
> > > >  		__field(struct mm_struct *, mm)
> > > > @@ -194,7 +194,7 @@ TRACE_EVENT(mm_khugepaged_scan_file,
> > > >
> > > >  	TP_fast_assign(
> > > >  		__entry->mm = mm;
> > > > -		__entry->pfn = folio ? folio_pfn(folio) : -1;
> > > > +		__entry->pfn = pfn;
> > >
> > > I wonder how easy it is for people to interpret that this is a PFN of something
> > > only in the case of an early exit.
> > >
> > > It's a bit of a mess that we're exposing internal implementation details like
> > > this, quite honestly.
> > >
> > > I hope there is no expectation of this being there indefinitely.
> > >
> > > >  		__assign_str(filename);
> > > >  		__entry->present = present;
> > > >  		__entry->swap = swap;
> > > > diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> > > > index 617bca76db49..e7830761d3a2 100644
> > > > --- a/mm/khugepaged.c
> > > > +++ b/mm/khugepaged.c
> > > > @@ -2683,6 +2683,7 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm,
> > > >  	int present, swap;
> > > >  	int node = NUMA_NO_NODE;
> > > >  	enum scan_result result = SCAN_SUCCEED;
> > > > +	unsigned long pfn;
> > >
> > > See below I think we should drop it.
> >
> > OK we can't because of museum piece architectures that will actually deref the
> > folio to get the PFN...
> >
> > I'd startr by initialising this to -1 then since I guess in theory it's possible
> > xas_for_each() could just not do anything is it? (folio is being set to NULL so
> > that suggests so).
> >
> > >
> > > >
> > > >  	present = 0;
> > > >  	swap = 0;
> > > > @@ -2720,27 +2721,23 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm,
> > > >  			 * PMD-sized THP implies that we can only try
> > > >  			 * retracting the PTE table.
> > > >  			 */
> > > > -			folio_put(folio);
> >
> > I still hate the idea of moving these outside of the loop, it's just asking for trouble.
> >
> > So I guess instead:
> >
> > 	xas_for_each(&xas, folio, start + HPAGE_PMD_NR - 1) {
> > 		pfn = -1;
> > 		...
> > 		if (xa_is_value(folio)) {
> > 			...
> > 		}
> > 		pfn = folio_pfn(folio);
> > 		...
> > 	}
> > 	...
> > 	trace_mm_khugepaged_scan_file(mm, pfn, file, present, swap, result);
> >
> > That way you avoid the horror or moving the folio put somewhere deeply
> > unintuitive and inconsistent, and maintain pfn lifetime for some arches nobody
> > uses.
>
> Thank you for the reference solution. After studying the overall
> process, I found that the above solution still has two issues:
>
> - When `!folio_try_get(folio)` or `folio != xas_reload(&xas)`, if the
>   next `xas_for_each()` iteration happens to terminate, pfn will be
>   incorrect, which is inconsistent with previous versions.

Ah you're right of course!

> - when the `xas_for_each()` iteration to terminate and the folio
>   operation preceding is normal. but pfn will be incorrect, also same
>   issue.

Yeah... :)

>
> To keep it simple, I modified it as follows. Is this OK?
>
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 79effd3f3da4..00337405c0e0 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2689,6 +2689,7 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm,
>  	int present, swap;
>  	int node = NUMA_NO_NODE;
>  	enum scan_result result = SCAN_SUCCEED;
> +	unsigned long pfn;
>
>  	present = 0;
>  	swap = 0;
> @@ -2719,6 +2720,7 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm,
>  			continue;
>  		}
>
> +		pfn = folio_pfn(folio);
>  		if (is_pmd_order(folio_order(folio))) {
>  			result = SCAN_PTE_MAPPED_HUGEPAGE;
>  			/*
> @@ -2779,7 +2781,8 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm,
>  		}
>  	}
>
> -	trace_mm_khugepaged_scan_file(mm, folio, file, present, swap, result);
> +	trace_mm_khugepaged_scan_file(mm, (!folio || xa_is_value(folio)) ? -1 : pfn,
> +				      file, present, swap, result);
>  	return result;
>  }

OK looks reasonable, thanks! :)

>
> --
> Cheers,
> Vernon
>

  reply	other threads:[~2026-08-21 17:09 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-15  5:19 [PATCH v2 0/3] mm: khugepaged: fix tracepoint UAF Vernon Yang
2026-08-15  5:19 ` [PATCH v2 1/3] mm: khugepaged: fix swap entry value to folio_pfn() Vernon Yang
2026-08-17 16:10   ` Lorenzo Stoakes (ARM)
2026-08-17 16:19     ` David Hildenbrand (Arm)
2026-08-17 16:24       ` Lorenzo Stoakes (ARM)
2026-08-17 16:23     ` Lorenzo Stoakes (ARM)
2026-08-21  8:17       ` Vernon Yang
2026-08-21 17:09         ` Lorenzo Stoakes (ARM) [this message]
2026-08-15  5:19 ` [PATCH v2 2/3] mm: khugepaged: fix folio is used after pte_unmap_unlock() Vernon Yang
2026-08-17 16:11   ` Lorenzo Stoakes (ARM)
2026-08-17 16:20     ` David Hildenbrand (Arm)
2026-08-17 16:29       ` Lorenzo Stoakes (ARM)
2026-08-17 16:33     ` Lorenzo Stoakes
2026-08-21  8:19       ` Vernon Yang
2026-08-15  5:19 ` [PATCH v2 3/3] mm: khugepaged: fix folio is used after folio_put/unlock() Vernon Yang
2026-08-15 17:44 ` [PATCH v2 0/3] mm: khugepaged: fix tracepoint UAF Lance Yang
2026-08-15 18:16   ` Lance Yang
2026-08-17  2:25     ` Baolin Wang
2026-08-17  2:53       ` Lance Yang
2026-08-17  7:24         ` Baolin Wang
2026-08-17 22:30     ` Andrew Morton
2026-08-21  6:03       ` Vernon Yang

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=aoiDTwCf6320fedN@gremlin \
    --to=ljs@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=baohua@kernel.org \
    --cc=david@kernel.org \
    --cc=dev.jain@arm.com \
    --cc=lance.yang@linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=nico.pache@linux.dev \
    --cc=ryan.roberts@arm.com \
    --cc=stable@vger.kernel.org \
    --cc=usama.arif@linux.dev \
    --cc=vernon2gm@gmail.com \
    --cc=yanglincheng@kylinos.cn \
    --cc=zokeefe@google.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.