diff mbox series

[v2,5/5] elf: Add support for GNU_PROPERTY_NO_MEMORY_SEAL

Message ID 20240731200307.2269811-6-adhemerval.zanella@linaro.org
State New
Headers show
Series Add support for memory sealing | expand

Commit Message

Adhemerval Zanella Netto July 31, 2024, 8:02 p.m. UTC
The GNU_PROPERTY_NO_MEMORY_SEAL is a GNU property per module instructing
the glibc not to seal the object PT_LOAD.  It can be used for any reason
the modules require to seal not to be enabled (i.e., on Firefox hack to
bypass the dynamic loader and enable DT_RELR on older glibc [1]).  In
this case, it is up to the module to apply memory sealing itself.

The sealing is applied by default, and it is always enforced with
glibc.rtld.seal=2.

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

[1] https://glandium.org/blog/?p=4297
---
 configure                                     | 35 ++++++++++
 configure.ac                                  |  5 ++
 elf/dl-load.c                                 |  4 +-
 elf/dl-open.c                                 |  2 +-
 elf/dl-reloc.c                                | 18 ++---
 elf/dl-support.c                              |  4 +-
 elf/elf.h                                     |  2 +
 elf/rtld.c                                    | 10 +--
 include/link.h                                |  1 +
 string/strerrorname_np.c                      |  1 -
 sysdeps/aarch64/dl-prop.h                     |  5 ++
 sysdeps/generic/dl-mseal.h                    |  2 -
 sysdeps/generic/dl-prop-mseal.h               | 38 +++++++++++
 sysdeps/generic/dl-prop.h                     |  5 ++
 sysdeps/generic/ldsodefs.h                    | 11 ++--
 sysdeps/unix/sysv/linux/Makefile              | 46 +++++++++++++
 sysdeps/unix/sysv/linux/dl-mseal.h            |  2 -
 .../tst-dl_mseal-dlopen-no-memory-seal-2-1.c  | 19 ++++++
 .../tst-dl_mseal-dlopen-no-memory-seal-2.c    | 19 ++++++
 .../linux/tst-dl_mseal-mod-no-memory-seal-1.c | 19 ++++++
 .../linux/tst-dl_mseal-mod-no-memory-seal-2.c | 19 ++++++
 .../tst-dl_mseal-no-memory-seal-auditmod.c    |  1 +
 .../tst-dl_mseal-no-memory-seal-preload.c     |  1 +
 .../sysv/linux/tst-dl_mseal-no-memory-seal.c  | 65 +++++++++++++++++++
 .../unix/sysv/linux/tst-dl_mseal-skeleton.c   |  6 +-
 .../tst-dl_mseal-static-no-memory-seal.c      | 38 +++++++++++
 sysdeps/x86/dl-prop.h                         |  4 ++
 27 files changed, 350 insertions(+), 32 deletions(-)
 create mode 100644 sysdeps/generic/dl-prop-mseal.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c
diff mbox series

Patch

diff --git a/configure b/configure
index 1d543548cd..31deacc983 100755
--- a/configure
+++ b/configure
@@ -7102,6 +7102,41 @@  printf "%s\n" "$libc_linker_feature" >&6; }
 config_vars="$config_vars
 have-no-dynamic-linker = $libc_cv_no_dynamic_linker"
 
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z no-memory-seal" >&5
+printf %s "checking for linker that supports -z no-memory-seal... " >&6; }
+libc_linker_feature=no
+cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
+		  -Wl,-z,no-memory-seal -nostdlib -nostartfiles
+		  -fPIC -shared -o conftest.so conftest.c
+		  1>&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+then
+  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-z,no-memory-seal -nostdlib \
+      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
+      | grep "warning: -z no-memory-seal ignored" > /dev/null 2>&1; then
+    true
+  else
+    libc_linker_feature=yes
+  fi
+fi
+rm -f conftest*
+if test $libc_linker_feature = yes; then
+  libc_cv_z_no_memory_seal=yes
+else
+  libc_cv_z_no_memory_seal=no
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
+printf "%s\n" "$libc_linker_feature" >&6; }
+config_vars="$config_vars
+have-z-no-memory-seal = $libc_cv_z_no_memory_seal"
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -static-pie" >&5
 printf %s "checking for -static-pie... " >&6; }
 if test ${libc_cv_static_pie+y}
