linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE
@ 2026-02-24 17:57 Catalin Marinas
  2026-02-24 17:57 ` [PATCH 1/5] mm: Introduce vm_mmap_shadow_stack() as a helper for VM_SHADOW_STACK mappings Catalin Marinas
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-02-24 17:57 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Mark Brown, Deepak Gupta,
	Rick Edgecombe
  Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, linux-arm-kernel, linux-kernel,
	linux-riscv, linux-mm

Hi,

arm64, riscv and x86 all implement shadow stack support and use a
similar pattern for mapping the user shadow stack (originally cloned
from x86). Extract this common pattern into a shared helper -
vm_mmap_shadow_stack().

Patch 1 introduces vm_mmap_shadow_stack() in mm/util.c, which wraps
do_mmap() with the flags required for a VM_SHADOW_STACK mapping. The
helper uses PROT_READ|PROT_WRITE prot bits instead of the earlier x86
approach of PROT_READ with an explicit VM_WRITE vm_flag. Functionally
there is no difference. I looked up the history of this flag on the
lists but it wasn't conclusive. My guess is that the original aim was to
mark the vma not writable but that would confuse the kernel, so it ended
up with the VM_WRITE flag instead.

Patches 2-4 update arm64, riscv and x86 respectively to use the new
helper, removing the duplicated mmap logic.

Patch 5 forces VM_NOHUGEPAGE when allocating the shadow stack via the
new helper, mirroring what commit c4608d1bf7c6 ("mm: mmap: map MAP_STACK
to VM_NOHUGEPAGE") did for normal stacks. It will save some memory,
especially when the ulimit -s is high.

Boot-tested on x86, fully tested on arm64. I do not have a compiler
version that supports the -march=rv64ima_zicfiss_zicfilp option for
riscv, so any help with testing is welcome.

Thanks.

Catalin Marinas (5):
  mm: Introduce vm_mmap_shadow_stack() as a helper for VM_SHADOW_STACK
    mappings
  arm64: gcs: Use the new common vm_mmap_shadow_stack() helper
  riscv: shstk: Use the new common vm_mmap_shadow_stack() helper
  x86: shstk: Use the new common vm_mmap_shadow_stack() helper
  mm: Do not map the shadow stack as THP

 arch/arm64/mm/gcs.c         | 14 +-------------
 arch/riscv/kernel/usercfi.c | 12 +-----------
 arch/x86/kernel/shstk.c     | 12 ++----------
 include/linux/mm.h          |  4 ++++
 mm/util.c                   | 29 +++++++++++++++++++++++++++++
 5 files changed, 37 insertions(+), 34 deletions(-)



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] mm: Introduce vm_mmap_shadow_stack() as a helper for VM_SHADOW_STACK mappings
  2026-02-24 17:57 [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE Catalin Marinas
@ 2026-02-24 17:57 ` Catalin Marinas
  2026-02-24 17:57 ` [PATCH 2/5] arm64: gcs: Use the new common vm_mmap_shadow_stack() helper Catalin Marinas
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-02-24 17:57 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Mark Brown, Deepak Gupta,
	Rick Edgecombe
  Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, linux-arm-kernel, linux-kernel,
	linux-riscv, linux-mm

arm64, riscv and x86 use a similar pattern for mapping the user shadow
stack (cloned from x86). Extract this into a helper to facilitate code
reuse.

The call to do_mmap() from the new helper uses PROT_READ|PROT_WRITE prot
bits instead of the PROT_READ with an explicit VM_WRITE vm_flag. The
x86 intent was to avoid PROT_WRITE implying normal write since the
shadow stack is not writable by normal stores. However, from a kernel
perspective, the vma is writeable. Functionally there is no difference.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
---
 include/linux/mm.h |  4 ++++
 mm/util.c          | 25 +++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5be3d8a8f806..1f28be975f86 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3908,6 +3908,10 @@ extern int vm_munmap(unsigned long, size_t);
 extern unsigned long __must_check vm_mmap(struct file *, unsigned long,
         unsigned long, unsigned long,
         unsigned long, unsigned long);
+#ifdef CONFIG_ARCH_HAS_USER_SHADOW_STACK
+extern unsigned long __must_check vm_mmap_shadow_stack(unsigned long addr,
+	unsigned long len, unsigned long flags);
+#endif
 
 struct vm_unmapped_area_info {
 #define VM_UNMAPPED_AREA_TOPDOWN 1
diff --git a/mm/util.c b/mm/util.c
index b05ab6f97e11..2592291948f0 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -618,6 +618,31 @@ unsigned long vm_mmap(struct file *file, unsigned long addr,
 }
 EXPORT_SYMBOL(vm_mmap);
 
+#ifdef CONFIG_ARCH_HAS_USER_SHADOW_STACK
+/*
+ * Perform a userland memory mapping for a shadow stack into the current
+ * process address space. This is intended to be used by architectures that
+ * support user shadow stacks.
+ */
+unsigned long vm_mmap_shadow_stack(unsigned long addr, unsigned long len,
+				   unsigned long flags)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long ret, unused;
+
+	flags |= MAP_ANONYMOUS | MAP_PRIVATE;
+	if (addr)
+		flags |= MAP_FIXED_NOREPLACE;
+
+	mmap_write_lock(mm);
+	ret = do_mmap(NULL, addr, len, PROT_READ | PROT_WRITE, flags,
+		      VM_SHADOW_STACK, 0, &unused, NULL);
+	mmap_write_unlock(mm);
+
+	return ret;
+}
+#endif /* CONFIG_ARCH_HAS_USER_SHADOW_STACK */
+
 /**
  * __vmalloc_array - allocate memory for a virtually contiguous array.
  * @n: number of elements.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/5] arm64: gcs: Use the new common vm_mmap_shadow_stack() helper
  2026-02-24 17:57 [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE Catalin Marinas
  2026-02-24 17:57 ` [PATCH 1/5] mm: Introduce vm_mmap_shadow_stack() as a helper for VM_SHADOW_STACK mappings Catalin Marinas
