aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv')
-rw-r--r--sysdeps/unix/sysv/linux/Makefile14
-rw-r--r--sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-dlopen.c1
-rw-r--r--sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.c47
-rw-r--r--sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.h33
-rw-r--r--sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-static.c2
-rw-r--r--sysdeps/unix/sysv/linux/tst-dl_mseal-mutable.c242
6 files changed, 339 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 8fe74be95f..d14ba1b121 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -690,6 +690,7 @@ endif
ifeq ($(have-z-memory-seal),yes)
tests-static += \
+ tst-dl_mseal-mutable-static \
tst-dl_mseal-static \
tst-dl_mseal-static-noseal \
# tests-static
@@ -697,6 +698,7 @@ tests-static += \
tests += \
$(tests-static) \
tst-dl_mseal \
+ tst-dl_mseal-mutable \
tst-dl_mseal-noseal \
# tests
@@ -708,6 +710,8 @@ modules-names += \
tst-dl_mseal-dlopen-2-1 \
tst-dl_mseal-mod-1 \
tst-dl_mseal-mod-2 \
+ tst-dl_mseal-mutable-dlopen \
+ tst-dl_mseal-mutable-mod \
tst-dl_mseal-preload \
# modules-names
@@ -731,6 +735,10 @@ $(objpfx)tst-dl_mseal-noseal.out: \
$(objpfx)tst-dl_mseal-dlopen-2.so \
$(objpfx)tst-dl_mseal-dlopen-2-1.so
+$(objpfx)tst-dl_mseal-mutable.out: \
+ $(objpfx)tst-dl_mseal-mutable-mod.so \
+ $(objpfx)tst-dl_mseal-mutable-dlopen.so
+
ifeq ($(enable-memory-seal),yes)
CFLAGS-tst-dl_mseal.c += -DDEFAULT_MEMORY_SEAL
CFLAGS-tst-dl_mseal-noseal.c += -DDEFAULT_MEMORY_SEAL
@@ -738,6 +746,8 @@ 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-mutable = -Wl,--no-as-needed -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-mutable-static = -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
@@ -745,12 +755,16 @@ 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
+LDFLAGS-tst-dl_mseal-mutable-mod.so = -Wl,-z,memory-seal
+LDFLAGS-tst-dl_mseal-mutable-dlopen.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-mutable: $(objpfx)tst-dl_mseal-mutable-mod.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
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-dlopen.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-dlopen.c
new file mode 100644
index 0000000000..325b2004b5
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-dlopen.c
@@ -0,0 +1 @@
+#include "tst-dl_mseal-mutable-mod.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.c
new file mode 100644
index 0000000000..fb7cf03925
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.c
@@ -0,0 +1,47 @@
+/* Check if PT_OPENBSD_MUTABLE is correctly applied.
+ 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 <elf.h>
+#include "tst-dl_mseal-mutable-mod.h"
+
+static unsigned char mutable_array1[128]
+ __attribute__ ((section (GNU_MUTABLE_SECTION_NAME)))
+ = { 0 };
+static unsigned char mutable_array2[256]
+ __attribute__ ((section (GNU_MUTABLE_SECTION_NAME)))
+ = { 0 };
+
+static unsigned char immutable_array[256];
+
+struct array_t
+get_mutable_array1 (void)
+{
+ return (struct array_t) { mutable_array1, sizeof (mutable_array1) };
+}
+
+struct array_t
+get_mutable_array2 (void)
+{
+ return (struct array_t) { mutable_array2, sizeof (mutable_array2) };
+}
+
+struct array_t
+get_immutable_array (void)
+{
+ return (struct array_t) { immutable_array, sizeof (immutable_array) };
+}
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.h b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.h
new file mode 100644
index 0000000000..cb0153756b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-mod.h
@@ -0,0 +1,33 @@
+/* Check if PT_OPENBSD_MUTABLE is correctly applied.
+ 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 <stddef.h>
+
+#define LIB_DLOPEN "tst-dl_mseal-mutable-dlopen.so"
+
+struct array_t
+{
+ unsigned char *arr;
+ size_t size;
+};
+
+typedef struct array_t (*get_array_t)(void);
+
+struct array_t get_mutable_array1 (void);
+struct array_t get_mutable_array2 (void);
+struct array_t get_immutable_array (void);
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-static.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-static.c
new file mode 100644
index 0000000000..550ef3f056
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable-static.c
@@ -0,0 +1,2 @@
+#define TEST_STATIC 1
+#include "tst-dl_mseal-mutable.c"
diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable.c
new file mode 100644
index 0000000000..d547e05cb1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mutable.c
@@ -0,0 +1,242 @@
+/* Check if PT_OPENBSD_MUTABLE is correctly applied.
+ 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 <dlfcn.h>
+#include <errno.h>
+#include <link.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <libc-pointer-arith.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <support/xdlfcn.h>
+#include <support/xsignal.h>
+#include <support/xunistd.h>
+
+#include "tst-dl_mseal-mutable-mod.h"
+
+static long int pagesize;
+
+/* To check if the protection flags are correctly set, the thread tries
+ read/writes on it and checks if a SIGSEGV is generated. */
+
+static volatile sig_atomic_t signal_jump_set;
+static sigjmp_buf signal_jmp_buf;
+
+static void
+sigsegv_handler (int sig)
+{
+ if (signal_jump_set == 0)
+ return;
+
+ siglongjmp (signal_jmp_buf, sig);
+}
+
+static bool
+try_access_buf (unsigned char *ptr, bool write)
+{
+ signal_jump_set = true;
+
+ bool failed = sigsetjmp (signal_jmp_buf, 0) != 0;
+ if (!failed)
+ {
+ if (write)
+ *(volatile unsigned char *)(ptr) = 'x';
+ else
+ *(volatile unsigned char *)(ptr);
+ }
+
+ signal_jump_set = false;
+ return !failed;
+}
+
+struct range_t
+{
+ const char *name;
+ unsigned char *start;
+ size_t size;
+ bool found;
+};
+
+static int
+callback (struct dl_phdr_info *info, size_t size, void *data)
+{
+ struct range_t *range = data;
+ if (strcmp (info->dlpi_name, range->name) != 0)
+ return 0;
+
+ for (size_t i = 0; i < info->dlpi_phnum; i++)
+ if (info->dlpi_phdr[i].p_type == PT_GNU_MUTABLE)
+ {
+ range->start = (unsigned char *) info->dlpi_phdr[i].p_vaddr;
+ range->size = info->dlpi_phdr[i].p_memsz;
+ range->found = true;
+ break;
+ }
+
+ return 0;
+}
+
+static bool
+find_mutable_range (void *addr, struct range_t *range)
+{
+ struct dl_find_object dlfo;
+ if (_dl_find_object (addr, &dlfo) != 0)
+ return false;
+
+ range->name = dlfo.dlfo_link_map->l_name;
+ range->found = false;
+ dl_iterate_phdr (callback, range);
+ if (range->found)
+ range->start = dlfo.dlfo_link_map->l_addr + range->start;
+
+ return range->found;
+}
+
+static bool
+__attribute_used__
+try_read_buf (unsigned char *ptr)
+{
+ return try_access_buf (ptr, false);
+}
+
+static bool
+__attribute_used__
+try_write_buf (unsigned char *ptr)
+{
+ return try_access_buf (ptr, true);
+}
+
+/* The GNU_MUTABLE_SECTION_NAME section is page-aligned and with a size
+ multiple of page size. */
+
+unsigned char mutable_array1[64]
+ __attribute__ ((section (GNU_MUTABLE_SECTION_NAME)))
+ = { 0 };
+unsigned char mutable_array2[32]
+ __attribute__ ((section (GNU_MUTABLE_SECTION_NAME)))
+ = { 0 };
+
+unsigned char immutable_array[128];
+
+static void
+check_array (struct array_t *arr)
+{
+ TEST_COMPARE (try_write_buf (arr->arr), false);
+ TEST_COMPARE (try_write_buf (&arr->arr[arr->size/2]), false);
+ TEST_COMPARE (try_write_buf (&arr->arr[arr->size-1]), false);
+}
+
+static void
+check_mutable (struct array_t *mut1,
+ struct array_t *mut2,
+ struct array_t *imut)
+{
+ struct range_t range1;
+ struct range_t range2;
+
+ TEST_VERIFY_EXIT (find_mutable_range (mut1->arr, &range1));
+ TEST_VERIFY (mut1->arr >= range1.start);
+ TEST_VERIFY (mut1->arr + mut1->size <= range1.start + range1.size);
+
+ TEST_VERIFY_EXIT (find_mutable_range (mut2->arr, &range2));
+ TEST_VERIFY (mut2->arr >= range2.start);
+ TEST_VERIFY (mut2->arr + mut2->size <= range2.start + range2.size);
+
+ /* Assume that both array will be placed in the same page since their
+ combined size is less than pagesize. */
+ TEST_VERIFY (range1.start == range2.start);
+ TEST_VERIFY (range2.size == range2.size);
+
+ if (test_verbose > 0)
+ printf ("mutable region: %-30s - %p-%p\n",
+ range1.name[0] == '\0' ? "main program" : basename (range1.name),
+ range1.start,
+ range1.start + range1.size);
+
+ memset (mut1->arr, 0xaa, mut1->size);
+ memset (mut2->arr, 0xbb, mut1->size);
+ memset (imut->arr, 0xcc, imut->size);
+
+ /* Sanity check, imut should be immutable. */
+ {
+ void *start = PTR_ALIGN_DOWN (imut->arr, pagesize);
+ TEST_COMPARE (mprotect (start, pagesize, PROT_READ), -1);
+ TEST_COMPARE (errno, EPERM);
+ }
+
+ /* Change permission of mutable region to just allow read. */
+ xmprotect ((void *)range1.start, range1.size, PROT_READ);
+
+ check_array (mut1);
+ check_array (mut2);
+}
+
+static int
+do_test (void)
+{
+ pagesize = xsysconf (_SC_PAGESIZE);
+
+ {
+ struct sigaction sa = {
+ .sa_handler = sigsegv_handler,
+ .sa_flags = SA_NODEFER,
+ };
+ sigemptyset (&sa.sa_mask);
+ xsigaction (SIGSEGV, &sa, NULL);
+ }
+
+#define ARR_TO_RANGE(__arr) \
+ &((struct array_t) { __arr, sizeof (__arr) })
+
+ check_mutable (ARR_TO_RANGE (mutable_array1),
+ ARR_TO_RANGE (mutable_array2),
+ ARR_TO_RANGE (immutable_array));
+
+#ifndef TEST_STATIC
+ {
+ struct array_t mut1 = get_mutable_array1 ();
+ struct array_t mut2 = get_mutable_array2 ();
+ struct array_t imut = get_immutable_array ();
+ check_mutable (&mut1, &mut2, &imut);
+ }
+
+ {
+ void *h = xdlopen (LIB_DLOPEN, RTLD_NOW | RTLD_NODELETE);
+
+#define GET_ARRAY_DLOPEN(__name) \
+ ({ \
+ get_array_t f = xdlsym (h, __name); \
+ f(); \
+ })
+
+ struct array_t mut1 = GET_ARRAY_DLOPEN ("get_mutable_array1");
+ struct array_t mut2 = GET_ARRAY_DLOPEN ("get_mutable_array2");
+ struct array_t imut = GET_ARRAY_DLOPEN ("get_immutable_array");
+ check_mutable (&mut1, &mut2, &imut);
+ }
+#endif
+
+ return 0;
+}
+
+#include <support/test-driver.c>