1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-05 19:01:16 +03:00

nptl: Fix pthread_getattr_np when modules with execstack are allowed (BZ 32897)

The BZ 32653 fix (12a497c716) kept the
stack pointer zeroing from make_main_stack_executable on
_dl_make_stack_executable.  However, previously the 'stack_endp'
pointed to temporary variable created before the call of
_dl_map_object_from_fd; while now we use the __libc_stack_end
directly.

Since pthread_getattr_np relies on correct __libc_stack_end, if
_dl_make_stack_executable is called (for instance, when
glibc.rtld.execstack=2 is set) __libc_stack_end will be set to zero,
and the call will always fail.

The __libc_stack_end zero was used a mitigation hardening, but since
52a01100ad it is used solely on
pthread_getattr_np code.  So there is no point in zeroing anymore.

Checked on x86_64-linux-gnu and i686-linux-gnu.
Reviewed-by: Sam James <sam@gentoo.org>
This commit is contained in:
Adhemerval Zanella
2025-04-24 12:27:44 -03:00
parent 4c966c0780
commit 0c34259423
9 changed files with 104 additions and 13 deletions

View File

@ -31,7 +31,7 @@ _dl_handle_execstack_tunable (void)
break; break;
case stack_tunable_mode_force: case stack_tunable_mode_force:
if (_dl_make_stack_executable (&__libc_stack_end) != 0) if (_dl_make_stack_executable (__libc_stack_end) != 0)
_dl_fatal_printf ( _dl_fatal_printf (
"Fatal glibc error: cannot enable executable stack as tunable requires"); "Fatal glibc error: cannot enable executable stack as tunable requires");
break; break;

View File

@ -23,7 +23,7 @@
so as to mprotect it. */ so as to mprotect it. */
int int
_dl_make_stack_executable (void **stack_endp) _dl_make_stack_executable (const void *stack_endp)
{ {
return ENOSYS; return ENOSYS;
} }

View File

@ -945,7 +945,7 @@ struct link_map *
_dl_map_object_from_fd (const char *name, const char *origname, int fd, _dl_map_object_from_fd (const char *name, const char *origname, int fd,
struct filebuf *fbp, char *realname, struct filebuf *fbp, char *realname,
struct link_map *loader, int l_type, int mode, struct link_map *loader, int l_type, int mode,
void **stack_endp, Lmid_t nsid) const void *stack_endp, Lmid_t nsid)
{ {
struct link_map *l = NULL; struct link_map *l = NULL;
const ElfW(Ehdr) *header; const ElfW(Ehdr) *header;
@ -2181,7 +2181,7 @@ _dl_map_new_object (struct link_map *loader, const char *name,
void *stack_end = __libc_stack_end; void *stack_end = __libc_stack_end;
return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader, return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
type, mode, &stack_end, nsid); type, mode, stack_end, nsid);
} }
struct link_map * struct link_map *

View File

