]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/dl-support.c
test-container: Fix "unused code" warnings on HURD
[thirdparty/glibc.git] / elf / dl-support.c
index 81e71720c670a13ed1dee468caf01eed7d5f6a87..153dd57ad2a4746fefe30294ed3fd90e9a9ce57e 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for dynamic linking code in static libc.
-   Copyright (C) 1996-2012 Free Software Foundation, Inc.
+   Copyright (C) 1996-2022 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
 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
+   <https://www.gnu.org/licenses/>.  */
 
 /* This file defines some things that for the dynamic linker are defined in
    rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking.  */
 
+#include <string.h>
+/* Mark symbols hidden in static PIE for early self relocation to work.
+   Note: string.h may have ifuncs which cannot be hidden on i686.  */
+#if BUILD_PIE_DEFAULT
+# pragma GCC visibility push(hidden)
+#endif
 #include <errno.h>
 #include <libintl.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/param.h>
+#include <stdint.h>
 #include <ldsodefs.h>
 #include <dl-machine.h>
-#include <bits/libc-lock.h>
+#include <libc-lock.h>
 #include <dl-cache.h>
 #include <dl-librecon.h>
 #include <dl-procinfo.h>
 #include <unsecvars.h>
 #include <hp-timing.h>
 #include <stackinfo.h>
+#include <dl-vdso.h>
+#include <dl-vdso-setup.h>
+#include <dl-auxv.h>
+#include <dl-find_object.h>
+#include <array_length.h>
 
 extern char *__progname;
 char **_dl_argv = &__progname; /* This is checked for some error messages.  */
@@ -43,7 +55,6 @@ size_t _dl_platformlen;
 
 int _dl_debug_mask;
 int _dl_lazy;
-ElfW(Addr) _dl_use_load_bias = -2;
 int _dl_dynamic_weak;
 
 /* If nonzero print warnings about problematic situations.  */
@@ -69,17 +80,52 @@ const char *_dl_origin_path;
 /* Nonzero if runtime lookup should not update the .got/.plt.  */
 int _dl_bind_not;
 
+/* A dummy link map for the executable, used by dlopen to access the global
+   scope.  We don't export any symbols ourselves, so this can be minimal.  */
+static struct link_map _dl_main_map =
+  {
+    .l_name = (char *) "",
+    .l_real = &_dl_main_map,
+    .l_ns = LM_ID_BASE,
+    .l_libname = &(struct libname_list) { .name = "", .dont_free = 1 },
+    .l_searchlist =
+      {
+       .r_list = &(struct link_map *) { &_dl_main_map },
+       .r_nlist = 1,
+      },
+    .l_symbolic_searchlist = { .r_list = &(struct link_map *) { NULL } },
+    .l_type = lt_executable,
+    .l_scope_mem = { &_dl_main_map.l_searchlist },
+    .l_scope_max = (sizeof (_dl_main_map.l_scope_mem)
+                   / sizeof (_dl_main_map.l_scope_mem[0])),
+    .l_scope = _dl_main_map.l_scope_mem,
+    .l_local_scope = { &_dl_main_map.l_searchlist },
+    .l_used = 1,
+    .l_tls_offset = NO_TLS_OFFSET,
+    .l_serial = 1,
+  };
+
 /* Namespace information.  */
-struct link_namespaces _dl_ns[DL_NNS];
-size_t _dl_nns;
+struct link_namespaces _dl_ns[DL_NNS] =
+  {
+    [LM_ID_BASE] =
+      {
+       ._ns_loaded = &_dl_main_map,
+       ._ns_nloaded = 1,
+       ._ns_main_searchlist = &_dl_main_map.l_searchlist,
+      }
+  };
+size_t _dl_nns = 1;
 
 /* Incremented whenever something may have been added to dl_loaded. */
-unsigned long long _dl_load_adds;
+unsigned long long _dl_load_adds = 1;
 
-/* Fake scope.  In dynamically linked binaries this is the scope of the
-   main application but here we don't have something like this.  So
-   create a fake scope containing nothing.  */
-struct r_scope_elem _dl_initial_searchlist;
+/* Fake scope of the main application.  */
+struct r_scope_elem _dl_initial_searchlist =
+  {
+    .r_list = &(struct link_map *) { &_dl_main_map },
+    .r_nlist = 1,
+  };
 
 #ifndef HAVE_INLINED_SYSCALLS
 /* Nonzero during startup.  */
@@ -90,23 +136,13 @@ int _dl_starting_up = 1;
 void *_dl_random;
 
 /* Get architecture specific initializer.  */
+#include <dl-procruntime.c>
 #include <dl-procinfo.c>
 
-/* We expect less than a second for relocation.  */
-#ifdef HP_SMALL_TIMING_AVAIL
-# undef HP_TIMING_AVAIL
-# define HP_TIMING_AVAIL HP_SMALL_TIMING_AVAIL
-#endif
-
-/* Initial value of the CPU clock.  */
-#ifndef HP_TIMING_NONAVAIL
-hp_timing_t _dl_cpuclock_offset;
-#endif
-
-void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
-
 size_t _dl_pagesize = EXEC_PAGESIZE;
 
