1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-10-27 12:15:39 +03:00

elf: early conversion of elf p_flags to mprotect flags

This patch replaces _dl_stack_flags global variable by
_dl_stack_prot_flags.
The advantage is that any convertion from p_flags to final used mprotect
flags occurs at loading of p_flags. It avoids repeated spurious
convertions of _dl_stack_flags, for example in allocate_thread_stack.

This modification was suggested in:
  https://sourceware.org/pipermail/libc-alpha/2025-March/165537.html

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Cupertino Miranda
2025-08-22 11:37:00 +01:00
committed by Adhemerval Zanella
parent 921e251e8f
commit 3b2b88ccee
30 changed files with 104 additions and 102 deletions

View File

@@ -2167,7 +2167,7 @@ $(objpfx)execstack-default: $(first-word $(wildcard $(sysdirs:%=%/stackinfo.h)))
$(make-target-directory)
{ echo '#include <elf.h>'; \
echo '#include <stackinfo.h>'; \
echo '#if (DEFAULT_STACK_PERMS & PF_X) == 0'; \
echo '#if (DEFAULT_STACK_PROT_PERMS & PROT_EXEC) == 0'; \
echo '@@@execstack-no@@@'; \
echo '#else'; \
echo '@@@execstack-yes@@@'; \

View File

@@ -25,7 +25,7 @@ _dl_handle_execstack_tunable (void)
switch (TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL))
{
case stack_tunable_mode_disable:
if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X))
if ((__glibc_unlikely (GL(dl_stack_prot_flags)) & PROT_EXEC))
_dl_fatal_printf (
"Fatal glibc error: executable stack is not allowed\n");
break;

View File