@ -733,7 +733,7 @@ void _dl_handle_execstack_tunable (void) attribute_hidden;
/* This function changes the permission of the memory region pointed /* This function changes the permission of the memory region pointed
by STACK_ENDP to executable and update the internal memory protection by STACK_ENDP to executable and update the internal memory protection
flags for future thread stack creation. */ flags for future thread stack creation. */
int _dl_make_stack_executable (void **stack_endp) attribute_hidden; int _dl_make_stack_executable (const void *stack_endp) attribute_hidden;
/* Variable pointing to the end of the stack (or close to it). This value /* Variable pointing to the end of the stack (or close to it). This value
must be constant over the runtime of the application. Some programs must be constant over the runtime of the application. Some programs

View File

@ -26,12 +26,11 @@ extern struct hurd_startup_data *_dl_hurd_data attribute_hidden;
so as to mprotect it. */ so as to mprotect it. */
int int
_dl_make_stack_executable (void **stack_endp) _dl_make_stack_executable (const void *stack_endp)
{ {
/* Challenge the caller. */ /* Challenge the caller. */
if (__builtin_expect (*stack_endp != __libc_stack_end, 0)) if (__glibc_unlikely (stack_endp != __libc_stack_end))
return EPERM; return EPERM;
*stack_endp = NULL;
#if IS_IN (rtld) #if IS_IN (rtld)
if (__mprotect ((void *)_dl_hurd_data->stack_base, _dl_hurd_data->stack_size, if (__mprotect ((void *)_dl_hurd_data->stack_base, _dl_hurd_data->stack_size,

View File

@ -273,6 +273,7 @@ tests += \
tst-spin4 \ tst-spin4 \
tst-spin5 \ tst-spin5 \
tst-stack1 \ tst-stack1 \
tst-stack2 \
tst-stdio1 \ tst-stdio1 \
tst-stdio2 \ tst-stdio2 \
tst-thrd-detach \ tst-thrd-detach \
@ -368,6 +369,7 @@ modules-names += \
tst-atfork4mod \ tst-atfork4mod \
tst-create1mod \ tst-create1mod \
tst-fini1mod \ tst-fini1mod \
tst-stack2-mod \
tst-tls4moda \ tst-tls4moda \
tst-tls4modb \ tst-tls4modb \
# modules-names # modules-names
@ -541,4 +543,11 @@ LDFLAGS-tst-create1 = -Wl,-export-dynamic
$(objpfx)tst-create1: $(shared-thread-library) $(objpfx)tst-create1: $(shared-thread-library)
$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so $(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so
$(objpfx)tst-stack2.out: $(objpfx)tst-stack2-mod.so
LDFLAGS-tst-stack2-mod.so = -Wl,-z,execstack
ifeq ($(have-no-error-execstack),yes)
LDFLAGS-tst-stack2-mod.so += -Wl,--no-error-execstack
endif
tst-stack2-ENV = GLIBC_TUNABLES=glibc.rtld.execstack=2
endif endif

View File

@ -0,0 +1,39 @@
/* Check if pthread_getattr_np works within modules with non-exectuble
stacks (BZ 32897).
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 <pthread.h>
bool init_result;
void
__attribute__ ((constructor))
init (void)
{
pthread_t me = pthread_self ();
pthread_attr_t attr;
init_result = pthread_getattr_np (me, &attr) == 0;
}
int
mod_func (void)
{
pthread_t me = pthread_self ();
pthread_attr_t attr;
return pthread_getattr_np (me, &attr);
}

View File

@ -0,0 +1,47 @@
/* Check if pthread_getattr_np works within modules with non-exectuble
stacks (BZ 32897).
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 <pthread.h>
#include <stdbool.h>
#include <support/xdlfcn.h>
#include <support/check.h>
static int
do_test (void)
{
{
pthread_t me = pthread_self ();
pthread_attr_t attr;
TEST_COMPARE (pthread_getattr_np (me, &attr), 0);
}
void *h = xdlopen ("tst-stack2-mod.so", RTLD_NOW);
bool *init_result = xdlsym (h, "init_result");
TEST_COMPARE (*init_result, true);
int (*mod_func)(void) = xdlsym (h, "mod_func");
TEST_COMPARE (mod_func (), 0);
xdlclose (h);
return 0;
}
#include <support/test-driver.c>

View File

@ -19,10 +19,10 @@
#include <ldsodefs.h> #include <ldsodefs.h>
int int
_dl_make_stack_executable (void **stack_endp) _dl_make_stack_executable (const void *stack_endp)
{ {
/* This gives us the highest/lowest page that needs to be changed. */ /* This gives us the highest/lowest page that needs to be changed. */
uintptr_t page = ((uintptr_t) *stack_endp uintptr_t page = ((uintptr_t) stack_endp
& -(intptr_t) GLRO(dl_pagesize)); & -(intptr_t) GLRO(dl_pagesize));
if (__mprotect ((void *) page, GLRO(dl_pagesize), if (__mprotect ((void *) page, GLRO(dl_pagesize),
@ -35,9 +35,6 @@ _dl_make_stack_executable (void **stack_endp)
) != 0) ) != 0)
return errno; return errno;
/* Clear the address. */
*stack_endp = NULL;
/* Remember that we changed the permission. */ /* Remember that we changed the permission. */
GL(dl_stack_flags) |= PF_X; GL(dl_stack_flags) |= PF_X;