]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
linux: Add memory sealing tests
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Fri, 6 Dec 2024 17:37:56 +0000 (14:37 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Fri, 7 Mar 2025 11:46:49 +0000 (08:46 -0300)
The new tests added are:

1. tst-dl_mseal: check memory sealing is applied for statically
   linked binaries.

2. tst-dl_mseal-static: memory sealing is not applied if there is no
   gnu attribute for statically linked binaries.

3. tst-dl-mseal: check memory sealing works as expected on multiples places:
   - On the binary itself.
   - On a LD_PRELOAD library.
   - On a depedency modules (tst-dl_mseal-mod-{1,2}.so).
   - On a audit modules (tst-dl_mseal-auditmod.so).
   - On a dlopen dependency opened with RTLD_NODELETE).
   - On the libgcc_s Aopened by thread unwind.

4. tst-dl-mseal-noseal: check if mixing object with and without
   memory sealing works as expected.

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

15 files changed:
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-common.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-static-noseal.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal-static.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-dl_mseal.c [new file with mode: 0644]

index a72635e340a190340f2102671ae703d0e9792110..8fe74be95f0e0cc17ab9450bd2948eaadaebe719 100644 (file)
@@ -687,6 +687,84 @@ tests-special += \
   $(objpfx)tst-nolink-libc-2.out \
   # tests-special
 endif
