diff mbox series

[v6,9/9] elf: Add glibc.rtld.seal tunable

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

Commit Message

Adhemerval Zanella Netto March 11, 2025, 5:09 p.m. UTC
The new tunable can be used to disable memory sealing on the program and
all its dependencies.  This can be useful for debugging, patchable
function entries (-fpatchable-function-entry), or profiling (-mfentry,
-mnop-count, -minstrument-return) where the program might be run
with or without changes to its text segment.

Checked on x86_64-linux-gnu.
---
 NEWS                                          |  6 ++++
 elf/dl-tunables.list                          |  6 ++++
 elf/tst-rtld-list-tunables.exp                |  1 +
 manual/tunables.texi                          | 36 +++++++++++++++++++
 sysdeps/unix/sysv/linux/Makefile              | 27 +++++++-------
 sysdeps/unix/sysv/linux/dl-mseal.c            |  9 +++++
 sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c |  6 +++-
 .../unix/sysv/linux/tst-dl_mseal-skeleton.c   |  3 ++
 .../unix/sysv/linux/tst-dl_mseal-tunable.c    | 24 +++++++++++++
 9 files changed, 103 insertions(+), 15 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-tunable.c
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index ff241b2863..e3362158dc 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,12 @@  Major new features:
 * A new configure option, "--enable-memory-sealing", can be used to build
   the GNU C Library libraries and programs with memory sealing.
 
+* A new tunable, glibc.rtld.seal, can enable memory sealing on the program
+  and all its dependencies.  The tunable accepts two different values, where
+  '0' disable memory sealing (even if the GNU_PROPERTY_MEMORY_SEAL attribute
+  is present), while '1' applies sealing accordingly to the sealing
+  attribute.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
   [Add deprecations, removals and changes affecting compatibility here]
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 0b6721bc51..43758f9755 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -141,6 +141,12 @@  glibc {
       maxval: 1
       default: 1
     }