+size_t _dl_minsigstacksize = CONSTANT_MINSIGSTKSZ;
+
 int _dl_inhibit_cache;
 
 unsigned int _dl_osversion;
@@ -126,39 +162,52 @@ int _dl_debug_fd = STDERR_FILENO;
 int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
 
 ElfW(auxv_t) *_dl_auxv;
-ElfW(Phdr) *_dl_phdr;
+const ElfW(Phdr) *_dl_phdr;
 size_t _dl_phnum;
-uint64_t _dl_hwcap __attribute__ ((nocommon));
+uint64_t _dl_hwcap;
+uint64_t _dl_hwcap2;
 
+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;
+
+#if !HAVE_TUNABLES
 /* This is not initialized to HWCAP_IMPORTANT, matching the definition
    of _dl_important_hwcaps, below, where no hwcap strings are ever
    used.  This mask is still used to mediate the lookups in the cache
    file.  Since there is no way to set this nonzero (we don't grok the
    LD_HWCAP_MASK environment variable here), there is no real point in
    setting _dl_hwcap nonzero below, but we do anyway.  */
-uint64_t _dl_hwcap_mask __attribute__ ((nocommon));
+uint64_t _dl_hwcap_mask;
+#endif
 
 /* 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;
 
+#if PTHREAD_IN_LIBC
+list_t _dl_stack_used;
+list_t _dl_stack_user;
+list_t _dl_stack_cache;
+size_t _dl_stack_cache_actsize;
+uintptr_t _dl_in_flight_stack;
+int _dl_stack_cache_lock;
+#else
 /* If loading a shared object requires that we make the stack executable
    when it was not, we do it by calling this function.
    It returns an errno code or zero on success.  */
-int (*_dl_make_stack_executable_hook) (void **) internal_function
-  = _dl_make_stack_executable;
-
-
-/* Function in libpthread to wait for termination of lookups.  */
-void (*_dl_wait_lookup_done) (void);
-
+int (*_dl_make_stack_executable_hook) (void **) = _dl_make_stack_executable;
+void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
+#endif
 struct dl_scope_free_list *_dl_scope_free_list;
 
 #ifdef NEED_DL_SYSINFO
-/* Needed for improved syscall handling on at least x86/Linux.  */
-uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;
+/* Needed for improved syscall handling on at least x86/Linux.  NB: Don't
+   initialize it here to avoid RELATIVE relocation in static PIE.  */
+uintptr_t _dl_sysinfo;
 #endif
-#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
+#ifdef NEED_DL_SYSINFO_DSO
 /* Address of the ELF headers in the vsyscall page.  */
 const ElfW(Ehdr) *_dl_sysinfo_dso;
 
@@ -167,6 +216,8 @@ struct link_map *_dl_sysinfo_map;
 # include "get-dynamic-info.h"
 #endif
 #include "setup-vdso.h"
+/* Define the vDSO function pointers.  */
+#include <dl-vdso-setup.c>
 
 /* During the program run we must not modify the global data of
    loaded shared object simultanously in two threads.  Therefore we
@@ -180,94 +231,45 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock)
    list of loaded objects while an object is added to or removed from
    that list.  */
 __rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
+  /* This lock protects global and module specific TLS related data.
+     E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+     GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+     accessed and when TLS related relocations are processed for a
+     module.  It was introduced to keep pthread_create accessing TLS
+     state that is being set up.  */
+__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
 
 
 #ifdef HAVE_AUX_VECTOR
+#include <dl-parse_auxv.h>
+
 int _dl_clktck;
 
 void
