aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2024-11-28 14:36:45 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2024-12-31 09:04:20 -0300
commit58272284b633e5fd17293abdc55d56e546a1b02a (patch)
tree4a1946ea2d7545fc77c8944aaddc3965564f5adb /elf
parentc9540704ac187e31bb35509b5e0fc1472b9ae1d9 (diff)
downloadglibc-58272284b633e5fd17293abdc55d56e546a1b02a.zip
glibc-58272284b633e5fd17293abdc55d56e546a1b02a.tar.gz
glibc-58272284b633e5fd17293abdc55d56e546a1b02a.tar.bz2
elf: Add glibc.rtld.execstack
The new tunable can be used to control whether executable stacks are allowed from either the main program or dependencies. The default is to allow executable stacks. The executable stacks default permission is checked agains the one provided by the PT_GNU_STACK from program headers (if present). The tunable also disables the stack permission change if any dependency requires an executable stack at loading time. Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. Reviewed-by: Florian Weimer <fweimer@redhat.com>
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile44
-rw-r--r--elf/dl-load.c4
-rw-r--r--elf/dl-support.c5
-rw-r--r--elf/dl-tunables.list6
-rw-r--r--elf/rtld.c4
-rw-r--r--elf/tst-rtld-list-tunables.exp1
6 files changed, 63 insertions, 1 deletions
diff --git a/elf/Makefile b/elf/Makefile
index cea48e9..4874d9b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -570,6 +570,13 @@ tests-execstack-yes = \
tests-execstack-static-yes = \
tst-execstack-prog-static
# tests-execstack-static-yes
+ifeq (yes,$(run-built-tests))
+tests-execstack-special-yes = \
+ $(objpfx)tst-execstack-needed-noexecstack.out \
+ $(objpfx)tst-execstack-prog-noexecstack.out \
+ $(objpfx)tst-execstack-prog-static-noexecstack.out \
+ # tests-execstack-special-yes
+endif # $(run-built-tests)
endif
endif
ifeq ($(have-depaudit),yes)
@@ -666,6 +673,7 @@ $(objpfx)tst-rtld-dash-dash.out: tst-rtld-dash-dash.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)tst-ldconfig-X.out \
@@ -1989,6 +1997,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
diff --git a/elf/dl-load.c b/elf/dl-load.c
index a238ff4..76430e2 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -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
@@ -1317,7 +1318,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)
errval = _dl_make_stack_executable (stack_endp);
else
errval = EINVAL;
diff --git a/elf/dl-support.c b/elf/dl-support.c
index fe1f8c8..73fcd33 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -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. */
@@ -331,6 +332,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. */
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 40ac5b3..8e65629 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -135,6 +135,12 @@ glibc {
maxval: 1
default: 0
}
+ execstack {
+ type: INT_32
+ minval: 0
+ maxval: 1
+ default: 1
+ }
}
mem {
diff --git a/elf/rtld.c b/elf/rtld.c
index 5eb130b..8dd0381 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1645,6 +1645,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 (_dl_rtld_map.l_info[DT_SONAME] != NULL
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
index db0e1c8..9f5990f 100644
--- a/elf/tst-rtld-list-tunables.exp
+++ b/elf/tst-rtld-list-tunables.exp
@@ -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]+)