elf: Fix elf_get_dynamic_info definition

Before to 490e6c62aa ('elf: Avoid nested functions in the loader
[BZ #27220]'), elf_get_dynamic_info() was defined twice on rtld.c: on
the first dynamic-link.h include and later within _dl_start().  The
former definition did not define DONT_USE_BOOTSTRAP_MAP and it is used
on setup_vdso() (since it is a global definition), while the former does
define DONT_USE_BOOTSTRAP_MAP and it is used on loader self-relocation.

With the commit change, the function is now included and defined once
instead of defined as a nested function.  So rtld.c defines without
defining RTLD_BOOTSTRAP and it brokes at least powerpc32.

This patch fixes by moving the get-dynamic-info.h include out of
dynamic-link.h, which then the caller can corirectly set the expected
semantic by defining STATIC_PIE_BOOTSTRAP, RTLD_BOOTSTRAP, and/or
RESOLVE_MAP.

It also required to enable some asserts only for the loader bootstrap
to avoid issues when called from setup_vdso().

As a side note, this is another issues with nested functions: it is
not clear from pre-processed output (-E -dD) how the function will
be build and its semantic (since nested function will be local and
extra C defines may change it).

I checked on x86_64-linux-gnu (w/o --enable-static-pie),
i686-linux-gnu, powerpc64-linux-gnu, powerpc-linux-gnu-power4,
aarch64-linux-gnu, arm-linux-gnu, sparc64-linux-gnu, and
s390x-linux-gnu.

Reviewed-by: Fangrui Song <maskray@google.com>
This commit is contained in:
Adhemerval Zanella 2021-10-11 16:01:49 -03:00
parent de82cb0da4
commit 4af6982e4c
11 changed files with 27 additions and 17 deletions

View file

@ -16,6 +16,7 @@
License along with the GNU C Library; see the file COPYING.LIB. If License along with the GNU C Library; see the file COPYING.LIB. If
not, see <https://www.gnu.org/licenses/>. */ not, see <https://www.gnu.org/licenses/>. */
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <libintl.h> #include <libintl.h>
#include <stdlib.h> #include <stdlib.h>

View file

@ -58,6 +58,7 @@ struct filebuf
}; };
#include "dynamic-link.h" #include "dynamic-link.h"
#include "get-dynamic-info.h"
#include <abi-tag.h> #include <abi-tag.h>
#include <stackinfo.h> #include <stackinfo.h>
#include <sysdep.h> #include <sysdep.h>
@ -1297,7 +1298,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
else else
l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr); l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
elf_get_dynamic_info (l); elf_get_dynamic_info (l, false);
/* Make sure we are not dlopen'ing an object that has the /* Make sure we are not dlopen'ing an object that has the
DF_1_NOOPEN flag set, or a PIE object. */ DF_1_NOOPEN flag set, or a PIE object. */

View file

@ -28,6 +28,7 @@
#define STATIC_PIE_BOOTSTRAP #define STATIC_PIE_BOOTSTRAP
#define RESOLVE_MAP(map, scope, sym, version, flags) map #define RESOLVE_MAP(map, scope, sym, version, flags) map
#include "dynamic-link.h" #include "dynamic-link.h"
#include "get-dynamic-info.h"
/* Relocate static executable with PIE. */ /* Relocate static executable with PIE. */
@ -51,7 +52,7 @@ _dl_relocate_static_pie (void)
break; break;
} }
elf_get_dynamic_info (main_map); elf_get_dynamic_info (main_map, false);
# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
ELF_MACHINE_BEFORE_RTLD_RELOC (main_map, main_map->l_info); ELF_MACHINE_BEFORE_RTLD_RELOC (main_map, main_map->l_info);

View file

@ -19,6 +19,7 @@
#define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */ #define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */
#include <alloca.h> #include <alloca.h>
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/param.h> #include <sys/param.h>

View file

@ -93,7 +93,6 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
#include <dl-machine.h> #include <dl-machine.h>
#include "get-dynamic-info.h"
#ifdef RESOLVE_MAP #ifdef RESOLVE_MAP

View file