-internal_function
 _dl_aux_init (ElfW(auxv_t) *av)
 {
-  int seen = 0;
-  uid_t uid = 0;
-  gid_t gid = 0;
-
-  _dl_auxv = av;
-  for (; av->a_type != AT_NULL; ++av)
-    switch (av->a_type)
-      {
-      case AT_PAGESZ:
-       GLRO(dl_pagesize) = av->a_un.a_val;
-       break;
-      case AT_CLKTCK:
-       GLRO(dl_clktck) = av->a_un.a_val;
-       break;
-      case AT_PHDR:
-       GL(dl_phdr) = (void *) av->a_un.a_val;
-       break;
-      case AT_PHNUM:
-       GL(dl_phnum) = av->a_un.a_val;
-       break;
-      case AT_HWCAP:
-       GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
-       break;
 #ifdef NEED_DL_SYSINFO
-      case AT_SYSINFO:
-       GL(dl_sysinfo) = av->a_un.a_val;
-       break;
-#endif
-#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
-      case AT_SYSINFO_EHDR:
-       GL(dl_sysinfo_dso) = (void *) av->a_un.a_val;
-       break;
+  /* NB: Avoid RELATIVE relocation in static PIE.  */
+  GL(dl_sysinfo) = DL_SYSINFO_DEFAULT;
 #endif
-      case AT_UID:
-       uid ^= av->a_un.a_val;
-       seen |= 1;
-       break;
-      case AT_EUID:
-       uid ^= av->a_un.a_val;
-       seen |= 2;
-       break;
-      case AT_GID:
-       gid ^= av->a_un.a_val;
-       seen |= 4;
-       break;
-      case AT_EGID:
-       gid ^= av->a_un.a_val;
-       seen |= 8;
-       break;
-      case AT_SECURE:
-       seen = -1;
-       __libc_enable_secure = av->a_un.a_val;
-       __libc_enable_secure_decided = 1;
-       break;
-      case AT_RANDOM:
-       _dl_random = (void *) av->a_un.a_val;
-       break;
-# ifdef DL_PLATFORM_AUXV
-      DL_PLATFORM_AUXV
-# endif
-      }
-  if (seen == 0xf)
-    {
-      __libc_enable_secure = uid != 0 || gid != 0;
-      __libc_enable_secure_decided = 1;
-    }
+
+  _dl_auxv = av;
+  dl_parse_auxv_t auxv_values;
+  /* Use an explicit initialization loop here because memset may not
+     be available yet.  */
+  for (int i = 0; i < array_length (auxv_values); ++i)
+    auxv_values[i] = 0;
+  _dl_parse_auxv (av, auxv_values);
 }
 #endif
 
 
 void
-internal_function
 _dl_non_dynamic_init (void)
 {
-  if (HP_TIMING_AVAIL)
-    HP_TIMING_NOW (_dl_cpuclock_offset);
-
-  if (!_dl_pagesize)
-    _dl_pagesize = __getpagesize ();
+  _dl_main_map.l_origin = _dl_get_origin ();
+  _dl_main_map.l_phdr = GL(dl_phdr);
+  _dl_main_map.l_phnum = GL(dl_phnum);
 
   _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
 
@@ -275,9 +277,15 @@ _dl_non_dynamic_init (void)
      so they can influence _dl_init_paths.  */
   setup_vdso (NULL, NULL);
 
+  /* With vDSO setup we can initialize the function pointers.  */
+  setup_vdso_pointers ();
+
   /* Initialize the data structures for the search paths for shared
      objects.  */
-  _dl_init_paths (getenv ("LD_LIBRARY_PATH"));
+  _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH",
+                 /* No glibc-hwcaps selection support in statically
+                    linked binaries.  */
+                 NULL, NULL);
 
   /* Remember the last search directory added at startup.  */
   _dl_init_all_dirs = GL(dl_all_dirs);
@@ -309,8 +317,10 @@ _dl_non_dynamic_init (void)
          cp = (const char *) __rawmemchr (cp, '\0') + 1;
        }
 
+#if !HAVE_TUNABLES
       if (__access ("/etc/suid-debug", F_OK) != 0)
        __unsetenv ("MALLOC_CHECK_");
+#endif
     }
 
 #ifdef DL_PLATFORM_INIT
@@ -325,16 +335,47 @@ _dl_non_dynamic_init (void)
   if (_dl_platform != NULL)
     _dl_platformlen = strlen (_dl_platform);
 
-  /* Scan for a program header telling us the stack is nonexecutable.  */
   if (_dl_phdr != NULL)
-    for (uint_fast16_t i = 0; i < _dl_phnum; ++i)
-      if (_dl_phdr[i].p_type == PT_GNU_STACK)
+    for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph)
+      switch (ph->p_type)
        {
-         _dl_stack_flags = _dl_phdr[i].p_flags;
+       /* Check if the stack is nonexecutable.  */
+       case PT_GNU_STACK:
+         _dl_stack_flags = ph->p_flags;
+         break;
+
+       case PT_GNU_RELRO:
+         _dl_main_map.l_relro_addr = ph->p_vaddr;
+         _dl_main_map.l_relro_size = ph->p_memsz;
          break;
        }
+
+  call_function_static_weak (_dl_find_object_init);
+
+  /* Setup relro on the binary itself.  */
+  if (_dl_main_map.l_relro_size != 0)
+    _dl_protect_relro (&_dl_main_map);
 }
 
 #ifdef DL_SYSINFO_IMPLEMENTATION
 DL_SYSINFO_IMPLEMENTATION
 #endif
+
+#if ENABLE_STATIC_PIE
+/* Since relocation to hidden _dl_main_map causes relocation overflow on
+   aarch64, a function is used to get the address of _dl_main_map.  */
+
+struct link_map *
+_dl_get_dl_main_map (void)
+{
+  return &_dl_main_map;
+}
+#endif
+
+/* This is used by _dl_runtime_profile, not used on static code.  */
+void
+DL_ARCH_FIXUP_ATTRIBUTE
+_dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
+                  const void *inregs, void *outregs)
+{
+}