]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/rtld.c
install.texi: Build was tested with binutils 2.41 (just released)
[thirdparty/glibc.git] / elf / rtld.c
index 3b2e05bf4c3ae129063cf3f54b14dbdaaaa23064..a91e2a44710d068c813e0a3a13254c955ce216a7 100644 (file)
@@ -1,5 +1,5 @@
 /* Run time dynamic linker.
-   Copyright (C) 1995-2022 Free Software Foundation, Inc.
+   Copyright (C) 1995-2023 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
@@ -32,7 +32,6 @@
 #include <fpu_control.h>
 #include <hp-timing.h>
 #include <libc-lock.h>
-#include <dl-librecon.h>
 #include <unsecvars.h>
 #include <dl-cache.h>
 #include <dl-osinfo.h>
@@ -53,6 +52,7 @@
 #include <dl-execve.h>
 #include <dl-find_object.h>
 #include <dl-audit-check.h>
+#include <dl-call_tls_init_tp.h>
 
 #include <assert.h>
 
@@ -157,16 +157,8 @@ static void dl_main_state_init (struct dl_main_state *state);
 extern char **_environ attribute_hidden;
 static void process_envvars (struct dl_main_state *state);
 
-#ifdef DL_ARGV_NOT_RELRO
-int _dl_argc attribute_hidden;
-char **_dl_argv = NULL;
-/* Nonzero if we were run directly.  */
-unsigned int _dl_skip_args attribute_hidden;
-#else
 int _dl_argc attribute_relro attribute_hidden;
 char **_dl_argv attribute_relro = NULL;
-unsigned int _dl_skip_args attribute_relro attribute_hidden;
-#endif
 rtld_hidden_data_def (_dl_argv)
 
 #ifndef THREAD_SET_STACK_GUARD
@@ -365,10 +357,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_sysinfo = DL_SYSINFO_DEFAULT,
 #endif
     ._dl_debug_fd = STDERR_FILENO,
-    ._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID,
-#if !HAVE_TUNABLES
-    ._dl_hwcap_mask = HWCAP_IMPORTANT,
-#endif
     ._dl_lazy = 1,
     ._dl_fpu_control = _FPU_DEFAULT,
     ._dl_pagesize = EXEC_PAGESIZE,
@@ -380,13 +368,10 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_lookup_symbol_x = _dl_lookup_symbol_x,
     ._dl_open = _dl_open,
     ._dl_close = _dl_close,
-    ._dl_catch_error = _rtld_catch_error,
+    ._dl_catch_error = _dl_catch_error,
     ._dl_error_free = _dl_error_free,
     ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
     ._dl_libc_freeres = __rtld_libc_freeres,
-#ifdef HAVE_DL_DISCOVER_OSVERSION
-    ._dl_discover_osversion = _dl_discover_osversion
-#endif
   };
 /* If we would use strong_alias here the compiler would see a
    non-hidden definition.  This would undo the effect of the previous
@@ -469,7 +454,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
   ElfW(Addr) start_addr;
 
   /* Do not use an initializer for these members because it would
-     intefere with __rtld_static_init.  */
+     interfere with __rtld_static_init.  */
   GLRO (dl_find_object) = &_dl_find_object;
 
   /* If it hasn't happen yet record the startup time.  */
@@ -743,7 +728,7 @@ match_version (const char *string, struct link_map *map)
   return 0;
 }
 
-static bool tls_init_tp_called;
+bool __rtld_tls_init_tp_called;
 
 static void *
 init_tls (size_t naudit)
@@ -809,11 +794,8 @@ cannot allocate TLS data structures for initial thread\n");
   GL(dl_initial_dtv) = GET_DTV (tcbp);
 
   /* And finally install it for the main thread.  */
-  const char *lossage = TLS_INIT_TP (tcbp);
-  if (__glibc_unlikely (lossage != NULL))
-    _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
-  __tls_init_tp ();
-  tls_init_tp_called = true;
+  call_tls_init_tp (tcbp);
+  __rtld_tls_init_tp_called = true;
 
   return tcbp;
 }
@@ -1039,7 +1021,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
        newp->fptr[cnt] = NULL;
       ++cnt;
 
-      cp = rawmemchr (cp, '\0') + 1;
+      cp = strchr (cp, '\0') + 1;
     }
   while (*cp != '\0');
   assert (cnt == naudit_ifaces);
