All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arnav Kansal <rnv@google.com>
To: Andrew Morton <akpm@linux-foundation.org>,
	Mike Rapoport <rppt@kernel.org>
Cc: Luis Chamberlain <mcgrof@kernel.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	 Arnav Kansal <rnv@google.com>,
	stable@vger.kernel.org, Rohan Kumar <rohakum@google.com>
Subject: [PATCH] mm/execmem: only free ROX cache vm_struct when fully unused
Date: Wed, 14 Oct 2026 16:30:58 -0700	[thread overview]
Message-ID: <20261014233058.1410692-1-rnv@google.com> (raw)

execmem_cache_clean() currently uses:

    IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(mas.index, PMD_SIZE)

as a proxy to determine whether a free range in execmem_cache.free_areas
spans an entire unused vm_struct that can be returned to vmalloc.

This heuristic is broken in both directions:

1. Premature vfree() of multi-PMD vm_structs (Use-After-Free):
   When execmem_cache_populate_alloc() services a request larger than
   PMD_SIZE (for example, a module with > 6 MiB of .text),
   alloc_size = round_up(size, PMD_SIZE) creates a single multi-PMD
   vm_struct (e.g., 8 MiB) whose remaining tail space is handed out to
   subsequent module allocations (e.g., kvm.ko). When a module inside
   that vm_struct unloads and leaves a PMD_SIZE-aligned free sub-range
   (such as a 2 MiB or 4 MiB chunk at the start of the 8 MiB vm_struct),
   execmem_cache_clean() passes the IS_ALIGNED() check and calls
   vfree(area), which unmaps and frees the entire enclosing multi-PMD
   vm_struct while sibling modules are still live:

     BUG: unable to handle page fault for address: ffffffffc07dc030
     #PF: supervisor instruction fetch in kernel mode
     #PF: error_code(0x0010) - not-present page
     PGD 2c33067 P4D 2c33067 PUD 2c35067 PMD 0
     Oops: Oops: 0010 [#1] SMP NOPTI
     RIP: 0010:dummy_exit+0x0/0xfd0 [tailm]

2. Failure to reclaim fallback vm_structs:
   After commit 3bd4e0ac61b2 ("execmem: add fallback for failures in
   vmalloc(VM_ALLOW_HUGE_VMAP)") and commit 4afb85f5e359 ("mm: remove
   PMD alignment constraint in execmem_vmalloc()"), ROX cache vm_structs
   allocated via the base-page or exact-size fallback paths are only
   PAGE_SIZE-aligned in address and/or size, so they never satisfy the
   PMD_SIZE alignment check even when completely unused.

Because vmalloc allocations include a trailing guard page, separate
vm_struct allocations can never coalesce into a single contiguous entry
in execmem_cache.free_areas. Replace the PMD_SIZE alignment check with
an explicit check that the free range starts at vm->addr and spans the
entire get_vm_area_size(vm).

Fixes: 2e45474ab14f ("execmem: add support for cache of large ROX pages")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Co-developed-by: Rohan Kumar <rohakum@google.com>
Signed-off-by: Rohan Kumar <rohakum@google.com>
Signed-off-by: Arnav Kansal <rnv@google.com>
---
 mm/execmem.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/mm/execmem.c b/mm/execmem.c
index 74a178a87e75..3a1da0498fe2 100644
--- a/mm/execmem.c
+++ b/mm/execmem.c
@@ -166,11 +166,9 @@ static void execmem_cache_clean(struct work_struct *work)
 	mutex_lock(mutex);
 	mas_for_each(&mas, area, ULONG_MAX) {
 		size_t size = mas_range_len(&mas);
+		struct vm_struct *vm = find_vm_area(area);
 
-		if (IS_ALIGNED(size, PMD_SIZE) &&
-		    IS_ALIGNED(mas.index, PMD_SIZE)) {
-			struct vm_struct *vm = find_vm_area(area);
-
+		if (vm->addr == area && get_vm_area_size(vm) == size) {
 			execmem_set_direct_map_valid(vm, true);
 			mas_store_gfp(&mas, NULL, GFP_KERNEL);
 			vfree(area);
-- 
2.47.0


             reply	other threads:[~2026-10-14 23:32 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14 23:30 Arnav Kansal [this message]
2026-10-15  8:10 ` [PATCH] mm/execmem: only free ROX cache vm_struct when fully unused Mike Rapoport
2026-10-15 13:37   ` Arnav Kansal

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=20261014233058.1410692-1-rnv@google.com \
    --to=rnv@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mcgrof@kernel.org \
    --cc=rohakum@google.com \
    --cc=rppt@kernel.org \
    --cc=stable@vger.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 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.