+    seal {
+      type: INT_32
+      minval: 0
+      maxval: 1
+      default: 1
+    }
   }
 
   mem {
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
index 9f5990f340..e398b9f020 100644
--- a/elf/tst-rtld-list-tunables.exp
+++ b/elf/tst-rtld-list-tunables.exp
@@ -16,3 +16,4 @@  glibc.rtld.enable_secure: 0 (min: 0, max: 1)
 glibc.rtld.execstack: 1 (min: 0, max: 1)
 glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
 glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
+glibc.rtld.seal: 1 (min: 0, max: 1)
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 7f0246c789..1af0956808 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -383,6 +383,42 @@  main program does not require an executable stack at loading time.  This
 is enforced regardless of the tunable value.
 @end deftp
 
+@deftp Tunable glibc.rtld.seal
+Sets whether to enable memory sealing during program execution.  The sealed
+memory prevents further changes to the metadata associated with an ELF mapped
+memory region, such as shrinking or expanding its size, mapping another
+segment over a pre-existing region, or changing the memory protection flags
+(check the @code{mseal} for more information).
+
+The sealing is done in multiple places where the memory is supposed to be
+immutable over program execution:
+
+@itemize @bullet
+@item
+All shared library dependencies from the binary, including the read-only segments
+after @code{PT_GNU_RELRO} setup.
+
+@item
+The binary itself, including dynamic and static linked ones.  In both cases, it is
+up either to binary or the loader to set up the sealing.
+
+@item
+Any preload libraries.
+
+@item
+Any library loaded with @code{dlopen} with @code{RTLD_NODELETE} flag.
+
+@item
+All audit modules and their dependencies.
+@end itemize
+
+The tunable accepts two values: @samp{0} where sealing is disabled even if the
+program has the GNU attribute @code{GNU_PROPERTY_MEMORY_SEAL} if present,
+and @samp{1} where sealing is aplied accondingly to the GNU attribute existent.
+
+The default value of this tunable is @samp{1}.
+@end deftp
+
 @node Elision Tunables
 @section Elision Tunables
 @cindex elision tunables
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 2faa377fd5..9bb3eeb53e 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -698,6 +698,7 @@  tests += \
   $(tests-static) \
   tst-dl_mseal \
   tst-dl_mseal-noseal \
+  tst-dl_mseal-tunable \
   # tests
 
 modules-names += \
@@ -713,25 +714,22 @@  modules-names += \
   tst-dl_mseal-preload \
   # modules-names
 
-$(objpfx)tst-dl_mseal.out: \
+test-dl_mseal-mods = \
   $(objpfx)tst-dl_mseal-auditmod.so \
-  $(objpfx)tst-dl_mseal-preload.so \
-  $(objpfx)tst-dl_mseal-mod-1.so \
-  $(objpfx)tst-dl_mseal-mod-2.so \
-  $(objpfx)tst-dl_mseal-dlopen-1.so \
   $(objpfx)tst-dl_mseal-dlopen-1-1.so \
+  $(objpfx)tst-dl_mseal-dlopen-1.so \
+  $(objpfx)tst-dl_mseal-dlopen-2-1.so \
   $(objpfx)tst-dl_mseal-dlopen-2.so \
-  $(objpfx)tst-dl_mseal-dlopen-2-1.so
-
-$(objpfx)tst-dl_mseal-noseal.out: \
-  $(objpfx)tst-dl_mseal-auditmod.so \
-  $(objpfx)tst-dl_mseal-preload.so \
   $(objpfx)tst-dl_mseal-mod-1.so \
   $(objpfx)tst-dl_mseal-mod-2.so \
-  $(objpfx)tst-dl_mseal-dlopen-1.so \
-  $(objpfx)tst-dl_mseal-dlopen-1-1.so \
-  $(objpfx)tst-dl_mseal-dlopen-2.so \
-  $(objpfx)tst-dl_mseal-dlopen-2-1.so
+  $(objpfx)tst-dl_mseal-preload.so \
+  # test-dl_mseal-mods
+
+$(objpfx)tst-dl_mseal.out: $(test-dl_mseal-mods)
+
+$(objpfx)tst-dl_mseal-noseal.out: $(test-dl_mseal-mods)
+
+$(objpfx)tst-dl_mseal-tunable.out: $(test-dl_mseal-mods)
 
 $(objpfx)tst-dl_mseal-mutable.out: \
   $(objpfx)tst-dl_mseal-mutable-mod.so \
@@ -771,6 +769,7 @@  tst-dl_mseal-ARGS = -- $(host-test-program-cmd)
 tst-dl_mseal-static-ARGS = -- $(host-test-program-cmd)
 tst-dl_mseal-noseal-ARGS = -- $(host-test-program-cmd)
 tst-dl_mseal-static-noseal-ARGS = -- $(host-test-program-cmd)
+tst-dl_mseal-tunable-ARGS = -- $(host-test-program-cmd)
 
 ifeq ($(have-pt-gnu-mutable),yes)
 tests-static += \
diff --git a/sysdeps/unix/sysv/linux/dl-mseal.c b/sysdeps/unix/sysv/linux/dl-mseal.c
index 74ab688ef3..acdbf79f1b 100644
--- a/sysdeps/unix/sysv/linux/dl-mseal.c
+++ b/sysdeps/unix/sysv/linux/dl-mseal.c
@@ -22,9 +22,18 @@ 
 #include <ldsodefs.h>
 #include <libintl.h>
 
+static inline bool
+is_sealing_enable (void)
+{
+  return TUNABLE_GET (glibc, rtld, seal, int32_t, NULL) == 1;
+}
+
 void
 _dl_mseal (void *addr, size_t len, const char *object)
 {
+  if (__glibc_unlikely (!is_sealing_enable ()))
+    return;
+
   int r = 0;
   bool fail = false;
 #if __ASSUME_MSEAL
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c
index 686347c86e..a1d0f077c4 100644
--- a/sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c
@@ -32,6 +32,10 @@ 
 
 #include "tst-dl_mseal-common.h"
 
+#ifndef TEST_NAME
+# define TEST_NAME "tst-dl_mseal-noseal"
+#endif
+
 /* Expected libraries that loader will seal.  */
 static const char *expected_sealed_vmas[] =
 {
@@ -43,7 +47,7 @@  static const char *expected_non_sealed_vmas[] =
 {
   "libc.so",
   "ld.so",
-  "tst-dl_mseal-noseal",
+  TEST_NAME,
   LIB_PRELOAD,
   LIB_AUDIT,
   LIB_MODULE1,
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
index 570a0a867d..1be341df5f 100644
--- a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
@@ -235,6 +235,9 @@  do_test (int argc, char *argv[])
 #endif
 #ifdef LD_AUDIT
     (char *) "LD_AUDIT=" LD_AUDIT,
+#endif
+#ifdef TUNABLE_ENV_VAR
+    TUNABLE_ENV_VAR,
 #endif
     NULL
   };
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-tunable.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-tunable.c
new file mode 100644
index 0000000000..df70132cd2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-tunable.c
@@ -0,0 +1,24 @@ 
+/* Check glibc.rtld.seal tunable.
+   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/>.  */
+
+/* Check if memory sealing is not applied if glibc.rtld.seal is set to 0. */
+
+#define TUNABLE_ENV_VAR (char *)"GLIBC_TUNABLES=glibc.rtld.seal=0"
+
+#define TEST_NAME "tst-dl_mseal-tunable"
+#include "tst-dl_mseal-noseal.c"