@ 2026-02-24 17:57 ` Catalin Marinas
  2026-02-24 17:57 ` [PATCH 3/5] riscv: shstk: " Catalin Marinas
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-02-24 17:57 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Mark Brown, Deepak Gupta,
	Rick Edgecombe
  Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, linux-arm-kernel, linux-kernel,
	linux-riscv, linux-mm

Replace the arm64 map_shadow_stack() content with a call to
vm_mmap_shadow_stack().

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
---
 arch/arm64/mm/gcs.c | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
index 04a23a497f20..680749611a9a 100644
--- a/arch/arm64/mm/gcs.c
+++ b/arch/arm64/mm/gcs.c
@@ -12,19 +12,7 @@
 
 static unsigned long alloc_gcs(unsigned long addr, unsigned long size)
 {
-	int flags = MAP_ANONYMOUS | MAP_PRIVATE;
-	struct mm_struct *mm = current->mm;
-	unsigned long mapped_addr, unused;
-
-	if (addr)
-		flags |= MAP_FIXED_NOREPLACE;
-
-	mmap_write_lock(mm);
-	mapped_addr = do_mmap(NULL, addr, size, PROT_READ, flags,
-			      VM_SHADOW_STACK | VM_WRITE, 0, &unused, NULL);
-	mmap_write_unlock(mm);
-
-	return mapped_addr;
+	return vm_mmap_shadow_stack(addr, size, 0);
 }
 
 static unsigned long gcs_size(unsigned long size)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/5] riscv: shstk: Use the new common vm_mmap_shadow_stack() helper
  2026-02-24 17:57 [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE Catalin Marinas
  2026-02-24 17:57 ` [PATCH 1/5] mm: Introduce vm_mmap_shadow_stack() as a helper for VM_SHADOW_STACK mappings Catalin Marinas
  2026-02-24 17:57 ` [PATCH 2/5] arm64: gcs: Use the new common vm_mmap_shadow_stack() helper Catalin Marinas
@ 2026-02-24 17:57 ` Catalin Marinas
  2026-02-24 17:57 ` [PATCH 4/5] x86: " Catalin Marinas
  2026-02-24 17:57 ` [PATCH 5/5] mm: Do not map the shadow stack as THP Catalin Marinas
  4 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-02-24 17:57 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Mark Brown, Deepak Gupta,
	Rick Edgecombe
  Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, linux-arm-kernel, linux-kernel,
	linux-riscv, linux-mm

Replace part of the allocate_shadow_stack() content with a call to
vm_mmap_shadow_stack().

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Deepak Gupta <debug@rivosinc.com>
---
 arch/riscv/kernel/usercfi.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c
index 1adba746f164..7e57f54dc5b2 100644
--- a/arch/riscv/kernel/usercfi.c
+++ b/arch/riscv/kernel/usercfi.c
@@ -230,17 +230,7 @@ int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr)
 static unsigned long allocate_shadow_stack(unsigned long addr, unsigned long size,
 					   unsigned long token_offset, bool set_tok)
 {
-	int flags = MAP_ANONYMOUS | MAP_PRIVATE;
-	struct mm_struct *mm = current->mm;
-	unsigned long populate;
-
-	if (addr)
-		flags |= MAP_FIXED_NOREPLACE;
-
-	mmap_write_lock(mm);
-	addr = do_mmap(NULL, addr, size, PROT_READ, flags,
-		       VM_SHADOW_STACK | VM_WRITE, 0, &populate, NULL);
-	mmap_write_unlock(mm);
+	addr = vm_mmap_shadow_stack(addr, size, 0);
 
 	if (!set_tok || IS_ERR_VALUE(addr))
 		goto out;


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 4/5] x86: shstk: Use the new common vm_mmap_shadow_stack() helper
  2026-02-24 17:57 [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE Catalin Marinas
                   ` (2 preceding siblings ...)
  2026-02-24 17:57 ` [PATCH 3/5] riscv: shstk: " Catalin Marinas
@ 2026-02-24 17:57 ` Catalin Marinas
  2026-02-24 17:57 ` [PATCH 5/5] mm: Do not map the shadow stack as THP Catalin Marinas
  4 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-02-24 17:57 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Mark Brown, Deepak Gupta,
	Rick Edgecombe
  Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, linux-arm-kernel, linux-kernel,
	linux-riscv, linux-mm

Replace part of the x86 alloc_shstk() content with a call to
vm_mmap_shadow_stack().

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Thomas Gleixner <tglx@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
 arch/x86/kernel/shstk.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c
index 978232b6d48d..9725e7d89b1e 100644
--- a/arch/x86/kernel/shstk.c
+++ b/arch/x86/kernel/shstk.c
@@ -100,17 +100,9 @@ static int create_rstor_token(unsigned long ssp, unsigned long *token_addr)
 static unsigned long alloc_shstk(unsigned long addr, unsigned long size,
 				 unsigned long token_offset, bool set_res_tok)
 {
-	int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_ABOVE4G;
-	struct mm_struct *mm = current->mm;
-	unsigned long mapped_addr, unused;
+	unsigned long mapped_addr;
 
-	if (addr)
-		flags |= MAP_FIXED_NOREPLACE;
-
-	mmap_write_lock(mm);
-	mapped_addr = do_mmap(NULL, addr, size, PROT_READ, flags,
-			      VM_SHADOW_STACK | VM_WRITE, 0, &unused, NULL);
-	mmap_write_unlock(mm);
+	mapped_addr = vm_mmap_shadow_stack(addr, size, MAP_ABOVE4G);
 
 	if (!set_res_tok || IS_ERR_VALUE(mapped_addr))
 		goto out;


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 5/5] mm: Do not map the shadow stack as THP
  2026-02-24 17:57 [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE Catalin Marinas
                   ` (3 preceding siblings ...)
  2026-02-24 17:57 ` [PATCH 4/5] x86: " Catalin Marinas
@ 2026-02-24 17:57 ` Catalin Marinas
  4 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-02-24 17:57 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Mark Brown, Deepak Gupta,
	Rick Edgecombe
  Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, linux-arm-kernel, linux-kernel,
	linux-riscv, linux-mm

The default shadow stack size allocated on first prctl() for the main
thread or subsequently on clone() is either half of RLIMIT_STACK or half
of a thread's stack size (for arm64). Both of these are likely to be
suitable for a THP allocation and the kernel is more aggressive in
creating such mappings. However, it does not make much sense to use a
huge page. It didn't make sense for the normal stacks either, see commit
c4608d1bf7c6 ("mm: mmap: map MAP_STACK to VM_NOHUGEPAGE").

Force VM_NOHUGEPAGE when allocating/mapping the shadow stack. As per
commit 7190b3c8bd2b ("mm: mmap: map MAP_STACK to VM_NOHUGEPAGE only if
THP is enabled"), only pass this flag if TRANSPARENT_HUGEPAGE is enabled
as not to confuse CRIU tools.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
---
 mm/util.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/mm/util.c b/mm/util.c
index 2592291948f0..9f33c6de6082 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -629,14 +629,18 @@ unsigned long vm_mmap_shadow_stack(unsigned long addr, unsigned long len,
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long ret, unused;
+	vm_flags_t vm_flags = VM_SHADOW_STACK;
 
 	flags |= MAP_ANONYMOUS | MAP_PRIVATE;
 	if (addr)
 		flags |= MAP_FIXED_NOREPLACE;
 
+	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+		vm_flags |= VM_NOHUGEPAGE;
+
 	mmap_write_lock(mm);
 	ret = do_mmap(NULL, addr, len, PROT_READ | PROT_WRITE, flags,
-		      VM_SHADOW_STACK, 0, &unused, NULL);
+		      vm_flags, 0, &unused, NULL);
 	mmap_write_unlock(mm);
 
 	return ret;


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-02-24 17:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-24 17:57 [PATCH 0/5] mm: arch/shstk: Common shadow stack mapping helper and VM_NOHUGEPAGE Catalin Marinas
2026-02-24 17:57 ` [PATCH 1/5] mm: Introduce vm_mmap_shadow_stack() as a helper for VM_SHADOW_STACK mappings Catalin Marinas
2026-02-24 17:57 ` [PATCH 2/5] arm64: gcs: Use the new common vm_mmap_shadow_stack() helper Catalin Marinas
2026-02-24 17:57 ` [PATCH 3/5] riscv: shstk: " Catalin Marinas
2026-02-24 17:57 ` [PATCH 4/5] x86: " Catalin Marinas
2026-02-24 17:57 ` [PATCH 5/5] mm: Do not map the shadow stack as THP Catalin Marinas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox