1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-11-14 04:22:38 +03:00

linux: Add mseal syscall support

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-existing
memory mapping.

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

Checked on x86_64-linux-gnu and aarch64-linux-gnu.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
This commit is contained in:
Adhemerval Zanella
2025-11-10 15:03:05 -03:00
parent a9c426bcca
commit 3d52fd274e
40 changed files with 280 additions and 0 deletions

5
NEWS
View File

@@ -21,6 +21,11 @@ Major new features:
platforms supporting _Float128) _Float128_t, introduced in TS
18661-3:2015, have been added to <math.h>.
* On Linux, the mseal function has been added. It allows for sealing
memory mappings to prevent further changes during process execution,
such as changes to protection permissions, unmapping, relocation 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

View File

@@ -3126,6 +3126,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, previously 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 the 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 associated 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 the address range.
The @var{flags} is currently unused.
The @code{mseal} function returns @math{0} on success 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 CPU (sealing is currently supported only on 64-bit CPUs,
although 32-bit binaries running on a 64-bit kernel are supported).
@item ENOMEM
Either the @var{address} is not allocated, or the end address is not within the
allocation, or there is unallocated memory between the start and end address.
@item ENOSYS
The kernel does not support the @code{mseal} syscall.
@end table
@end deftypefun
@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}.
@subsection Memory Protection Keys
@cindex memory protection key

View File

@@ -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 \

View File

@@ -339,6 +339,9 @@ libc {
cfsetispeed;
cfsetspeed;
}
GLIBC_2.43 {
mseal;
}
GLIBC_PRIVATE {
# functions used in other libraries
__syscall_rt_sigqueueinfo;

View File

@@ -2770,4 +2770,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -3117,6 +3117,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2531,4 +2531,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2823,6 +2823,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2820,6 +2820,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -80,6 +80,16 @@ 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 remapping to
shrink or expand the VMA, changing protection permission with mprotect,
unmap with munmap, or destructive semantics such as madvise with
MADV_DONTNEED.
The address range must be a valid VMA, without any gaps (unallocated
memory) between the start and end, and ADDR must 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 */

View File

@@ -2807,4 +2807,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2844,6 +2844,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -3027,6 +3027,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -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 */

View File

@@ -2291,4 +2291,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2803,6 +2803,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2970,6 +2970,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2856,4 +2856,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2853,4 +2853,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2933,6 +2933,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2939,6 +2939,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2841,6 +2841,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2281,4 +2281,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -3160,6 +3160,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -3205,6 +3205,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2914,6 +2914,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2990,4 +2990,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2534,4 +2534,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -2734,4 +2734,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F

View File

@@ -3158,6 +3158,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2951,6 +2951,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2850,6 +2850,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2847,6 +2847,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -3181,6 +3181,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2817,6 +2817,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -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

View File

@@ -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 (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>

View File

@@ -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 (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>

View File

@@ -2766,6 +2766,7 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F

View File

@@ -2785,4 +2785,5 @@ GLIBC_2.42 ullabs F
GLIBC_2.43 __memset_explicit_chk F
GLIBC_2.43 memalignment F
GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 umaxabs F