@@ -307,6 +307,9 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
#endif /* !SHARED */
+ /* Make the thread executable if required. */
+ GLRO(dl_check_executable_stack) ();
+
/* Register the destructor of the dynamic linker if there is any. */
if (__glibc_likely (rtld_fini != NULL))
__cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
@@ -138,7 +138,7 @@ glibc {
execstack {
type: INT_32
minval: 0
- maxval: 1
+ maxval: 2
default: 1
}
}
@@ -372,6 +372,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_error_free = _dl_error_free,
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
._dl_libc_freeres = __rtld_libc_freeres,
+ ._dl_check_executable_stack = _dl_check_executable_stack,
};
/* If we would use strong_alias here the compiler would see a
non-hidden definition. This would undo the effect of the previous
@@ -13,6 +13,6 @@ glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0x[f]+)
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
glibc.rtld.enable_secure: 0 (min: 0, max: 1)
-glibc.rtld.execstack: 1 (min: 0, max: 1)
+glibc.rtld.execstack: 1 (min: 0, max: 2)
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
@@ -365,8 +365,11 @@ change the main stack permission if kernel starts with a non-executable stack.
The @code{glibc.rtld.execstack} can be used to control whether an executable
stack is allowed from the main program. Setting the value to @code{0} disables
the ABI auto-negotiation (meaning no executable stacks even if the ABI or ELF
-header requires it), while @code{1} enables auto-negotiation (although the
-program might not need an executable stack).
+header requires it), @code{1} enables auto-negotiation (although the program
+might not need an executable stack), while @code{2} forces and executable
+stack during initialization (this is provide for compatibility reasons, where
+the program requires to dynamically load modules with executable stacks with
+@code{dlopen}).
When executable stacks are not allowed, and if the main program requires it,
the loader will fail with an error message.
@@ -380,7 +383,8 @@ of hardware capabilities and kernel configuration.
@strong{NB:} Trying to load a dynamic shared library with @code{dlopen} or
@code{dlmopen} that requires an executable stack will always fail if the
main program does not require an executable stack at loading time. This
-is enforced regardless of the tunable value.
+can be disable by setting the tunable to @code{2}, where the stack is
+always executable.
@end deftp
@node Elision Tunables
@@ -671,6 +671,8 @@ struct rtld_global_ro
/* Called from __libc_shared to deallocate malloc'ed memory. */
void (*_dl_libc_freeres) (void);
+ int (*_dl_check_executable_stack) (void);
+
/* Implementation of _dl_find_object. The public entry point is in
libc, and this is patched by __rtld_static_init to support static
dlopen. */
@@ -707,6 +709,8 @@ extern const ElfW(Phdr) *_dl_phdr;
extern size_t _dl_phnum;
#endif
+int _dl_check_executable_stack (void) attribute_hidden;
+
/* This function changes the permission of the memory region pointed
by STACK_ENDP to executable and update the internal memory protection
flags for future thread stack creation. */
@@ -681,6 +681,18 @@ tests-special += \
$(objpfx)tst-nolink-libc-2.out \
# tests-special
endif
+
+ifeq ($(have-z-execstack),yes)
+tests += \
+ tst-execstack-tunable \
+ # tests
+
+# Re-use the module with an executable stack from elf/Makefile
+$(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so
+
+tst-execstack-tunable-ENV = GLIBC_TUNABLES=glibc.rtld.execstack=2
+endif
+
endif # $(subdir) == elf
ifeq ($(subdir),rt)
@@ -17,9 +17,10 @@
<https://www.gnu.org/licenses/>. */
#include <ldsodefs.h>
+#include <dl-tunables.h>
-int
-_dl_make_stack_executable (void **stack_endp)
+static int
+make_stack_executable (void **stack_endp)
{
/* This gives us the highest/lowest page that needs to be changed. */
uintptr_t page = ((uintptr_t) *stack_endp
@@ -35,11 +36,31 @@ _dl_make_stack_executable (void **stack_endp)
) != 0)
return errno;
+ /* Remember that we changed the permission. */
+ GL(dl_stack_flags) |= PF_X;
+
+ return 0;
+}
+
+int
+_dl_make_stack_executable (void **stack_endp)
+{
+ int r = make_stack_executable (stack_endp);
+ if (r != 0)
+ return r;
+
/* Clear the address. */
*stack_endp = NULL;
- /* Remember that we changed the permission. */
- GL(dl_stack_flags) |= PF_X;
+ return r;
+}
+int
+_dl_check_executable_stack (void)
+{
+ if (TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 2)
+ /* We can't clean the __libc_stack_end because it is marked as RO
+ when this function is called. */
+ return make_stack_executable (&__libc_stack_end);
return 0;
}
new file mode 100644
@@ -0,0 +1,12 @@
+#ifndef _INCLUDE_SYS_PERSONALITY_H
+#define _INCLUDE_SYS_PERSONALITY_H 1
+
+#include_next <sys/personality.h>
+
+# ifndef _ISOMAC
+
+extern __typeof (personality) __personality __THROW;
+hidden_proto (__personality)
+
+# endif /* _ISOMAC */
+#endif /* sys/sysinfo.h */
new file mode 100644
@@ -0,0 +1 @@
+#include "tst-execstack-tunable-skeleton.c"
new file mode 100644
@@ -0,0 +1,39 @@
+/* Check glibc.rtld.execstack=2 makes the stack executable.
+
+ 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 <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
+ TEST_VERIFY (h != NULL);
+
+ void (*f)(void) = xdlsym (h, "tryme");
+ f ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
new file mode 100644
@@ -0,0 +1,39 @@
+/* Check if READ_IMPLIES_EXEC makes the initial stack executable (BZ#32653)
+
+ 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 <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
+ TEST_VERIFY (h != NULL);
+
+ void (*f)(void) = xdlsym (h, "tryme");
+ f ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>