[PATCH] linux: Add mseal syscall support

Adhemerval Zanella adhemerval.zanella@linaro.org
Fri Oct 10 19:07:48 GMT 2025


It has been added on Linux 6.10 (8be7258aad44b5e25977a98db136f677fa6f4370)
as a way to block operations such as mapping, moving to another location,
shrinking the size, expanding the size, or modifying it to a pre-existent
memory mapping.

Although the system only works on 64-bit CPU, the entrypoint was added
for all ABIs (since kernel might eventually implement it to additional
ones and/or the abi can execute on a 64-bit kernel).

Checked on x86_64-linux-gnu.
---
 NEWS                                          |  4 +
 manual/memory.texi                            | 69 +++++++++++++++
 sysdeps/unix/sysv/linux/Makefile              |  2 +
 sysdeps/unix/sysv/linux/Versions              |  3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |  1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/bits/mman-shared.h    |  8 ++
 sysdeps/unix/sysv/linux/csky/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/kernel-features.h     |  8 ++
 .../sysv/linux/loongarch/lp64/libc.abilist    |  1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |  1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  1 +
 .../sysv/linux/microblaze/be/libc.abilist     |  1 +
 .../sysv/linux/microblaze/le/libc.abilist     |  1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |  1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |  1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |  1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |  1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |  1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |  1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |  1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |  1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |  1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |  1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |  1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |  1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/syscalls.list         |  1 +
 sysdeps/unix/sysv/linux/tst-mseal-pkey.c      | 84 +++++++++++++++++++
 sysdeps/unix/sysv/linux/tst-mseal.c           | 67 +++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  1 +
 40 files changed, 277 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/tst-mseal-pkey.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-mseal.c

diff --git a/NEWS b/NEWS
index 8a5c197d42e..4b1ba4715a7 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,10 @@ Major new features:
 
 * The ISO C23 memset_explicit function has been added.
 
+* On Linux, the mseal function has been added.  It allows to seal memory
+  mappings to avoid further change during process execution such as protection
+  permissions, unmapping, moving to another location, or shrinking the size.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * Support for dumped heaps has been removed - malloc_set_state() now always
diff --git a/manual/memory.texi b/manual/memory.texi
index 6a70168e616..38a358a64fc 100644
--- a/manual/memory.texi
+++ b/manual/memory.texi
@@ -3071,6 +3071,75 @@ process memory, no matter how it was allocated.  However, portable use
 of the function requires that it is only used with memory regions
 returned by @code{mmap} or @code{mmap64}.
 