@@ -1085,7 +1067,7 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
     }
 }
 
-/* Check if the executable is not actualy dynamically linked, and
+/* Check if the executable is not actually dynamically linked, and
    invoke it directly in that case.  */
 static void
 rtld_chain_load (struct link_map *main_map, char *argv0)
@@ -1185,7 +1167,7 @@ rtld_setup_main_map (struct link_map *main_map)
        /* _dl_rtld_libname.next = NULL;        Already zero.  */
        GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
 
-       /* Ordinarilly, we would get additional names for the loader from
+       /* Ordinarily, we would get additional names for the loader from
           our DT_SONAME.  This can't happen if we were actually linked as
           a static executable (detect this case when we have no DYNAMIC).
           If so, assume the filename component of the interpreter path to
@@ -1306,6 +1288,62 @@ rtld_setup_main_map (struct link_map *main_map)
   return has_interp;
 }
 
+/* Adjusts the contents of the stack and related globals for the user
+   entry point.  The ld.so processed skip_args arguments and bumped
+   _dl_argv and _dl_argc accordingly.  Those arguments are removed from
+   argv here.  */
+static void
+_dl_start_args_adjust (int skip_args)
+{
+  void **sp = (void **) (_dl_argv - skip_args - 1);
+  void **p = sp + skip_args;
+
+  if (skip_args == 0)
+    return;
+
+  /* Sanity check.  */
+  intptr_t argc __attribute__ ((unused)) = (intptr_t) sp[0] - skip_args;
+  assert (argc == _dl_argc);
+
+  /* Adjust argc on stack.  */
+  sp[0] = (void *) (intptr_t) _dl_argc;
+
+  /* Update globals in rtld.  */
+  _dl_argv -= skip_args;
+  _environ -= skip_args;
+
+  /* Shuffle argv down.  */
+  do
+    *++sp = *++p;
+  while (*p != NULL);
+
+  assert (_environ == (char **) (sp + 1));
+
+  /* Shuffle envp down.  */
+  do
+    *++sp = *++p;
+  while (*p != NULL);
+
+#ifdef HAVE_AUX_VECTOR
+  void **auxv = (void **) GLRO(dl_auxv) - skip_args;
+  GLRO(dl_auxv) = (ElfW(auxv_t) *) auxv; /* Aliasing violation.  */
+  assert (auxv == sp + 1);
+
+  /* Shuffle auxv down. */
+  ElfW(auxv_t) ax;
+  char *oldp = (char *) (p + 1);
+  char *newp = (char *) (sp + 1);
+  do
+    {
+      memcpy (&ax, oldp, sizeof (ax));
+      memcpy (newp, &ax, sizeof (ax));
+      oldp += sizeof (ax);
+      newp += sizeof (ax);
+    }
+  while (ax.a_type != AT_NULL);
+#endif
+}
+
 static void
 dl_main (const ElfW(Phdr) *phdr,
         ElfW(Word) phnum,
@@ -1359,6 +1397,7 @@ dl_main (const ElfW(Phdr) *phdr,
       rtld_is_main = true;
 
       char *argv0 = NULL;
+      char **orig_argv = _dl_argv;
 
       /* Note the place where the dynamic linker actually came from.  */
       GL(dl_rtld_map).l_name = rtld_progname;
@@ -1373,7 +1412,6 @@ dl_main (const ElfW(Phdr) *phdr,
                GLRO(dl_lazy) = -1;
              }
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
@@ -1382,14 +1420,12 @@ dl_main (const ElfW(Phdr) *phdr,
            if (state.mode != rtld_mode_help)
              state.mode = rtld_mode_verify;
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
        else if (! strcmp (_dl_argv[1], "--inhibit-cache"))
          {
            GLRO(dl_inhibit_cache) = 1;
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
@@ -1399,7 +1435,6 @@ dl_main (const ElfW(Phdr) *phdr,
            state.library_path = _dl_argv[2];
            state.library_path_source = "--library-path";
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1408,7 +1443,6 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            GLRO(dl_inhibit_rpath) = _dl_argv[2];
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1416,14 +1450,12 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            audit_list_add_string (&state.audit_list, _dl_argv[2]);
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
        else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2)
          {
            state.preloadarg = _dl_argv[2];
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1431,7 +1463,6 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            argv0 = _dl_argv[2];
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1439,7 +1470,6 @@ dl_main (const ElfW(Phdr) *phdr,
                 && _dl_argc > 2)
          {
            state.glibc_hwcaps_prepend = _dl_argv[2];
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1447,25 +1477,20 @@ dl_main (const ElfW(Phdr) *phdr,
                 && _dl_argc > 2)
          {
            state.glibc_hwcaps_mask = _dl_argv[2];
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
-#if HAVE_TUNABLES
        else if (! strcmp (_dl_argv[1], "--list-tunables"))
          {
            state.mode = rtld_mode_list_tunables;
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
-#endif
        else if (! strcmp (_dl_argv[1], "--list-diagnostics"))
          {
            state.mode = rtld_mode_list_diagnostics;
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
@@ -1489,13 +1514,11 @@ dl_main (const ElfW(Phdr) *phdr,
        else
          break;
 
-#if HAVE_TUNABLES
       if (__glibc_unlikely (state.mode == rtld_mode_list_tunables))
        {
          __tunables_print ();
          _exit (0);
        }
-#endif
 
       if (state.mode == rtld_mode_list_diagnostics)
        _dl_print_diagnostics (_environ);
@@ -1511,7 +1534,6 @@ dl_main (const ElfW(Phdr) *phdr,
            _dl_usage (ld_so_name, NULL);
        }
 
-      ++_dl_skip_args;
       --_dl_argc;
       ++_dl_argv;
 
@@ -1610,6 +1632,9 @@ dl_main (const ElfW(Phdr) *phdr,
       /* Set the argv[0] string now that we've processed the executable.  */
       if (argv0 != NULL)
         _dl_argv[0] = argv0;
+
+      /* Adjust arguments for the application entry point.  */
+      _dl_start_args_adjust (_dl_argv - orig_argv);
     }
   else
     {
@@ -1695,10 +1720,6 @@ dl_main (const ElfW(Phdr) *phdr,
       if (main_map->l_ld == NULL)
        _exit (1);
 
-      /* We allow here some platform specific code.  */
-#ifdef DISTINGUISH_LIB_VERSIONS
-      DISTINGUISH_LIB_VERSIONS;
-#endif
       _exit (has_interp ? 0 : 2);
     }
 
@@ -1710,10 +1731,6 @@ dl_main (const ElfW(Phdr) *phdr,
   /* With vDSO setup we can initialize the function pointers.  */
   setup_vdso_pointers ();
 
-#ifdef DL_SYSDEP_OSCHECK
-  DL_SYSDEP_OSCHECK (_dl_fatal_printf);
-#endif
-
   /* Initialize the data structures for the search paths for shared
      objects.  */
   call_init_paths (&state);
@@ -2024,7 +2041,7 @@ dl_main (const ElfW(Phdr) *phdr,
      an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
      used.  Trying to do it lazily is too hairy to try when there could be
      multiple threads (from a non-TLS-using libpthread).  */
-  bool was_tls_init_tp_called = tls_init_tp_called;
+  bool was_tls_init_tp_called = __rtld_tls_init_tp_called;
   if (tcbp == NULL)
     tcbp = init_tls (0);
 
@@ -2096,8 +2113,14 @@ dl_main (const ElfW(Phdr) *phdr,
            if (l->l_faked)
              /* The library was not found.  */
              _dl_printf ("\t%s => not found\n",  l->l_libname->name);
+           else if (strcmp (l->l_libname->name, l->l_name) == 0)
+             /* Print vDSO like libraries without duplicate name.  Some
+                consumers depend of this format.  */
+             _dl_printf ("\t%s (0x%0*zx)\n", l->l_libname->name,
+                         (int) sizeof l->l_map_start * 2,
+                         (size_t) l->l_map_start);
            else
-             _dl_printf ("\t%s => %s (0x%0*Zx)\n",
+             _dl_printf ("\t%s => %s (0x%0*zx)\n",
                          DSO_FILENAME (l->l_libname->name),
                          DSO_FILENAME (l->l_name),
                          (int) sizeof l->l_map_start * 2,
@@ -2119,7 +2142,7 @@ dl_main (const ElfW(Phdr) *phdr,
 
            loadbase = LOOKUP_VALUE_ADDRESS (result, false);
 
-           _dl_printf ("%s found at 0x%0*Zd in object at 0x%0*Zd\n",
+           _dl_printf ("%s found at 0x%0*zd in object at 0x%0*zd\n",
                        _dl_argv[i],
                        (int) sizeof ref->st_value * 2,
                        (size_t) ref->st_value,
@@ -2289,7 +2312,7 @@ dl_main (const ElfW(Phdr) *phdr,
                               consider_profiling);
 
        /* Add object to slot information data if necessasy.  */
-       if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+       if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
          _dl_add_to_slotinfo (l, true);
       }
   }
@@ -2315,14 +2338,8 @@ dl_main (const ElfW(Phdr) *phdr,
   _dl_allocate_tls_init (tcbp, false);
 
   /* And finally install it for the main thread.  */
-  if (! tls_init_tp_called)
-    {
-      const char *lossage = TLS_INIT_TP (tcbp);
-      if (__glibc_unlikely (lossage != NULL))
-       _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
-                         lossage);
-      __tls_init_tp ();
-    }
+  if (! __rtld_tls_init_tp_called)
+    call_tls_init_tp (tcbp);
 
   /* Make sure no new search directories have been added.  */
   assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
@@ -2369,10 +2386,8 @@ dl_main (const ElfW(Phdr) *phdr,
      _dl_relocate_object might need to call `mprotect' for DT_TEXTREL.  */
   _dl_sysdep_start_cleanup ();
 
-#ifdef SHARED
   /* Auditing checkpoint: we have added all objects.  */
   _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
-#endif
 
   /* Notify the debugger all new objects are now ready to go.  We must re-get
      the address since by now the variable might be in another object.  */
@@ -2600,15 +2615,6 @@ process_envvars (struct dl_main_state *state)
            _dl_show_auxv ();
          break;
 
-#if !HAVE_TUNABLES
-       case 10:
-         /* Mask for the important hardware capabilities.  */
-         if (!__libc_enable_secure
-             && memcmp (envline, "HWCAP_MASK", 10) == 0)
-           GLRO(dl_hwcap_mask) = _dl_strtoul (&envline[11], NULL);
-         break;
-#endif
-
        case 11:
          /* Path where the binary is found.  */
          if (!__libc_enable_secure
@@ -2638,14 +2644,6 @@ process_envvars (struct dl_main_state *state)
            GLRO(dl_dynamic_weak) = 1;
          break;
 
-       case 13:
-         /* We might have some extra environment variable with length 13
-            to handle.  */
-#ifdef EXTRA_LD_ENVVARS_13
-         EXTRA_LD_ENVVARS_13
-#endif
-         break;
-
        case 14:
          /* Where to place the profiling data file.  */
          if (!__libc_enable_secure
@@ -2663,44 +2661,23 @@ process_envvars (struct dl_main_state *state)
                = _dl_strtoul (&envline[21], NULL) > 1;
            }
          break;
-
-         /* We might have some extra environment variable to handle.  This
-            is tricky due to the pre-processing of the length of the name
-            in the switch statement here.  The code here assumes that added
-            environment variables have a different length.  */
-#ifdef EXTRA_LD_ENVVARS
-         EXTRA_LD_ENVVARS
-#endif
        }
     }
 
   /* Extra security for SUID binaries.  Remove all dangerous environment
      variables.  */
-  if (__builtin_expect (__libc_enable_secure, 0))
+  if (__glibc_unlikely (__libc_enable_secure))
     {
-      static const char unsecure_envvars[] =
-#ifdef EXTRA_UNSECURE_ENVVARS
-       EXTRA_UNSECURE_ENVVARS
-#endif
-       UNSECURE_ENVVARS;
-      const char *nextp;
-
-      nextp = unsecure_envvars;
+      const char *nextp = UNSECURE_ENVVARS;
       do
        {
          unsetenv (nextp);
-         /* We could use rawmemchr but this need not be fast.  */
-         nextp = (char *) (strchr) (nextp, '\0') + 1;
+         nextp = strchr (nextp, '\0') + 1;
        }
       while (*nextp != '\0');
 
       if (__access ("/etc/suid-debug", F_OK) != 0)
-       {
-#if !HAVE_TUNABLES
-         unsetenv ("MALLOC_CHECK_");
-#endif
-         GLRO(dl_debug_mask) = 0;
-       }
+       GLRO(dl_debug_mask) = 0;
 
       if (state->mode != rtld_mode_normal)
        _exit (5);