diff --git a/configure.ac b/configure.ac
index 9cbc0bf68f..a8fc276cfb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1278,6 +1278,11 @@  LIBC_LINKER_FEATURE([--no-dynamic-linker],
 		    [libc_cv_no_dynamic_linker=no])
 LIBC_CONFIG_VAR([have-no-dynamic-linker], [$libc_cv_no_dynamic_linker])
 
+LIBC_LINKER_FEATURE([-z no-memory-seal],
+		    [-Wl,-z,no-memory-seal],
+		    [libc_cv_z_no_memory_seal=yes], [libc_cv_z_no_memory_seal=no])
+LIBC_CONFIG_VAR([have-z-no-memory-seal], [$libc_cv_z_no_memory_seal])
+
 AC_CACHE_CHECK(for -static-pie, libc_cv_static_pie, [dnl
 LIBC_TRY_CC_OPTION([-static-pie],
 		   [libc_cv_static_pie=yes],
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 4c2371ec46..17b64363f7 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1431,7 +1431,9 @@  cannot enable executable stack as shared object requires");
     /* Assign the next available module ID.  */
     _dl_assign_tls_modid (l);
 
-  l->l_seal = mode & RTLD_NODELETE ? lt_seal_toseal : lt_seal_dont;
+  /* Do not alter the sealing if the GNU property disables it.  */
+  if (l->l_seal == lt_seal_undefined && mode & RTLD_NODELETE)
+    l->l_seal = lt_seal_toseal;
 
 #ifdef DL_AFTER_LOAD
   DL_AFTER_LOAD (l);
diff --git a/elf/dl-open.c b/elf/dl-open.c
index f53b1b0572..7cc39fba5b 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -841,7 +841,7 @@  dl_open_worker (void *a)
 
   /* The seal flag is set only for NEW, however its dependencies could not be
      unloaded and thus can also be sealed.  */
-  _dl_mseal_map (new, true);
+  _dl_mseal_map (new, true, false);
 }
 
 void *
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 6bb424f789..4a81c3914c 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -352,7 +352,7 @@  _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
   /* Seal the memory mapping after RELRO setup, we can use the PT_LOAD
      segments because even if relro splits the the original RW VMA,
      mseal works with multiple VMAs with different flags.  */
-  _dl_mseal_map (l, false);
+  _dl_mseal_map (l, false, false);
 }
 
 
@@ -376,11 +376,10 @@  cannot apply additional memory protection after relocation");
 }
 
 static void
-_dl_mseal_map_1 (struct link_map *l)
+_dl_mseal_map_1 (struct link_map *l, bool force)
 {
-  /* We only checked if the map is already sealed here so we can seal audit
-     module dependencies after the initial audit setup.  */
-  if (l->l_seal == lt_seal_sealed)
+  if (l->l_seal == lt_seal_dont
+      || (!force && (l->l_seal != lt_seal_toseal)))
     return;
 
   int r = -1;
@@ -408,16 +407,13 @@  _dl_mseal_map_1 (struct link_map *l)
 }
 
 void
-_dl_mseal_map (struct link_map *l, bool dep)
+_dl_mseal_map (struct link_map *l, bool dep, bool force)
 {
-  if (l->l_seal == lt_seal_dont || l->l_seal == lt_seal_sealed)
-    return;
-
   if (l->l_searchlist.r_list == NULL || !dep)
-    _dl_mseal_map_1 (l);
+    _dl_mseal_map_1 (l, force);
   else
     for (unsigned int i = 0; i < l->l_searchlist.r_nlist; ++i)
-      _dl_mseal_map_1 (l->l_searchlist.r_list[i]);
+      _dl_mseal_map_1 (l->l_searchlist.r_list[i], force);
 }
 
 void
