@@ -36,6 +36,10 @@ Major new features:
* On Linux, update epoll header to include epoll ioctl definitions and
related structure added in Linux kernel 6.9.
+* A new tunable, glibc.rtld.execstack, can be used to control whether
+ executable stacks are allowed from either main program or dependencies.
+ The default is to allow executable stacks.
+
Deprecated and removed features, and other changes affecting compatibility:
* Architectures which use a 32-bit seconds-since-epoch field in struct
@@ -546,6 +546,11 @@ tests-execstack-yes = \
tests-execstack-static-yes = \
tst-execstack-prog-static
# tests-execstack-static-yes
+tests-execstack-special-yes = \
+ $(objpfx)tst-execstack-prog-noexecstack.out \
+ $(objpfx)tst-execstack-needed-noexecstack.out \
+ $(objpfx)tst-execstack-prog-static-noexecstack.out \
+ # tests-execstack-special-yes
endif
ifeq ($(have-depaudit),yes)
tests += \
@@ -634,6 +639,7 @@ $(objpfx)tst-rtld-does-not-exist.out: tst-rtld-does-not-exist.sh $(objpfx)ld.so
tests += $(tests-execstack-$(have-z-execstack))
tests-static+= $(tests-execstack-static-$(have-z-execstack))
+tests-special += $(tests-execstack-special-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += \
$(objpfx)noload-mem.out \
@@ -1863,6 +1869,42 @@ CFLAGS-tst-execstack-mod.c += -Wno-trampolines
LDFLAGS-tst-execstack-prog-static = -Wl,-z,execstack
CFLAGS-tst-execstack-prog-static.c += -Wno-trampolines
+
+ifeq (yes,$(build-hardcoded-path-in-tests))
+tst-execstack-prog-noexecstack-msg = "Fatal glibc error: executable stack is not allowed$$"
+else
+tst-execstack-prog-noexecstack-msg = "error while loading shared libraries:.*cannot enable executable stack as shared object requires:"
+endif
+
+$(objpfx)tst-execstack-prog-noexecstack.out: $(objpfx)tst-execstack-prog
+ $(test-program-cmd-before-env) \
+ $(run-program-env) \
+ GLIBC_TUNABLES=glibc.rtld.execstack=0 \
+ $(test-program-cmd-after-env) $< \
+ > $@ 2>&1; echo "status: $$?" >> $@; \
+ grep -q $(tst-execstack-prog-noexecstack-msg) $@ \
+ && grep -q '^status: 127$$' $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-execstack-needed-noexecstack.out: $(objpfx)tst-execstack-needed
+ $(test-program-cmd-before-env) \
+ $(run-program-env) \
+ GLIBC_TUNABLES=glibc.rtld.execstack=0 \
+ $(test-program-cmd-after-env) $< \
+ > $@ 2>&1; echo "status: $$?" >> $@; \
+ grep -q 'error while loading shared libraries:.*cannot enable executable stack as shared object requires:' $@ \
+ && grep -q '^status: 127$$' $@; \
+ $(evaluate-test)
+
+$(objpfx)tst-execstack-prog-static-noexecstack.out: $(objpfx)tst-execstack-prog-static
+ $(test-program-cmd-before-env) \
+ $(run-program-env) \
+ GLIBC_TUNABLES=glibc.rtld.execstack=0 \
+ $< \
+ > $@ 2>&1; echo "status: $$?" >> $@; \
+ grep -q 'Fatal glibc error: executable stack is not allowed$$' $@ \
+ && grep -q '^status: 127$$' $@; \
+ $(evaluate-test)
endif
LDFLAGS-tst-array2 = -Wl,--no-as-needed
@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <gnu/lib-names.h>
+#include <dl-tunables.h>
/* Type for the buffer we put the ELF header and hopefully the program
header. This buffer does not really have to be too large. In most
@@ -1300,7 +1301,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* The stack is presently not executable, but this module
requires that it be executable. Only tries to change the
stack protection during process startup. */
- if ((mode & __RTLD_DLOPEN) == 0)
+ if ((mode & __RTLD_DLOPEN) == 0
+ && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 1)
#if PTHREAD_IN_LIBC
errval = _dl_make_stacks_executable (stack_endp);
#else
@@ -45,6 +45,7 @@
#include <dl-find_object.h>
#include <array_length.h>
#include <dl-symbol-redir-ifunc.h>
+#include <dl-tunables.h>
extern char *__progname;
char **_dl_argv = &__progname; /* This is checked for some error messages. */
@@ -335,6 +336,10 @@ _dl_non_dynamic_init (void)
break;
}
+ if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X)
+ && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0)
+ _dl_fatal_printf ("Fatal glibc error: executable stack is not allowed\n");
+
call_function_static_weak (_dl_find_object_init);
/* Setup relro on the binary itself. */
@@ -142,6 +142,12 @@ glibc {
maxval: 1
default: 0
}
+ execstack {
+ type: INT_32
+ minval: 0
+ maxval: 1
+ default: 1
+ }
}
mem {
@@ -1668,6 +1668,10 @@ dl_main (const ElfW(Phdr) *phdr,
bool has_interp = rtld_setup_main_map (main_map);
+ if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X)
+ && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0)
+ _dl_fatal_printf ("Fatal glibc error: executable stack is not allowed\n");
+
/* If the current libname is different from the SONAME, add the
latter as well. */
if (GL(dl_rtld_map).l_info[DT_SONAME] != NULL
@@ -13,5 +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.nns: 0x4 (min: 0x1, max: 0x10)
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
@@ -356,6 +356,25 @@ tests for @code{AT_SECURE} programs and not meant to be a security feature.
The default value of this tunable is @samp{0}.
@end deftp
+@deftp Tunable glibc.rtld.execstack
+@theglibc{} will use either the default architecture flags (that might contain
+the executable bit) or the value of @code{PT_GNU_STACK} (if present), and if
+the program or any shared library dependency require an executable stack the
+loader will change the main stack permission if kernel starts with a non
+executable stack.
+
+The @code{glibc.rtld.execstack} tunable allows the user to control whether
+to control executable stacks from the main program or dependencies. Setting
+its value to @code{0} disable executable stacks, where @code{1} enables it.
+The default value is @code{1}.
+
+When executable stacks are not allowed, and if the main program or dependencies
+require an executable stack, the loader will fail with an error message.
+@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
+default flags does not contain the executable bit.
+@end deftp
+
@node Elision Tunables
@section Elision Tunables
@cindex elision tunables