From: Mike Rapoport <rppt@kernel.org>
To: Will Deacon <will@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Suren Baghdasaryan <surenb@google.com>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Shakeel Butt <shakeel.butt@linux.dev>,
David Hildenbrand <david@kernel.org>,
Michal Hocko <mhocko@suse.com>,
Uladzislau Rezki <urezki@gmail.com>,
Toshi Kani <toshi.kani@hpe.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Andy Lutomirski <luto@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Borislav Petkov <bp@alien8.de>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
Kiryl Shutsemau <kas@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Dev Jain <dev.jain@arm.com>, Ryan Roberts <ryan.roberts@arm.com>,
David Carlier <devnexen@gmail.com>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
bpf@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
stable@vger.kernel.org, abarnas@google.com
Subject: Re: [PATCH mm-hotfixes v3 2/4] x86/mm/pat: acquire mmap lock on page table free to avoid ptdump UAF
Date: Wed, 15 Jul 2026 18:49:30 +0300 [thread overview]
Message-ID: <alesCtwXdIqH6bOP@kernel.org> (raw)
In-Reply-To: <alemS7vxeRB7NcBO@willie-the-truck>
Hi Will,
On Wed, Jul 15, 2026 at 04:24:59PM +0100, Will Deacon wrote:
> Hi Lorenzo,
>
> I'm certainly no x86 expert (quite the opposite!), but I was looking at
> this with Adrian and got myself confused. See below.
>
> On Tue, Jul 14, 2026 at 06:24:24PM +0100, Lorenzo Stoakes wrote:
> > x86 implements page attribute modification using its Change Page
> > Attributes (CPA) mechanism.
> >
> > This tracks properties of ranges such as cache mode through x86 page
> > attributes, and as part of that logic manipulates kernel page tables.
> >
> > Since commit 41d88484c71c ("x86/mm/pat: restore large ROX pages after
> > fragmentation") ranges of kernel page table entries can be collapsed into
> > huge page table entries as part of this logic.
> >
> > As part of this collapse, it frees the page tables which the collapsed
> > entries previously pointed to, and it does so without any relevant locks
> > being held to preclude concurrent kernel page table walkers.
> >
> > The only way this code can be reached is if CPA_COLLAPSE is specified, and
> > this is only set in set_memory_rox() via:
> >
> > set_memory_rox()
> > -> change_page_attr_set_clr()
> > -> cpa_flush()
> > -> cpa_collapse_large_pages()
> >
> > Notable users of this are execmem and bpf when manipulating executable
> > mappings.
> >
> > However, this is problematic for ptdump as it walks ranges it does not own
> > and thus runs the risk of a use-after-free on page tables freed underneath
> > it.
> >
> > Resolve the issue by acquiring the mmap read lock on init_mm which prevents
> > a concurrent ptdump as it acquires the write lock.
> >
> > It is safe to acquire a sleeping lock as all the callers invoke
> > set_memory_rox() from process context and in any case,
> > change_page_attr_set_clr() calls vm_unmap_alias() which ultimately takes a
> > mutex, disallowing atomic context here.
> >
> > Fixes: 41d88484c71c ("x86/mm/pat: restore large ROX pages after fragmentation")
> > Cc: stable@vger.kernel.org
> > Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> > ---
> > arch/x86/mm/pat/set_memory.c | 14 +++++++++++---
> > 1 file changed, 11 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
> > index d023a40a1e03..4c4b8244502f 100644
> > --- a/arch/x86/mm/pat/set_memory.c
> > +++ b/arch/x86/mm/pat/set_memory.c
> > @@ -22,6 +22,7 @@
> > #include <linux/cc_platform.h>
> > #include <linux/set_memory.h>
> > #include <linux/memregion.h>
> > +#include <linux/cleanup.h>
> >
> > #include <asm/e820/api.h>
> > #include <asm/processor.h>
> > @@ -436,9 +437,16 @@ static void cpa_collapse_large_pages(struct cpa_data *cpa)
> >
> > flush_tlb_all();
> >
> > - list_for_each_entry_safe(ptdesc, tmp, &pgtables, pt_list) {
> > - list_del(&ptdesc->pt_list);
> > - pagetable_free(ptdesc);
> > + /*
> > + * ptdump might read these page tables, so avoid a use-after-free by
> > + * acquiring the mmap read lock on init_mm (ptdump acquires the mmap
> > + * write lock).
> > + */
> > + scoped_guard(mmap_read_lock, &init_mm) {
> > + list_for_each_entry_safe(ptdesc, tmp, &pgtables, pt_list) {
> > + list_del(&ptdesc->pt_list);
> > + pagetable_free(ptdesc);
> > + }
>
> As I understand it, the argument for taking the read lock is that we're
> operating on a region that we "wholly own" and therefore we can happily
> run concurrently with CPUs walking distinct parts of the page-table.
> However, from what I can tell, the CPA collapse logic will operate on
> regions outside of the address range being manipulated by its caller
> because it rounds up to the PMD size.
>
> As a made-up example, imagine I have a 2MiB aligned region where the
> first 1MiB is read-only and the second 1MiB is in the default r/w state.
> If one CPU calls set_memory_rw() on the first 1MiB while another CPU is
> walking the second 1MiB (via some other API that doesn't take cpa_lock),
> it looks to me like the first CPU can collapse the page-table and free
> the unused pages under the feet of the other CPU. What prevents that
> from happening?
Nothing, and there's a patch to fix that that synchronizes
cpa_collapse_large_pages() using cpa_lock:
https://lore.kernel.org/all/20260626163213.2284080-1-den@openvz.org
This still won't be enough to sync with ptdump though.
> If all concurrent walkers have interrupts disabled, I guess the TLB
> invalidation logic would do it, but it would be good to call this out in
> the commit message because it's not clear to me why the read_lock is
> sufficient for the collapsing case.
>
> Cheers,
>
> Will
--
Sincerely yours,
Mike.
next prev parent reply other threads:[~2026-07-15 15:49 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 17:24 [PATCH mm-hotfixes v3 0/4] mm: fix UAF caused by race between ptdump and vmap pgtable freeing Lorenzo Stoakes
2026-07-14 17:24 ` [PATCH mm-hotfixes v3 1/4] mm/vmalloc: acquire init_mm lock on huge vmap to avoid ptdump UAF Lorenzo Stoakes
2026-07-15 10:34 ` Kiryl Shutsemau
2026-07-15 14:16 ` Lorenzo Stoakes (ARM)
2026-07-15 19:14 ` Andrew Morton
2026-07-14 17:24 ` [PATCH mm-hotfixes v3 2/4] x86/mm/pat: acquire mmap lock on page table free " Lorenzo Stoakes
2026-07-14 17:29 ` Dave Hansen
2026-07-15 15:24 ` Will Deacon
2026-07-15 15:49 ` Mike Rapoport [this message]
2026-07-14 17:24 ` [PATCH mm-hotfixes v3 3/4] mm/ptdump: always stabilise against page table freeing using init_mm Lorenzo Stoakes
2026-07-15 10:36 ` Kiryl Shutsemau
2026-07-14 17:24 ` [PATCH mm-hotfixes v3 4/4] arm64: remove redundant concurrent ptdump UAF mitigation Lorenzo Stoakes
2026-07-14 17:31 ` [PATCH mm-hotfixes v3 0/4] mm: fix UAF caused by race between ptdump and vmap pgtable freeing Dave Hansen
2026-07-14 19:11 ` Andrew Morton
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=alesCtwXdIqH6bOP@kernel.org \
--to=rppt@kernel.org \
--cc=abarnas@google.com \
--cc=akpm@linux-foundation.org \
--cc=bp@alien8.de \
--cc=bpf@vger.kernel.org \
--cc=catalin.marinas@arm.com \
--cc=dave.hansen@linux.intel.com \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=devnexen@gmail.com \
--cc=hpa@zytor.com \
--cc=kas@kernel.org \
--cc=liam@infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=luto@kernel.org \
--cc=mhocko@suse.com \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=ryan.roberts@arm.com \
--cc=shakeel.butt@linux.dev \
--cc=stable@vger.kernel.org \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=toshi.kani@hpe.com \
--cc=urezki@gmail.com \
--cc=vbabka@kernel.org \
--cc=will@kernel.org \
--cc=x86@kernel.org \
/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