diff --git a/elf/dl-support.c b/elf/dl-support.c
index a02ae712b3..dd02943dd0 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -101,7 +101,7 @@  static struct link_map _dl_main_map =
     .l_used = 1,
     .l_tls_offset = NO_TLS_OFFSET,
     .l_serial = 1,
-    .l_seal = SUPPORT_MSEAL,
+    .l_seal = lt_seal_toseal,
   };
 
 /* Namespace information.  */
@@ -359,7 +359,7 @@  _dl_non_dynamic_init (void)
   /* Seal the memory mapping after RELRO setup, we can use the PT_LOAD
      segments because even if relro splits the the original RW VMA,
      mseal works with multiple VMAs with different flags.  */
-  _dl_mseal_map (&_dl_main_map, false);
+  _dl_mseal_map (&_dl_main_map, false, false);
 }
 
 #ifdef DL_SYSINFO_IMPLEMENTATION
diff --git a/elf/elf.h b/elf/elf.h
index 33aea7f743..62f493b9ee 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1357,6 +1357,8 @@  typedef struct
 #define GNU_PROPERTY_STACK_SIZE			1
 /* No copy relocation on protected data symbol.  */
 #define GNU_PROPERTY_NO_COPY_ON_PROTECTED	2
+/* No memory sealing.  */
+#define GNU_PROPERTY_NO_MEMORY_SEAL		3
 
 /* A 4-byte unsigned integer property: A bit is set if it is set in all
    relocatable inputs.  */
diff --git a/elf/rtld.c b/elf/rtld.c
index efe7e97b04..23b651ee55 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -478,7 +478,7 @@  _dl_start_final (void *arg, struct dl_start_final_info *info)
   GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
   GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start;
   GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
-  GL(dl_rtld_map).l_seal = 1;
+  GL(dl_rtld_map).l_seal = lt_seal_toseal;
   /* Copy the TLS related data if necessary.  */
 #ifndef DONT_USE_BOOTSTRAP_MAP
 # if NO_TLS_OFFSET != 0
@@ -1046,9 +1046,9 @@  ERROR: audit interface '%s' requires version %d (maximum supported version %d);
   /* Mark the DSO as being used for auditing.  */
   dlmargs.map->l_auditing = 1;
 
-  /* Seal the audit modules and their dependencies.  */
-  dlmargs.map->l_seal = lt_seal_toseal;
-  _dl_mseal_map (dlmargs.map, true);
+  /* Since audit modules can not be loaded with RTLD_NODELETE, force the
+     sealing of the modules and its dependencies.  */
+  _dl_mseal_map (dlmargs.map, true, true);
 }
 
 /* Load all audit modules.  */
@@ -1131,7 +1131,7 @@  rtld_setup_main_map (struct link_map *main_map)
   /* And it was opened directly.  */
   ++main_map->l_direct_opencount;
   main_map->l_contiguous = 1;
