[v6,2/9] elf: Parse gnu properties for statically linked binaries
Checks
Commit Message
It allows static binary to 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
Comments
On Tue, Mar 11, 2025 at 02:09:49PM -0300, Adhemerval Zanella wrote:
> It allows static binary to 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
>
> + /* Process program headers again, but scan them backwards so
> + that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */
Why do we need to process headers again?
> + 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
> + <https://www.gnu.org/licenses/>. */
> +
> +#ifndef _LIBC_PROP_H
> +#define _LIBC_PROP_H
> +
> +#include <dl-prop.h>
> +
> +/* 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)
I think that "__libc_process_gnu_properties" may be a better name. There may
be a need in the future to process build attributes [1] and the name of the
function above might be confusing.
[1] https://github.com/smithp35/abi-aa/blob/build-attributes/buildattr64/buildattr64.rst
Kind regardsm
Yury
@@ -36,6 +36,7 @@
#include <stdbool.h>
#include <elf-initfini.h>
#include <shlib-compat.h>
+#include <libc-prop.h>
#include <elf/dl-tunables.h>
@@ -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 ();
@@ -45,6 +45,7 @@
#include <array_length.h>
#include <dl-symbol-redir-ifunc.h>
#include <dl-tunables.h>
+#include <dl-prop.h>
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)
new file mode 100644
@@ -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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC_PROP_H
+#define _LIBC_PROP_H
+
+#include <dl-prop.h>
+
+/* 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
@@ -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,
@@ -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
}