@@ -1095,7 +1095,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* On most platforms presume that PT_GNU_STACK is absent and the stack is
* executable. Other platforms default to a nonexecutable stack and don't
* need PT_GNU_STACK to do so. */
unsigned int stack_flags = DEFAULT_STACK_PERMS;
unsigned int stack_flags = DEFAULT_STACK_PROT_PERMS;
{
/* Scan the program header table, collecting its load commands. */
@@ -1170,18 +1170,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
DIAG_POP_NEEDS_COMMENT;
/* Optimize a common case. */
#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
c->prot = (PF_TO_PROT
>> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
#else
c->prot = 0;
if (ph->p_flags & PF_R)
c->prot |= PROT_READ;
if (ph->p_flags & PF_W)
c->prot |= PROT_WRITE;
if (ph->p_flags & PF_X)
c->prot |= PROT_EXEC;
#endif
c->prot = pf_to_prot (ph->p_flags);
break;
case PT_TLS:
@@ -1218,7 +1207,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
break;
case PT_GNU_STACK:
stack_flags = ph->p_flags;
stack_flags = pf_to_prot (ph->p_flags);
break;
case PT_GNU_RELRO:
@@ -1318,7 +1307,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* Adjust the PT_PHDR value by the runtime load address. */
l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_prot_flags)) & PROT_EXEC))
{
/* The stack is presently not executable, but this module
requires that it be executable. Only tries to change the

View File

@@ -166,9 +166,8 @@ enum dso_sort_algorithm _dl_dso_sort_algo;
/* The value of the FPU control word the kernel will preset in hardware. */
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
/* Prevailing state of the stack. Generally this includes PF_X, indicating it's
* executable but this isn't true for all platforms. */
ElfW(Word) _dl_stack_flags = DEFAULT_STACK_PERMS;
/* Required flags used for stack allocation. */
int _dl_stack_prot_flags = DEFAULT_STACK_PROT_PERMS;
#if PTHREAD_IN_LIBC
list_t _dl_stack_used;
@@ -322,7 +321,7 @@ _dl_non_dynamic_init (void)
{
/* Check if the stack is nonexecutable. */
case PT_GNU_STACK:
_dl_stack_flags = ph->p_flags;
_dl_stack_prot_flags = pf_to_prot (ph->p_flags);
break;
case PT_GNU_RELRO:

View File

@@ -322,7 +322,7 @@ struct rtld_global _rtld_global =
#include <dl-procruntime.c>
/* Generally the default presumption without further information is an
* executable stack but this is not true for all platforms. */
._dl_stack_flags = DEFAULT_STACK_PERMS,
._dl_stack_prot_flags = DEFAULT_STACK_PROT_PERMS,
#ifdef _LIBC_REENTRANT
._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
@@ -1197,7 +1197,7 @@ rtld_setup_main_map (struct link_map *main_map)
break;
case PT_GNU_STACK:
GL(dl_stack_flags) = ph->p_flags;
GL(dl_stack_prot_flags) = pf_to_prot (ph->p_flags);
break;
case PT_GNU_RELRO:
@@ -1541,12 +1541,12 @@ dl_main (const ElfW(Phdr) *phdr,
--_dl_argc;
++_dl_argv;
/* The initialization of _dl_stack_flags done below assumes the
/* The initialization of dl_stack_prot_flags done below assumes the
executable's PT_GNU_STACK may have been honored by the kernel, and
so a PT_GNU_STACK with PF_X set means the stack started out with
execute permission. However, this is not really true if the
dynamic linker is the executable the kernel loaded. For this
case, we must reinitialize _dl_stack_flags to match the dynamic
case, we must reinitialize dl_stack_prot_flags to match the dynamic
linker itself. If the dynamic linker was built with a
PT_GNU_STACK, then the kernel may have loaded us with a
nonexecutable stack that we will have to make executable when we
@@ -1556,7 +1556,7 @@ dl_main (const ElfW(Phdr) *phdr,
for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
if (ph->p_type == PT_GNU_STACK)
{
GL(dl_stack_flags) = ph->p_flags;
GL(dl_stack_prot_flags) = pf_to_prot (ph->p_flags);
break;
}
@@ -1677,8 +1677,6 @@ dl_main (const ElfW(Phdr) *phdr,
bool has_interp = rtld_setup_main_map (main_map);
/* Handle this after PT_GNU_STACK parse, because it updates dl_stack_flags
if required. */
_dl_handle_execstack_tunable ();
/* If the current libname is different from the SONAME, add the

View File

@@ -4,7 +4,7 @@
# ifndef _ISOMAC
#include <stackinfo.h>
#include <elf.h>
#undef __alloca

View File

@@ -39,4 +39,38 @@
# error "stackinfo.h must define _STACK_GROWS_UP or _STACK_GROWS_DOWN!"
#endif
#include <sys/mman.h>
#include <link.h>
/* ELF uses the PF_x macros to specify the segment permissions, mmap
uses PROT_xxx. In most cases the three macros have the values 1, 2,
and 4 but not in a matching order. The following macros allows
converting from the PF_x values to PROT_xxx values. */
#define PF_TO_PROT \
((PROT_READ << (PF_R * 4)) \
| (PROT_WRITE << (PF_W * 4)) \
| (PROT_EXEC << (PF_X * 4)) \
| ((PROT_READ | PROT_WRITE) << ((PF_R | PF_W) * 4)) \
| ((PROT_READ | PROT_EXEC) << ((PF_R | PF_X) * 4)) \
| ((PROT_WRITE | PROT_EXEC) << (PF_W | PF_X) * 4) \
| ((PROT_READ | PROT_WRITE | PROT_EXEC) << ((PF_R | PF_W | PF_X) * 4)))
static inline int
pf_to_prot (ElfW(Word) value)
{
#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
return (PF_TO_PROT >> ((value & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
#else
ElfW(Word) ret = 0;
if (value & PF_R)
ret |= PROT_READ;
if (value & PF_W)
ret |= PROT_WRITE;
if (value & PF_X)
ret |= PROT_EXEC;
return ret;
#endif
}
#endif /* include/stackinfo.h */

View File

@@ -150,17 +150,11 @@ get_cached_stack (size_t *sizep, void **memp)
and fallback to ALLOCATE_GUARD_PROT_NONE if the madvise call fails. */
static int allocate_stack_mode = ALLOCATE_GUARD_MADV_GUARD;
static inline int stack_prot (void)
{
return (PROT_READ | PROT_WRITE
| ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
}
static void *
allocate_thread_stack (size_t size, size_t guardsize)
{
/* MADV_ADVISE_GUARD does not require an additional PROT_NONE mapping. */
int prot = stack_prot ();
int prot = GL(dl_stack_prot_flags);
if (atomic_load_relaxed (&allocate_stack_mode) == ALLOCATE_GUARD_PROT_NONE)
/* If a guard page is required, avoid committing memory by first allocate
@@ -216,7 +210,7 @@ setup_stack_prot (char *mem, size_t size, struct pthread *pd,
}
else
{
const int prot = stack_prot ();
const int prot = GL(dl_stack_prot_flags);
char *guardend = guard + guardsize;
#if _STACK_GROWS_DOWN
/* As defined at guard_position, for architectures with downward stack
@@ -294,7 +288,7 @@ adjust_stack_prot (char *mem, size_t size, const struct pthread *pd,
}
else if (pd->stack_mode == ALLOCATE_GUARD_PROT_NONE)
{
const int prot = stack_prot ();
const int prot = GL(dl_stack_prot_flags);
#if _STACK_GROWS_DOWN
return __mprotect (mem + guardsize, slacksize, prot) == 0;
#else

View File

@@ -64,11 +64,10 @@ support_stack_alloc (size_t size)
MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
-1);
/* Some architecture still requires executable stack for the signal return
trampoline, although PF_X could be overridden if PT_GNU_STACK is present.
However since glibc does not export such information with a proper ABI,
it uses the historical permissions. */
int prot = PROT_READ | PROT_WRITE
| (DEFAULT_STACK_PERMS & PF_X ? PROT_EXEC : 0);
trampoline, although PROT_EXEC could be overridden if PT_GNU_STACK is
present. However since glibc does not export such information with a
proper ABI, it uses the historical permissions. */
int prot = DEFAULT_STACK_PROT_PERMS;
xmprotect (alloc_base + guardsize, stacksize, prot);
memset (alloc_base + guardsize, 0xA5, stacksize);
return (struct support_stack) { alloc_base + guardsize, stacksize, guardsize };

View File

@@ -26,8 +26,8 @@
/* On Alpha the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -26,8 +26,8 @@
/* On Arm the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -171,19 +171,6 @@ dl_symbol_visibility_binds_local_p (const ElfW(Sym) *sym)
# define ELF_RTYPE_CLASS_COPY 0
#endif
/* ELF uses the PF_x macros to specify the segment permissions, mmap
uses PROT_xxx. In most cases the three macros have the values 1, 2,
and 3 but not in a matching order. The following macros allows
converting from the PF_x values to PROT_xxx values. */
#define PF_TO_PROT \
((PROT_READ << (PF_R * 4)) \
| (PROT_WRITE << (PF_W * 4)) \
| (PROT_EXEC << (PF_X * 4)) \
| ((PROT_READ | PROT_WRITE) << ((PF_R | PF_W) * 4)) \
| ((PROT_READ | PROT_EXEC) << ((PF_R | PF_X) * 4)) \
| ((PROT_WRITE | PROT_EXEC) << (PF_W | PF_X) * 4) \
| ((PROT_READ | PROT_WRITE | PROT_EXEC) << ((PF_R | PF_W | PF_X) * 4)))
/* The filename itself, or the main program name, if available. */
#define DSO_FILENAME(name) ((name)[0] ? (name) \
: (rtld_progname ?: "<main program>"))
@@ -416,7 +403,7 @@ struct rtld_global
#include <dl-procruntime.c>
/* Prevailing state of the stack, PF_X indicating it's executable. */
EXTERN ElfW(Word) _dl_stack_flags;
EXTERN int _dl_stack_prot_flags;
/* Flag signalling whether there are gaps in the module ID allocation. */
EXTERN bool _dl_tls_dtv_gaps;

View File

@@ -24,6 +24,6 @@
#include <elf.h>
#define _STACK_GROWS_DOWN 1
#define DEFAULT_STACK_PERMS (PF_R|PF_W)
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE)
#endif

View File

@@ -23,9 +23,9 @@
#include <elf.h>
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
/* On PA the stack grows up. */
#define _STACK_GROWS_UP 1

View File

@@ -26,9 +26,9 @@
/* On x86 the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
/* Access to the stack pointer. The macros are used in alloca_account
for which they need to act as barriers as well, hence the additional

View File

@@ -26,9 +26,9 @@
/* On m68k the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
is present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
/* Access to the stack pointer. */
#define stackinfo_get_sp() \

View File

@@ -34,7 +34,7 @@ __pthread_stack_alloc (void **stackaddr, size_t stacksize)
error_t err;
vm_prot_t prot = VM_PROT_READ | VM_PROT_WRITE;
if (GL(dl_stack_flags) & PF_X)
if (GL(dl_stack_prot_flags) & PROT_EXEC)
prot |= VM_PROT_EXECUTE;
err = __vm_map (__mach_task_self (), (vm_offset_t *) stackaddr,

View File

@@ -38,7 +38,7 @@ _dl_make_stack_executable (const void *stack_endp)
return errno;
/* Remember that we changed the permission. */
GL(dl_stack_flags) |= PF_X;
GL(dl_stack_prot_flags) |= PROT_EXEC;
return 0;
#else

View File

@@ -25,6 +25,7 @@
#include <pt-internal.h>
#include <pthreadP.h>
#include <stackinfo.h>
static void
reset_pthread_total (void)

View File

@@ -27,8 +27,8 @@
/* On MicroBlaze the stack grows down. */
# define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
# define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h. */

View File

@@ -26,8 +26,8 @@
/* On MIPS the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -27,8 +27,8 @@
/* On or1k the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R | PF_W | PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -26,7 +26,8 @@
/* On PPC the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* PF_X can be overridden if PT_GNU_STACK is present but is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* PROT_EXEC can be overridden if PT_GNU_STACK is present but is presumed
absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -26,8 +26,8 @@
/* On s390 the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -26,8 +26,8 @@
/* On SH the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -26,8 +26,8 @@
/* On sparc the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
#endif /* stackinfo.h */

View File

@@ -17,6 +17,7 @@
<https://www.gnu.org/licenses/>. */
#include <ldsodefs.h>
#include <stackinfo.h>
int
_dl_make_stack_executable (const void *stack_endp)
@@ -36,7 +37,7 @@ _dl_make_stack_executable (const void *stack_endp)
return errno;
/* Remember that we changed the permission. */
GL(dl_stack_flags) |= PF_X;
GL(dl_stack_prot_flags) |= PROT_EXEC;
return 0;
}

View File

@@ -19,6 +19,8 @@
#ifndef _MACHINE_SP_H
#define _MACHINE_SP_H
#include <stackinfo.h>
/* Return the current stack pointer. */
static inline uintptr_t
__thread_stack_pointer (void)

View File

@@ -348,9 +348,6 @@ __spawnix (int *pid, const char *file,
return errno;
}
int prot = (PROT_READ | PROT_WRITE
| ((GL (dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
/* Add a slack area for child's stack. */
size_t argv_size = (argc * sizeof (void *)) + 512;
/* We need at least a few pages in case the compiler's stack checking is
@@ -361,7 +358,7 @@ __spawnix (int *pid, const char *file,
where it might use about 1k extra stack space). */
argv_size += (32 * 1024);
size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
void *stack = __mmap (NULL, stack_size, prot,
void *stack = __mmap (NULL, stack_size, GL (dl_stack_prot_flags),
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (__glibc_unlikely (stack == MAP_FAILED))
return errno;

View File

@@ -32,9 +32,9 @@
/* On x86_64 the stack grows down. */
#define _STACK_GROWS_DOWN 1
/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
* present, but it is presumed absent. */
#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
/* Default to an executable stack. PROT_EXEC can be overridden if PT_GNU_STACK
* is present, but it is presumed absent. */
#define DEFAULT_STACK_PROT_PERMS (PROT_READ|PROT_WRITE|PROT_EXEC)
/* Access to the stack pointer. The macros are used in alloca_account
for which they need to act as barriers as well, hence the additional