-  main_map->l_seal = 1;
+  main_map->l_seal = lt_seal_toseal;
 
   /* A PT_LOAD segment at an unexpected address will clear the
      l_contiguous flag.  The ELF specification says that PT_LOAD
diff --git a/include/link.h b/include/link.h
index fd8e7f25bf..176f4abddd 100644
--- a/include/link.h
+++ b/include/link.h
@@ -214,6 +214,7 @@  struct link_map
 					       lt_library map.  */
     enum			/* Memory sealing status.  */
       {
+	lt_seal_undefined = 0,	/* No set.  */
 	lt_seal_dont,		/* Do not seal the object.  */
 	lt_seal_toseal,		/* The library is marked to be sealed.  */
 	lt_seal_sealed		/* The library is sealed.  */
diff --git a/string/strerrorname_np.c b/string/strerrorname_np.c
index e0e22fa79e..042cea381c 100644
--- a/string/strerrorname_np.c
+++ b/string/strerrorname_np.c
@@ -17,7 +17,6 @@ 
    <https://www.gnu.org/licenses/>.  */
 
 #include <stdio.h>
-#include <string.h>
 
 const char *
 strerrorname_np (int errnum)
diff --git a/sysdeps/aarch64/dl-prop.h b/sysdeps/aarch64/dl-prop.h
index df05c0211d..c66d9a49f0 100644
--- a/sysdeps/aarch64/dl-prop.h
+++ b/sysdeps/aarch64/dl-prop.h
@@ -19,6 +19,8 @@ 
 #ifndef _DL_PROP_H
 #define _DL_PROP_H
 
+#include <dl-prop-mseal.h>
+
 extern void _dl_bti_protect (struct link_map *, int) attribute_hidden;
 
 extern void _dl_bti_check (struct link_map *, const char *)
@@ -45,6 +47,9 @@  static inline int
 _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
 			  uint32_t datasz, void *data)
 {
+  if (_dl_process_gnu_property_seal (l, fd, type, datasz, data))
+    return 0;
+
   if (!GLRO(dl_aarch64_cpu_features).bti)
     /* Skip note processing.  */
     return 0;
diff --git a/sysdeps/generic/dl-mseal.h b/sysdeps/generic/dl-mseal.h
index d542fcac75..dccf78ae38 100644
--- a/sysdeps/generic/dl-mseal.h
+++ b/sysdeps/generic/dl-mseal.h
@@ -21,5 +21,3 @@  _dl_mseal (void *addr, size_t len)
 {
   return 0;
 }
-
-#define SUPPORT_MSEAL lt_seal_dont
diff --git a/sysdeps/generic/dl-prop-mseal.h b/sysdeps/generic/dl-prop-mseal.h
new file mode 100644
index 0000000000..b9dbd24fa5
--- /dev/null
+++ b/sysdeps/generic/dl-prop-mseal.h
@@ -0,0 +1,38 @@ 
+/* Support for GNU properties.  Generic version.
+   Copyright (C) 2024 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/>.  */
+
+#ifndef _DL_PROP_MSEAL_H
+#define _LD_PROP_MSEAL_H
+
+#include <dl-tunables.h>
+#include <dl-mseal-mode.h>
+
+static __always_inline bool
+_dl_process_gnu_property_seal (struct link_map *l, int fd, uint32_t type,
+			       uint32_t datasz, void *data)
+{
+  if (type == GNU_PROPERTY_NO_MEMORY_SEAL && datasz == 0)
+    {
+      int32_t mode = TUNABLE_GET (glibc, rtld, seal, int32_t, NULL);
+      l->l_seal = (mode == DL_SEAL_ENFORCE) ? lt_seal_toseal : lt_seal_dont;
+      return true;
+    }
+  return false;
+}
+
+#endif
diff --git a/sysdeps/generic/dl-prop.h b/sysdeps/generic/dl-prop.h
index 1d92920a96..5fac690c81 100644
--- a/sysdeps/generic/dl-prop.h
+++ b/sysdeps/generic/dl-prop.h
@@ -19,6 +19,8 @@ 
 #ifndef _DL_PROP_H
 #define _DL_PROP_H
 
+#include <dl-prop-mseal.h>
+
 /* The following functions are used by the dynamic loader and the
    dlopen machinery to process PT_NOTE and PT_GNU_PROPERTY entries in
    the binary or shared object.  The notes can be used to change the
@@ -47,6 +49,9 @@  static inline int __attribute__ ((always_inline))
 _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
 			  uint32_t datasz, void *data)
 {
+  if (_dl_process_gnu_property_seal (l, fd, type, datasz, data))
+    return 0;
+
   /* Continue until GNU_PROPERTY_1_NEEDED is found.  */
   if (type == GNU_PROPERTY_1_NEEDED)
     {
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index aad5a219df..577f3ae06b 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1017,10 +1017,13 @@  extern void _dl_relocate_object (struct link_map *map,
 /* Protect PT_GNU_RELRO area.  */
 extern void _dl_protect_relro (struct link_map *map) attribute_hidden;
 
-/* Protect MAP with mseal.  If MAP is contiguous the while region is
-   sealed, otherwise iterate over the phdr to seal each PT_LOAD.  The DEP
-   specify whether to seal the dependencies as well.  */
-extern void _dl_mseal_map (struct link_map *map, bool dep)
+/* Issue memory sealing for the link map MAP.  If MAP is contiguous the
+   whole region is sealed, otherwise iterate over the program headerrs and
+   seal each PT_LOAD segment.i
+   The DEP specify whether to seal the dependencies as well, while FORCE
+   ignores if previous seal configuration (such as
+   GNU_PROPERTY_NO_MEMORY_SEAL mark).  */
+extern void _dl_mseal_map (struct link_map *map, bool dep, bool force)
      attribute_hidden;
 
 /* Call _dl_signal_error with a message about an unhandled reloc type.
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 3161363db1..c82aeb3403 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -685,6 +685,52 @@  $(objpfx)tst-dl_mseal-dlopen-2.so: $(objpfx)tst-dl_mseal-dlopen-2-1.so
 LDFLAGS-tst-dl_mseal-dlopen-2.so = -Wl,--no-as-needed
 
 tst-dl_mseal-static-ARGS = -- $(host-test-program-cmd)
+
+ifeq ($(have-z-no-memory-seal),yes)
+tests-static += \
+  tst-dl_mseal-static-no-memory-seal \
+  # tests-static
+
+tests += \
+  tst-dl_mseal-no-memory-seal \
+  tst-dl_mseal-static-no-memory-seal \
+  # tests
+
+modules-names += \
+  tst-dl_mseal-dlopen-no-memory-seal-2 \
+  tst-dl_mseal-dlopen-no-memory-seal-2-1 \
+  tst-dl_mseal-mod-no-memory-seal-1 \
+  tst-dl_mseal-mod-no-memory-seal-2 \
+  tst-dl_mseal-no-memory-seal-auditmod \
+  tst-dl_mseal-no-memory-seal-preload \
+  # modules-names
+
+$(objpfx)tst-dl_mseal-no-memory-seal.out: \
+  $(objpfx)tst-dl_mseal-no-memory-seal-auditmod.so \
+  $(objpfx)tst-dl_mseal-no-memory-seal-preload.so \
+  $(objpfx)tst-dl_mseal-mod-no-memory-seal-1.so \
+  $(objpfx)tst-dl_mseal-mod-no-memory-seal-2.so \
+  $(objpfx)tst-dl_mseal-dlopen-1.so \
+  $(objpfx)tst-dl_mseal-dlopen-1-1.so \
+  $(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2.so \
+  $(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2-1.so
+
+tst-dl_mseal-no-memory-seal-ARGS = -- $(host-test-program-cmd)
+
+LDFLAGS-tst-dl_mseal-no-memory-seal-preload.so = -Wl,-z,no-memory-seal
+
+LDFLAGS-tst-dl_mseal-no-memory-seal-auditmod.so = -Wl,-z,no-memory-seal
+$(objpfx)tst-dl_mseal-no-memory-seal: $(objpfx)tst-dl_mseal-mod-no-memory-seal-1.so
+LDFLAGS-tst-dl_mseal-no-memory-seal = -Wl,-z,no-memory-seal -Wl,--no-as-needed
+$(objpfx)tst-dl_mseal-mod-no-memory-seal-1.so: $(objpfx)tst-dl_mseal-mod-no-memory-seal-2.so
+LDFLAGS-tst-dl_mseal-mod-no-memory-seal-1.so = -Wl,--no-as-needed
+LDFLAGS-tst-dl_mseal-mod-no-memory-seal-2.so = -Wl,-z,no-memory-seal -Wl,--no-as-needed
+$(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2.so: $(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2-1.so
+LDFLAGS-tst-dl_mseal-dlopen-no-memory-seal-2.so = -Wl,--no-as-needed -Wl,-z,no-memory-seal
+
+LDFLAGS-tst-dl_mseal-static-no-memory-seal = -Wl,-z,no-memory-seal
+tst-dl_mseal-static-no-memory-seal-ARGS = -- $(host-test-program-cmd)
+endif
 endif
 
 ifeq ($(subdir),rt)
diff --git a/sysdeps/unix/sysv/linux/dl-mseal.h b/sysdeps/unix/sysv/linux/dl-mseal.h
index 89b19e33c4..25e3f724dc 100644
--- a/sysdeps/unix/sysv/linux/dl-mseal.h
+++ b/sysdeps/unix/sysv/linux/dl-mseal.h
@@ -25,5 +25,3 @@ 
    Return 0 in case of success or a negative value otherwise (a negative
    errno).  */
 int _dl_mseal (void *addr, size_t len) attribute_hidden;
-
-#define SUPPORT_MSEAL lt_seal_toseal
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c
new file mode 100644
index 0000000000..0cd647de46
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c
@@ -0,0 +1,19 @@ 
+/* Additional module for tst-dl_mseal test.
+   Copyright (C) 2024 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/>.  */
+
+int bar2_1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c
new file mode 100644
index 0000000000..f719dd3cba
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c
@@ -0,0 +1,19 @@ 
+/* Additional module for tst-dl_mseal test.
+   Copyright (C) 2024 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/>.  */
+
+int bar2 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c
new file mode 100644
index 0000000000..3bd188efe8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c
@@ -0,0 +1,19 @@ 
+/* Additional module for tst-dl_mseal test.
+   Copyright (C) 2024 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/>.  */
+
+int foo1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c
new file mode 100644
index 0000000000..636e9777af
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c
@@ -0,0 +1,19 @@ 
+/* Additional module for tst-dl_mseal test.
+   Copyright (C) 2024 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/>.  */
+
+int bar1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c
new file mode 100644
index 0000000000..a5b257d05e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c
@@ -0,0 +1 @@ 
+#include "tst-dl_mseal-auditmod.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c
new file mode 100644
index 0000000000..32b4153e79
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c
@@ -0,0 +1 @@ 
+#include "tst-dl_mseal-preload.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c
new file mode 100644
index 0000000000..014a8e76c7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c
@@ -0,0 +1,65 @@ 
+/* Basic tests for sealing.
+   Copyright (C) 2024 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 <gnu/lib-names.h>
+
+/* This test checks the GNU_PROPERTY_NO_MEMORY_SEAL handling on multiple
+   places:
+
+   - On the binary itself.
+   - On a LD_PRELOAD library.
+   - On a depedency module (tst-dl_mseal-mod-no-memory-seal-2.so).
+   - On a audit modules (tst-dl_mseal-no-memory-seal-auditmod.so).
+   - On a dlopen dependency opened with RTLD_NODELET
+     (tst-dl_mseal-dlopen-no-memory-seal-2.so).
+*/
+
+#define LIB_PRELOAD              "tst-dl_mseal-no-memory-seal-preload.so"
+#define GLIBC_RTLD_SEAL          "1"
+
+#define LIB_DLOPEN_DEFAULT       "tst-dl_mseal-dlopen-1.so"
+#define LIB_DLOPEN_DEFAULT_DEP   "tst-dl_mseal-dlopen-1-1.so"
+#define LIB_DLOPEN_NODELETE      "tst-dl_mseal-dlopen-no-memory-seal-2.so"
+#define LIB_DLOPEN_NODELETE_DEP  "tst-dl_mseal-dlopen-no-memory-seal-2-1.so"
+
+#define LIB_AUDIT                "tst-dl_mseal-no-memory-seal-auditmod.so"
+
+/* Expected libraries that loader will seal.  */
+static const char *expected_sealed_libs[] =
+{
+  "libc.so",
+  "ld.so",
+  "tst-dl_mseal-mod-no-memory-seal-1.so",
+  LIB_DLOPEN_NODELETE_DEP,
+  LIBGCC_S_SO,
+};
+
+/* Expected non sealed libraries.  */
+static const char *expected_non_sealed_libs[] =
+{
+  "[vdso]",
+  "tst-dl_mseal-no-memory-seal",
+  LIB_PRELOAD,
+  LIB_AUDIT,
+  "tst-dl_mseal-mod-no-memory-seal-2.so",
+  LIB_DLOPEN_DEFAULT,
+  LIB_DLOPEN_DEFAULT_DEP,
+  LIB_DLOPEN_NODELETE,
+};
+
+#include "tst-dl_mseal-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
index fbf18d9b7c..6c77b14d86 100644
--- a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
@@ -1,4 +1,4 @@ 
-/* Basic tests for sealing.  Static version.
+/* Basic tests for sealing.
    Copyright (C) 2024 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -198,7 +198,7 @@  handle_restart (void)
 
   /* Also check if all the expected sealed maps were found.  */
   for (int i = 0; i < array_length (expected_sealed_libs); i++)
-    if (!found_expected[i])
+    if (expected_sealed_libs[i][0] && !found_expected[i])
       FAIL_EXIT1 ("expected VMA %s not sealed\n", expected_sealed_libs[i]);
 
   return 0;
@@ -239,7 +239,7 @@  do_test (int argc, char *argv[])
   spargv[i] = NULL;
 
   char *envvarss[4];
-  envvarss[0] = (char *) "GLIBC_TUNABLES=glibc.rtld.seal=2";
+  envvarss[0] = (char *) "GLIBC_TUNABLES=glibc.rtld.seal=" GLIBC_RTLD_SEAL;
 #ifndef TEST_STATIC
   envvarss[1] = (char *) "LD_PRELOAD=" LIB_PRELOAD;
   envvarss[2] = (char *) "LD_AUDIT=" LIB_AUDIT,
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c
new file mode 100644
index 0000000000..257500ea47
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c
@@ -0,0 +1,38 @@ 
+/* Basic tests for sealing.  Static version.
+   Copyright (C) 2024 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/>.  */
+
+/* This test checks the GNU_PROPERTY_NO_MEMORY_SEAL handling on a statically
+   built binary.  In this case only the vDSO (if existent) will be sealed.  */
+
+#define GLIBC_RTLD_SEAL          "1"
+#define TEST_STATIC              1
+
+/* Expected libraries that loader will seal.  */
+static const char *expected_sealed_libs[] =
+{
+  "",
+};
+
+/* Expected non sealed libraries.  */
+static const char *expected_non_sealed_libs[] =
+{
+  "[vdso]",
+  "tst-dl_mseal-static-no-memory-seal",
+};
+
+#include "tst-dl_mseal-skeleton.c"
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index 08387dfaff..26a687d611 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -19,6 +19,7 @@ 
 #ifndef _DL_PROP_H
 #define _DL_PROP_H
 
+#include <dl-prop-mseal.h>
 #include <libintl.h>
 
 extern void _dl_cet_check (struct link_map *, const char *)
@@ -241,6 +242,9 @@  _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
 			  uint32_t datasz, void *data)
 {
   /* This is called on each GNU property.  */
+  if (_dl_process_gnu_property_seal (l, fd, type, datasz, data))
+    return 0;
+
   unsigned int needed_1 = 0;
   unsigned int feature_1_and = 0;
   unsigned int isa_1_needed = 0;