+@deftypefun int mseal (void *@var{address}, size_t @var{length}, unsigned long @var{flags})
+@standards{Linux, sys/mman.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+
+A successful call to the @code {mseal} function protects the memory
+range @var{address} of @var{length} bytes, previous allocated with
+@code{mmap} or @code{mremap}, against further metadata changes such
+as:
+
+@itemize @bullet
+@item
+Unmapping, moving to another location, extending or shrinking the size,
+via @code{munmap} and @code{mremap}.
+
+@item
+Moving or expanding a different VMA into the current location, via
+@code{mremap}.
+
+@item
+Modifying the memory range with @code{mmap} along with flag @code{MAP_FIXED}.
+
+@item
+Change the protection flags with @code{mprotect} or @code{pkey_mprotect}.  Also
+for certain destructive @code{madvise} behaviours (@code{MADV_DONTNEED},
+@code{MADV_FREE}, @code{MADV_DONTNEED_LOCKED}, and @code{MADV_WIPEONFORK}),
+@code{mseal} only blocks the operation if the protection key associate with
+the memory denies write.
+
+@item
+Destructive behaviors on anonymous memory, such as @code{madvice} with
+@code{MADV_DONTNEED}.
+@end itemize
+
+The @var{address} must be an allocated virtual memory done by @code{mmap}
+or @code{mremap}, and it must be page aligned.  The end address (@var{address}
+plus @var{length}) must be within an allocated virtual memory range.  There
+should be no unallocated memory between the start and end of address range.
+
+The @var{flags} is currently ununsed.
+
+The @code{mseal} function returns @math{0} on sucess and @math{-1} on
+failure.
+
+The following @code{errno} error conditions are defined for this
+function:
+
+@table @code
+@item EPERM
+The system blocked the operation, and the given address range is unmodified
+without a partial update.  This error is also returned when @code{mseal}
+is issued on a 32 bit CPUs (the sealing is currently supported only on
+64-bit CPUs, although 32 bit binaries running on 64 bit kernel is
+supported).
+
+@item ENOMEM
+Either the @var{address} is not allocated, or the end address is not within the
+allocation, or there is an unallocated memory between start and end address.
+
+@item ENOSYS
+The kernel does not support the @code{mseal} syscall.
+
+@strong{NB:} The memory sealing changes the lifetime of a mapping, where the
+sealing memory could not be unmapped until the process terminates or replaces
+the process image through @code{execve} function.  The sealed mappings are
+inherited through @code{fork}.
+
+@end table
+@end deftypefun
+
 @subsection Memory Protection Keys
 
 @cindex memory protection key
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 2c5bf42236a..fd4a840b258 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -205,6 +205,8 @@ tests += \
   tst-misalign-clone \
   tst-mlock2 \
   tst-mount \
+  tst-mseal \
+  tst-mseal-pkey \
   tst-ntp_adjtime \
   tst-ntp_gettime \
   tst-ntp_gettimex \
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index 585dec7689e..8f4d71ad7fe 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -339,6 +339,9 @@ libc {
     cfsetispeed;
     cfsetspeed;
   }
+  GLIBC_2.43 {
+    mseal;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bde5e66ce02..acc52ccfc33 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2769,3 +2769,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 0060616d206..6755c448202 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3116,6 +3116,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 79895b9b374..08723c3ea24 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2530,3 +2530,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3426d99f1e0..f68bcce642e 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -2822,6 +2822,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index eca31a2e27c..34501890d28 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -2819,6 +2819,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/bits/mman-shared.h b/sysdeps/unix/sysv/linux/bits/mman-shared.h
index 0be4b471bff..2de52989808 100644
--- a/sysdeps/unix/sysv/linux/bits/mman-shared.h
+++ b/sysdeps/unix/sysv/linux/bits/mman-shared.h
@@ -80,6 +80,14 @@ int pkey_free (int __key) __THROW;
    range.  */
 int pkey_mprotect (void *__addr, size_t __len, int __prot, int __pkey) __THROW;
 
+/* Seal the address range to avoid further modifications, such as remmap to
+   shrink or expand the VMA, change protection permission with mprotect,
+   unmap with munmap, destructive semantic such madvise with MADV_DONTNEED.
+   The address range must be valid VMA, withouth any gap (unallocated memory)
+   between start and end, and ADDR much be page aligned (LEN will be page
+   aligned implicitly).  */
+int mseal (void *__addr, size_t __len, unsigned long flags) __THROW;
+
 __END_DECLS
 
 #endif /* __USE_GNU */
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 7c5ebdf3ba4..6c33857c935 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2806,3 +2806,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 742118e65ed..d39072a45a4 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2843,6 +2843,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 8a8ff34e35b..1048b5078fe 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3026,6 +3026,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index a49a9159cfa..79191695b4f 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -261,4 +261,12 @@
 # define __ASSUME_FCHMODAT2 0
 #endif
 
+/* The mseal system call was introduced across all architectures in Linux 6.10
+   (although only supported on 64-bit CPUs).  */
+#if __LINUX_KERNEL_VERSION >= 0x060A00
+# define __ASSUME_MSEAL 1
+#else
+# define __ASSUME_MSEAL 0
+#endif
+
 #endif /* kernel-features.h */
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index 86b0246ad1b..8de87dfd6a9 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2290,3 +2290,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 92cef27d982..250738d03ff 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -2802,6 +2802,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 3b745745603..2b6b0b3d1cb 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2969,6 +2969,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index ae2d13ad8f5..f8c9c4b18ee 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2855,3 +2855,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 1b0264df273..acb385ec1ab 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2852,3 +2852,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 89232280909..af0f243368e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2932,6 +2932,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index e3c971367d6..3d65a13ebcd 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2938,6 +2938,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index db707fad52d..7eefb6ed653 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2840,6 +2840,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index 0780d53978e..f6f94a12898 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2280,3 +2280,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index f4f15510545..4f6ba6d4fab 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3159,6 +3159,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 34ec11f6853..25488e247ef 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3204,6 +3204,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index b790b43f4b3..026246d4b64 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2913,6 +2913,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index b7de3f95a8d..6d233d19b5c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2989,3 +2989,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 2680eabc7cb..e7a4091f092 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2533,3 +2533,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 074ca2f2802..fb1b2291122 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2733,3 +2733,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 0573db9f500..b2c0465679c 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -3157,6 +3157,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 55760b901f4..d4b3562de91 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2950,6 +2950,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a15b4df221f..361a9f67f82 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2849,6 +2849,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index b490e1064c3..b7688f6842b 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2846,6 +2846,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 8fd42d21d06..d057423b20d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3180,6 +3180,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index b62dec6a635..73fab212222 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2816,6 +2816,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index f1cfe8dc139..424bf43868f 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -39,6 +39,7 @@ mlockall	-	mlockall	i:i	mlockall
 mount		EXTRA	mount		i:sssUp	__mount	mount
 mount_setattr	EXTRA	mount_setattr	i:isUpU	mount_setattr
 move_mount	EXTRA	move_mount	i:isisU	move_mount
+mseal		EXTRA	mseal		i:bUU	__mseal	mseal
 munlock		-	munlock		i:aU	munlock
 munlockall	-	munlockall	i:	munlockall
 nfsservctl	EXTRA	nfsservctl	i:ipp	__compat_nfsservctl	nfsservctl@GLIBC_2.0:GLIBC_2.28
diff --git a/sysdeps/unix/sysv/linux/tst-mseal-pkey.c b/sysdeps/unix/sysv/linux/tst-mseal-pkey.c
new file mode 100644
index 00000000000..d194fbaaafe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-mseal-pkey.c
@@ -0,0 +1,84 @@
+/* Basic tests for mseal and pkey.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+static int
+do_test (void)
+{
+  TEST_VERIFY_EXIT (mseal (MAP_FAILED, 0, 0) == -1);
+  if (errno == ENOSYS || errno == EPERM)
+    FAIL_UNSUPPORTED ("kernel does not support mseal");
+  TEST_COMPARE (errno, EINVAL);
+
+  int key = pkey_alloc (0, 0);
+  if (key < 0)
+    {
+      if (errno == ENOSYS)
+        FAIL_UNSUPPORTED
+          ("kernel does not support memory protection keys");
+      if (errno == EINVAL)
+        FAIL_UNSUPPORTED
+          ("CPU does not support memory protection keys: %m");
+      if (errno == ENOSPC)
+        FAIL_UNSUPPORTED
+          ("no keys available or kernel does not support memory"
+           " protection keys");
+      FAIL_EXIT1 ("pkey_alloc: %m");
+    }
+
+  long pagesize = xsysconf (_SC_PAGESIZE);
+
+  void *page = xmmap (NULL, pagesize, PROT_READ | PROT_WRITE,
+		      MAP_ANONYMOUS | MAP_PRIVATE, -1);
+
+  TEST_COMPARE (pkey_mprotect (page, pagesize, PROT_READ | PROT_WRITE,
+			       key), 0);
+
+  TEST_VERIFY_EXIT (mseal (page, pagesize, 0) == 0);
+
+  /* For certain destructive madvise behaviours (MADV_DONTNEED,
+     MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK), mseal
+     only blocks the operation if the PKRU denies write.  */
+  TEST_VERIFY_EXIT (pkey_set (key, 0) == 0);
+  TEST_COMPARE (madvise (page, pagesize, MADV_DONTNEED), 0);
+
+  /* The other mapping operation change are always blocked,
+     regardless of PKRU state.  */
+  TEST_COMPARE (pkey_mprotect (page, pagesize, PROT_READ, key), -1);
+  TEST_COMPARE (errno, EPERM);
+
+  TEST_COMPARE (mprotect (page, pagesize, PROT_READ), -1);
+  TEST_COMPARE (errno, EPERM);
+
+  TEST_VERIFY_EXIT (pkey_set (key, PKEY_DISABLE_WRITE) == 0);
+  TEST_COMPARE (madvise (page, pagesize, MADV_DONTNEED), -1);
+  TEST_COMPARE (errno, EPERM);
+
+  TEST_COMPARE (mprotect (page, pagesize, PROT_READ), -1);
+  TEST_COMPARE (errno, EPERM);
+  TEST_COMPARE (munmap (page, pagesize),-1);
+  TEST_COMPARE (errno, EPERM);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/tst-mseal.c b/sysdeps/unix/sysv/linux/tst-mseal.c
new file mode 100644
index 00000000000..0aff1e9e4c1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-mseal.c
@@ -0,0 +1,67 @@
+/* Basic tests for mseal.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+static int
+do_test (void)
+{
+  TEST_VERIFY_EXIT (mseal (MAP_FAILED, 0, 0) == -1);
+  if (errno == ENOSYS || errno == EPERM)
+    FAIL_UNSUPPORTED ("kernel does not support mseal");
+  TEST_COMPARE (errno, EINVAL);
+
+  size_t pagesize = getpagesize ();
+  void *p = xmmap (NULL, 4 * pagesize, PROT_READ,
+		   MAP_ANONYMOUS | MAP_PRIVATE, -1);
+  xmunmap (p + 2 * pagesize, pagesize);
+
+  /* Unaligned address.  */
+  TEST_VERIFY_EXIT (mseal (p + 1, pagesize, 0) == -1);
+  TEST_COMPARE (errno, EINVAL);
+
+  /* Length too big.  */
+  TEST_VERIFY_EXIT (mseal (p, 3 * pagesize, 0) == -1);
+  TEST_COMPARE (errno, ENOMEM);
+
+  TEST_VERIFY_EXIT (mseal (p, pagesize, 0) == 0);
+  /* Apply the same seal should be idempotent.  */
+  TEST_VERIFY_EXIT (mseal (p, pagesize, 0) == 0);
+
+  TEST_VERIFY_EXIT (mprotect (p, pagesize, PROT_WRITE) == -1);
+  TEST_COMPARE (errno, EPERM);
+
+  TEST_VERIFY_EXIT (munmap (p, pagesize) == -1);
+  TEST_COMPARE (errno, EPERM);
+
+  TEST_VERIFY_EXIT (mremap (p, pagesize, 2 * pagesize, 0) == MAP_FAILED);
+  TEST_COMPARE (errno, EPERM);
+
+  TEST_VERIFY_EXIT (madvise (p, pagesize, MADV_DONTNEED) == -1);
+  TEST_COMPARE (errno, EPERM);
+
+  xmunmap (p + pagesize, pagesize);
+  xmunmap (p + 3 * pagesize, pagesize);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index fe23ac66822..0bb07a8cc08 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2765,6 +2765,7 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 986dfcca2a0..2847efeb84a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2784,3 +2784,4 @@ GLIBC_2.42 ulabs F
 GLIBC_2.42 ullabs F
 GLIBC_2.43 __memset_explicit_chk F
 GLIBC_2.43 memset_explicit F
+GLIBC_2.43 mseal F
-- 
2.43.0



More information about the Libc-alpha mailing list