@ -25,7 +25,7 @@
#include <libc-diag.h> #include <libc-diag.h>
static inline void __attribute__ ((unused, always_inline)) static inline void __attribute__ ((unused, always_inline))
elf_get_dynamic_info (struct link_map *l) elf_get_dynamic_info (struct link_map *l, bool check)
{ {
#if __ELF_NATIVE_CLASS == 32 #if __ELF_NATIVE_CLASS == 32
typedef Elf32_Word d_tag_utype; typedef Elf32_Word d_tag_utype;
@ -112,16 +112,19 @@ elf_get_dynamic_info (struct link_map *l)
assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
#endif #endif
#ifdef RTLD_BOOTSTRAP #ifdef RTLD_BOOTSTRAP
/* Only the bind now flags are allowed. */ if (check)
assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL {
|| (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0); /* Only the bind now flags are allowed. */
/* Flags must not be set for ld.so. */ assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL
assert (info[DT_FLAGS] == NULL || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0);
|| (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0); /* Flags must not be set for ld.so. */
#endif assert (info[DT_FLAGS] == NULL
#if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
assert (info[DT_RUNPATH] == NULL); # ifdef STATIC_PIE_BOOTSTRAP
assert (info[DT_RPATH] == NULL); assert (info[DT_RUNPATH] == NULL);
assert (info[DT_RPATH] == NULL);
# endif
}
#else #else
if (info[DT_FLAGS] != NULL) if (info[DT_FLAGS] != NULL)
{ {

View file

@ -513,6 +513,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
is trivial: always the map of ld.so itself. */ is trivial: always the map of ld.so itself. */
#define RTLD_BOOTSTRAP #define RTLD_BOOTSTRAP
#define RESOLVE_MAP(map, scope, sym, version, flags) map #define RESOLVE_MAP(map, scope, sym, version, flags) map
#include "get-dynamic-info.h"
#include "dynamic-link.h" #include "dynamic-link.h"
static ElfW(Addr) __attribute_used__ static ElfW(Addr) __attribute_used__
@ -547,7 +548,7 @@ _dl_start (void *arg)
/* Read our own dynamic section and fill in the info array. */ /* Read our own dynamic section and fill in the info array. */
bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
elf_get_dynamic_info (&bootstrap_map); elf_get_dynamic_info (&bootstrap_map, true);
#if NO_TLS_OFFSET != 0 #if NO_TLS_OFFSET != 0
bootstrap_map.l_tls_offset = NO_TLS_OFFSET; bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
@ -1615,7 +1616,7 @@ dl_main (const ElfW(Phdr) *phdr,
if (! rtld_is_main) if (! rtld_is_main)
{ {
/* Extract the contents of the dynamic section for easy access. */ /* Extract the contents of the dynamic section for easy access. */
elf_get_dynamic_info (main_map); elf_get_dynamic_info (main_map, false);
/* If the main map is libc.so, update the base namespace to /* If the main map is libc.so, update the base namespace to
refer to this map. If libc.so is loaded later, this happens refer to this map. If libc.so is loaded later, this happens

View file

@ -64,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
l->l_map_end += l->l_addr; l->l_map_end += l->l_addr;
l->l_text_end += l->l_addr; l->l_text_end += l->l_addr;
l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
elf_get_dynamic_info (l); elf_get_dynamic_info (l, false);
_dl_setup_hash (l); _dl_setup_hash (l);
l->l_relocated = 1; l->l_relocated = 1;

View file

@ -21,6 +21,7 @@
#define ELF_MACHINE_NAME "ARM" #define ELF_MACHINE_NAME "ARM"
#include <assert.h>
#include <sys/param.h> #include <sys/param.h>
#include <tls.h> #include <tls.h>
#include <dl-tlsdesc.h> #include <dl-tlsdesc.h>

View file

@ -21,6 +21,7 @@
#define ELF_MACHINE_NAME "i386" #define ELF_MACHINE_NAME "i386"
#include <assert.h>
#include <sys/param.h> #include <sys/param.h>
#include <sysdep.h> #include <sysdep.h>
#include <tls.h> #include <tls.h>

View file

@ -21,6 +21,7 @@
#define ELF_MACHINE_NAME "x86_64" #define ELF_MACHINE_NAME "x86_64"
#include <assert.h>
#include <sys/param.h> #include <sys/param.h>
#include <sysdep.h> #include <sysdep.h>
#include <tls.h> #include <tls.h>