From 13a46ff0f3f585762a26a444f03ba7fb9ebdbf6b Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Fri, 6 Dec 2024 14:37:50 -0300 Subject: [PATCH] elf: Parse gnu properties for static linked binaries So the static binary can opt-in of memory sealing. The aarch64 already does it for GCS, so refactor it to use __libc_process_gnu_attributes instead. Checked on x86_64-linux-gnu. --- csu/libc-start.c | 4 ++ elf/dl-support.c | 13 ++++++ sysdeps/generic/libc-prop.h | 44 ++++++++++++++++++++ sysdeps/unix/sysv/linux/aarch64/libc-start.h | 11 ----- sysdeps/x86/dl-prop.h | 4 +- 5 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 sysdeps/generic/libc-prop.h diff --git a/csu/libc-start.c b/csu/libc-start.c index 6f3d52e223..44fe5d5738 100644 --- a/csu/libc-start.c +++ b/csu/libc-start.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -276,6 +277,9 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), /* Perform IREL{,A} relocations. */ ARCH_SETUP_IREL (); + /* Process notes: PT_NOTE / PT_GNU_PROPERTY. */ + __libc_process_gnu_attributes (); + /* The stack guard goes into the TCB, so initialize it early. */ ARCH_SETUP_TLS (); diff --git a/elf/dl-support.c b/elf/dl-support.c index c7860f327a..d8f1dd8ee9 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -45,6 +45,7 @@ #include #include #include +#include extern char *__progname; char **_dl_argv = &__progname; /* This is checked for some error messages. */ @@ -330,6 +331,18 @@ _dl_non_dynamic_init (void) _dl_main_map.l_relro_size = ph->p_memsz; break; } + /* Process program headers again, but scan them backwards so + that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */ + for (const ElfW(Phdr) *ph = &_dl_phdr[_dl_phnum]; ph != _dl_phdr; --ph) + switch (ph[-1].p_type) + { + case PT_NOTE: + _dl_process_pt_note (&_dl_main_map, -1, &ph[-1]); + break; + case PT_GNU_PROPERTY: + _dl_process_pt_gnu_property (&_dl_main_map, -1, &ph[-1]); + break; + } if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X) && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0) diff --git a/sysdeps/generic/libc-prop.h b/sysdeps/generic/libc-prop.h new file mode 100644 index 0000000000..723575d29b --- /dev/null +++ b/sysdeps/generic/libc-prop.h @@ -0,0 +1,44 @@ +/* Support for GNU properties for static builds. Generic version. + 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 + . */ + +#ifndef _LIBC_PROP_H +#define _LIBC_PROP_H + +#include + +/* Called at the start of program execution to handle GNU attribute from + PT_NOTE / PT_GNU_PROPERTY. Must be on a top-level stack frame that does + not return. */ +static __always_inline void +__libc_process_gnu_attributes (void) +{ +# ifndef SHARED + struct link_map *main_map = _dl_get_dl_main_map (); + const ElfW(Phdr) *phdr = GL(dl_phdr); + const ElfW(Phdr) *ph; + for (ph = phdr; ph < phdr + GL(dl_phnum); ph++) + if (ph->p_type == PT_GNU_PROPERTY) + { + _dl_process_pt_gnu_property (main_map, -1, ph); + _rtld_main_check (main_map, _dl_argv[0]); + break; + } +# endif +} + +#endif diff --git a/sysdeps/unix/sysv/linux/aarch64/libc-start.h b/sysdeps/unix/sysv/linux/aarch64/libc-start.h index 75ae0a884a..64acbdb533 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc-start.h +++ b/sysdeps/unix/sysv/linux/aarch64/libc-start.h @@ -34,17 +34,6 @@ aarch64_libc_setup_tls (void) { __libc_setup_tls (); - struct link_map *main_map = _dl_get_dl_main_map (); - const ElfW(Phdr) *phdr = GL(dl_phdr); - const ElfW(Phdr) *ph; - for (ph = phdr; ph < phdr + GL(dl_phnum); ph++) - if (ph->p_type == PT_GNU_PROPERTY) - { - _dl_process_pt_gnu_property (main_map, -1, ph); - _rtld_main_check (main_map, _dl_argv[0]); - break; - } - if (GL(dl_aarch64_gcs) != 0) { int ret = INLINE_SYSCALL_CALL (prctl, PR_SET_SHADOW_STACK_STATUS, diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h index 8625751427..9a5e10821c 100644 --- a/sysdeps/x86/dl-prop.h +++ b/sysdeps/x86/dl-prop.h @@ -66,9 +66,11 @@ dl_isa_level_check (struct link_map *m, const char *program) static inline void __attribute__ ((always_inline)) _rtld_main_check (struct link_map *m, const char *program) { +#ifdef SAHRED dl_isa_level_check (m, program); -#if CET_ENABLED +# if CET_ENABLED _dl_cet_check (m, program); +# endif #endif }