+
+ifeq ($(have-z-memory-seal),yes)
+tests-static += \
+  tst-dl_mseal-static \
+  tst-dl_mseal-static-noseal \
+  # tests-static
+
+tests += \
+  $(tests-static) \
+  tst-dl_mseal \
+  tst-dl_mseal-noseal \
+  # tests
+
+modules-names += \
+  tst-dl_mseal-auditmod \
+  tst-dl_mseal-dlopen-1 \
+  tst-dl_mseal-dlopen-1-1 \
+  tst-dl_mseal-dlopen-2 \
+  tst-dl_mseal-dlopen-2-1 \
+  tst-dl_mseal-mod-1 \
+  tst-dl_mseal-mod-2 \
+  tst-dl_mseal-preload \
+  # modules-names
+
+$(objpfx)tst-dl_mseal.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-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
+
+ifeq ($(enable-memory-seal),yes)
+CFLAGS-tst-dl_mseal.c += -DDEFAULT_MEMORY_SEAL
+CFLAGS-tst-dl_mseal-noseal.c += -DDEFAULT_MEMORY_SEAL
+endif
+
+LDFLAGS-tst-dl_mseal = -Wl,--no-as-needed -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-static = -Wl,--no-as-needed -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-mod-1.so = -Wl,--no-as-needed -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-mod-2.so = -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-dlopen-1.so = -Wl,--no-as-needed
+LDFLAGS-tst-dl_mseal-dlopen-2.so = -Wl,--no-as-needed -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-preload.so = -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-auditmod.so = -Wl,-z,memory-seal
+
+tst-dl_mseal-noseal-no-memory-seal = yes
+tst-dl_mseal-dlopen-1-1.so-no-memory-seal = yes
+tst-dl_mseal-dlopen-2-1.so-no-memory-seal = yes
+
+$(objpfx)tst-dl_mseal: $(objpfx)tst-dl_mseal-mod-1.so
+$(objpfx)tst-dl_mseal-noseal: $(objpfx)tst-dl_mseal-mod-1.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
+
+LDFLAGS-tst-dl_mseal-noseal = -Wl,--no-as-needed
+
+tst-dl_mseal-static-noseal-no-memory-seal = yes
+
+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)
+endif
+
 endif # $(subdir) == elf
 
 ifeq ($(subdir),rt)
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c
new file mode 100644 (file)
index 0000000..7767620
--- /dev/null
@@ -0,0 +1,23 @@
+/* Audit module for tst-dl_mseal test.
+   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/>.  */
+
+unsigned int
+la_version (unsigned int v)
+{
+  return v;
+}
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-common.h b/sysdeps/unix/sysv/linux/tst-dl_mseal-common.h
new file mode 100644 (file)
index 0000000..4e2461b
--- /dev/null
@@ -0,0 +1,29 @@
+/* Basic tests for sealing.
+   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/>.  */
+
+#define LIB_PRELOAD              "tst-dl_mseal-preload.so"
+
+#define LIB_AUDIT                "tst-dl_mseal-auditmod.so"
+
+#define LIB_MODULE1              "tst-dl_mseal-mod-1.so"
+#define LIB_MODULE1_DEP          "tst-dl_mseal-mod-2.so"
+
+#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-2.so"
+#define LIB_DLOPEN_NODELETE_DEP  "tst-dl_mseal-dlopen-2-1.so"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c
new file mode 100644 (file)
index 0000000..fd11653
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int foo2_1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c
new file mode 100644 (file)
index 0000000..aa7a183
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int foo2 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c
new file mode 100644 (file)
index 0000000..dc3d832
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int bar2_1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c
new file mode 100644 (file)
index 0000000..6be7ce4
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int bar2 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c
new file mode 100644 (file)
index 0000000..e8e42de
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int foo1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c
new file mode 100644 (file)
index 0000000..05226a4
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int bar1 (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-noseal.c
new file mode 100644 (file)
index 0000000..686347c
--- /dev/null
@@ -0,0 +1,90 @@
+/* Basic tests for sealing.
+   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 <support/xdlfcn.h>
+#include <support/xthread.h>
+#include <gnu/lib-names.h>
+
+/* Check if memory sealing is not applied if program does not have the
+   GNU_PROPERTY_MEMORY_SEAL attribute.  It included:
+   - On the binary itself.
+   - On a LD_PRELOAD library.
+   - On a dependency modules (tst-dl_mseal-mod-{1,2}.so).
+   - On a audit modules (tst-dl_mseal-auditmod.so).
+   - On a dlopen dependency opened with RTLD_NODELETE
+     (tst-dl_mseal-dlopen-{2,2-1}.so).
+   - On the libgcc_s opened by thread unwind.  */
+
+#include "tst-dl_mseal-common.h"
+
+/* Expected libraries that loader will seal.  */
+static const char *expected_sealed_vmas[] =
+{
+  "",
+};
+
+/* Expected non sealed libraries.  */
+static const char *expected_non_sealed_vmas[] =
+{
+  "libc.so",
+  "ld.so",
+  "tst-dl_mseal-noseal",
+  LIB_PRELOAD,
+  LIB_AUDIT,
+  LIB_MODULE1,
+  LIB_MODULE1_DEP,
+  LIB_DLOPEN_NODELETE,
+  LIB_DLOPEN_NODELETE_DEP,
+  LIB_DLOPEN_DEFAULT,
+  LIB_DLOPEN_DEFAULT_DEP,
+  /* Auxiliary pages mapped by the kernel.  */
+  "[vdso]",
+  "[sigpage]",
+};
+
+/* Special pages, either Auxiliary kernel pages where permission can not be
+   changed or auxiliary libs that we can know prior hand that sealing is
+   enabled.  */
+static const char *expected_non_sealed_special[] =
+{
+  LIBGCC_S_SO,
+  "[vectors]",
+};
+
+static void *
+tf (void *closure)
+{
+  pthread_exit (NULL);
+  return NULL;
+}
+
+static void
+run_extra_steps (void)
+{
+  /* dlopen should work even if the modules contains the sealing attribute.  */
+  xdlopen (LIB_DLOPEN_NODELETE, RTLD_NOW | RTLD_NODELETE);
+  xdlopen (LIB_DLOPEN_DEFAULT, RTLD_NOW);
+
+  /* pthread_exit will load LIBGCC_S_SO.  */
+  xpthread_join (xpthread_create (NULL, tf, NULL));
+}
+
+#define LD_PRELOAD LIB_PRELOAD
+#define LD_AUDIT   LIB_AUDIT
+
+#include "tst-dl_mseal-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c
new file mode 100644 (file)
index 0000000..414c8c7
--- /dev/null
@@ -0,0 +1,19 @@
+/* Additional module for tst-dl_mseal test.
+   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/>.  */
+
+int foo (void) { return 42; }
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c
new file mode 100644 (file)
index 0000000..570a0a8
--- /dev/null
@@ -0,0 +1,263 @@
+/* Basic tests for memory sealing.
+   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 <array_length.h>
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+
+#if UINTPTR_MAX == UINT64_MAX
+# define PTR_FMT "#018" PRIxPTR
+#else
+# define PTR_FMT "#010" PRIxPTR
+#endif
+
+static int
+new_flags (const char flags[4])
+{
+  bool read_flag  = flags[0] == 'r';
+  bool write_flag = flags[1] == 'w';
+  bool exec_flag  = flags[2] == 'x';
+
+  write_flag = !write_flag;
+
+  return (read_flag ? PROT_READ : 0)
+        | (write_flag ? PROT_WRITE : 0)
+        | (exec_flag ? PROT_EXEC : 0);
+}
+
+/* Libraries/VMA that could not be sealed, and that checking for sealing
+   does not work (kernel does not allow changing protection).  */
+static const char *non_sealed_vmas[] =
+{
+  ".",                         /* basename value for empty string anonymous
+                                  mappings.  */
+  "[heap]",
+  "[vsyscall]",
+  "[vvar]",
+  "[stack]",
+  "[vvar_vclock]",
+  "zero",                      /* /dev/zero  */
+};
+
+static int
+is_in_string_list (const char *s, const char *const list[], size_t len)
+{
+  for (size_t i = 0; i != len; i++)
+    if (strcmp (s, list[i]) == 0)
+      return i;
+  return -1;
+}
+#define IS_IN_STRING_LIST(__s, __list) \
+  is_in_string_list (__s, __list, array_length (__list))
+
+static int
+handle_restart (void)
+{
+  run_extra_steps ();
+
+  FILE *fp = xfopen ("/proc/self/maps", "r");
+  char *line = NULL;
+  size_t linesiz = 0;
+
+  unsigned long pagesize = getpagesize ();
+
+  bool found_expected[array_length(expected_sealed_vmas)] = { false };
+  while (xgetline (&line, &linesiz, fp) > 0)
+    {
+      uintptr_t start;
+      uintptr_t end;
+      char flags[5] = { 0 };
+      char name[256] = { 0 };
+      int idx;
+
+      /* The line is in the form:
+        start-end flags offset dev inode pathname   */
+      int r = sscanf (line,
+                     "%" SCNxPTR "-%" SCNxPTR " %4s %*s %*s %*s %256s",
+                     &start,
+                     &end,
+                     flags,
+                     name);
+      TEST_VERIFY_EXIT (r == 3 || r == 4);
+
+      int found = false;
+
+      const char *libname = basename (name);
+      if ((idx = IS_IN_STRING_LIST (libname, expected_sealed_vmas))
+          != -1)
+       {
+         /* Check if we can change the protection flags of the segment.  */
+         int new_prot = new_flags (flags);
+         TEST_VERIFY_EXIT (mprotect ((void *) start, end - start,
+                                     new_prot) == -1);
+         TEST_VERIFY_EXIT (errno == EPERM);
+
+         /* Also checks trying to map over the sealed libraries.  */
+         {
+           char *p = mmap ((void *) start, pagesize, new_prot,
+                           MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+           TEST_VERIFY_EXIT (p == MAP_FAILED);
+           TEST_VERIFY_EXIT (errno == EPERM);
+         }
+
+         /* And if remap is also blocked.  */
+         {
+           char *p = mremap ((void *) start, end - start, end - start, 0);
+           TEST_VERIFY_EXIT (p == MAP_FAILED);
+           TEST_VERIFY_EXIT (errno == EPERM);
+         }
+
+         printf ("sealed:     vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n",
+                 start,
+                 end,
+                 flags,
+                 name);
+
+         found_expected[idx] = true;
+         found = true;
+       }
+      else if ((idx = IS_IN_STRING_LIST (libname, expected_non_sealed_vmas))
+              != -1)
+       {
+         /* Check if expected non-sealed segments protection can indeed be
+            changed.  The idea is to use something that would not break
+            process execution, so just try to mprotect with all protection
+            bits.  */
+         int new_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+         TEST_VERIFY_EXIT (mprotect ((void *) start, end - start, new_prot)
+                           == 0);
+
+         printf ("not-sealed: vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n",
+                 start,
+                 end,
+                 flags,
+                 name);
+
+         found = true;
+       }
+      else if (IS_IN_STRING_LIST (libname, expected_non_sealed_special) != -1)
+       {
+         /* These pages protection can no be changed.  */
+         found = true;
+       }
+
+      if (!found)
+       {
+         if (IS_IN_STRING_LIST (libname, non_sealed_vmas) != -1)
+           printf ("not-sealed: vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n",
+                   start,
+                   end,
+                   flags,
+                   name);
+         else
+           FAIL_EXIT1 ("unexpected vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n",
+                       start,
+                       end,
+                       flags,
+                       name);
+       }
+    }
+  xfclose (fp);
+
+  printf ("\n");
+
+  /* Also check if all the expected sealed maps were found.  */
+  for (int i = 0; i < array_length (expected_sealed_vmas); i++)
+    if (expected_sealed_vmas[i][0] && !found_expected[i])
+      FAIL_EXIT1 ("expected VMA %s not sealed\n", expected_sealed_vmas[i]);
+
+  return 0;
+}
+
+static int restart;
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+     - One or four parameters left if called initially:
+       + path to ld.so         optional
+       + "--library-path"      optional
+       + the library path      optional
+       + the application name  */
+  if (restart)
+    return handle_restart ();
+
+  /* Check the test requirements.  */
+  {
+    int r = mseal (NULL, 0, 0);
+    if (r == -1 && (errno == ENOSYS || errno == EPERM))
+      FAIL_UNSUPPORTED ("mseal is not supported by the kernel");
+    else
+      TEST_VERIFY_EXIT (r == 0);
+  }
+  support_need_proc ("Reads /proc/self/maps to get stack names.");
+
+  char *spargv[9];
+  int i = 0;
+  for (; i < argc - 1; i++)
+    spargv[i] = argv[i + 1];
+  spargv[i++] = (char *) "--direct";
+  spargv[i++] = (char *) "--restart";
+  spargv[i] = NULL;
+
+  char *envvarss[] = {
+#ifdef LD_PRELOAD
+    (char *) "LD_PRELOAD=" LD_PRELOAD,
+#endif
+#ifdef LD_AUDIT
+    (char *) "LD_AUDIT=" LD_AUDIT,
+#endif
+    NULL
+  };
+
+  struct support_capture_subprocess result =
+    support_capture_subprogram (spargv[0], spargv, envvarss);
+  support_capture_subprocess_check (&result, "tst-dl_mseal", 0,
+                                   sc_allow_stdout);
+
+  {
+    FILE *out = fmemopen (result.out.buffer, result.out.length, "r");
+    TEST_VERIFY (out != NULL);
+    char *line = NULL;
+    size_t linesz = 0;
+    while (xgetline (&line, &linesz, out))
+      printf ("%s", line);
+    fclose (out);
+  }
+
+  support_capture_subprocess_free (&result);
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-static-noseal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-static-noseal.c
new file mode 100644 (file)
index 0000000..dcaea0c
--- /dev/null
@@ -0,0 +1,59 @@
+/* Basic tests for sealing.  Static version.
+   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 <support/xthread.h>
+
+/* This test checks the GNU_PROPERTY_MEMORY_SEAL handling on a statically
+   built binary.  In this case only the vDSO (if existent) will be sealed.  */
+
+#define TEST_STATIC              1
+
+/* Expected libraries that loader will seal.  */
+static const char *expected_sealed_vmas[] =
+{
+  "",
+};
+
+/* Expected non sealed libraries.  */
+static const char *expected_non_sealed_vmas[] =
+{
+  "tst-dl_mseal-static-noseal",
+  /* Auxiary pages mapped by the kernel.  */
+  "[vdso]",
+  "[sigpage]",
+};
+
+/* Auxiliary kernel pages where permission can not be changed.  */
+static const char *expected_non_sealed_special[] =
+{
+  "[vectors]",
+};
+
+static void *
+tf (void *closure)
+{
+  return NULL;
+}
+
+static void
+run_extra_steps (void)
+{
+  xpthread_join (xpthread_create (NULL, tf, NULL));
+}
+
+#include "tst-dl_mseal-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-static.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-static.c
new file mode 100644 (file)
index 0000000..bca9e0d
--- /dev/null
@@ -0,0 +1,56 @@
+/* Basic tests for sealing.  Static version.
+   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 <support/xthread.h>
+
+/* This test checks the memory sealing work on a statically built binary.  */
+
+#define TEST_STATIC              1
+
+/* Expected libraries that loader will seal.  */
+static const char *expected_sealed_vmas[] =
+{
+  "tst-dl_mseal-static",
+};
+
+/* Auxiliary pages mapped by the kernel.  */
+static const char *expected_non_sealed_vmas[] =
+{
+  "[vdso]",
+  "[sigpage]",
+};
+
+/* Auxiliary kernel pages where permission can not be changed.  */
+static const char *expected_non_sealed_special[] =
+{
+  "[vectors]",
+};
+
+static void *
+tf (void *closure)
+{
+  return NULL;
+}
+
+static void
+run_extra_steps (void)
+{
+  xpthread_join (xpthread_create (NULL, tf, NULL));
+}
+
+#include "tst-dl_mseal-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal.c
new file mode 100644 (file)
index 0000000..1a45f2a
--- /dev/null
@@ -0,0 +1,92 @@
+/* Basic tests for sealing.
+   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 <support/xdlfcn.h>
+#include <support/xthread.h>
+#include <gnu/lib-names.h>
+#include "tst-dl_mseal-common.h"
+
+/* Check if memory sealing works as expected on multiples places:
+   - On the binary itself.
+   - On a LD_PRELOAD library.
+   - On a dependency modules (tst-dl_mseal-mod-{1,2}.so).
+   - On a audit modules (tst-dl_mseal-auditmod.so).
+   - On a dlopen dependency opened with RTLD_NODELETE
+     (tst-dl_mseal-dlopen-{2,2-1}.so).
+   - On the libgcc_s opened by thread unwind.  */
+
+/* Expected libraries that loader will seal.  */
+static const char *expected_sealed_vmas[] =
+{
+#ifdef DEFAULT_MEMORY_SEAL
+  "libc.so",
+  "ld.so",
+#endif
+  "tst-dl_mseal",
+  LIB_MODULE1,
+  LIB_MODULE1_DEP,
+  LIB_PRELOAD,
+  LIB_AUDIT,
+  LIB_DLOPEN_NODELETE,
+};
+
+/* Expected non sealed libraries.  */
+static const char *expected_non_sealed_vmas[] =
+{
+#ifndef DEFAULT_MEMORY_SEAL
+  "libc.so",
+  "ld.so",
+#endif
+  LIB_DLOPEN_DEFAULT,
+  LIB_DLOPEN_DEFAULT_DEP,
+  LIB_DLOPEN_NODELETE_DEP,
+  /* Auxiliary pages mapped by the kernel.  */
+  "[vdso]",
+  "[sigpage]",
+};
+
+/* Special pages, either Auxiliary kernel pages where permission can not be
+   changed or auxiliary libs that we can know prior hand that sealing is
+   enabled.  */
+static const char *expected_non_sealed_special[] =
+{
+   LIBGCC_S_SO,
+  "[vectors]",
+};
+
+static void *
+tf (void *closure)
+{
+  pthread_exit (NULL);
+  return NULL;
+}
+
+static void
+run_extra_steps (void)
+{
+  xdlopen (LIB_DLOPEN_NODELETE, RTLD_NOW | RTLD_NODELETE);
+  xdlopen (LIB_DLOPEN_DEFAULT, RTLD_NOW);
+
+  /* pthread_exit will load LIBGCC_S_SO.  */
+  xpthread_join (xpthread_create (NULL, tf, NULL));
+}
+
+#define LD_PRELOAD LIB_PRELOAD
+#define LD_AUDIT   LIB_AUDIT
+
+#include "tst-dl_mseal-skeleton.c"