(root)/
glibc-2.38/
elf/
dl-object.c
       1  /* Storage management for the chain of loaded shared objects.
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <string.h>
      21  #include <stdlib.h>
      22  #include <unistd.h>
      23  #include <ldsodefs.h>
      24  
      25  #include <assert.h>
      26  
      27  
      28  /* Add the new link_map NEW to the end of the namespace list.  */
      29  void
      30  _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
      31  {
      32    /* We modify the list of loaded objects.  */
      33    __rtld_lock_lock_recursive (GL(dl_load_write_lock));
      34  
      35    if (GL(dl_ns)[nsid]._ns_loaded != NULL)
      36      {
      37        struct link_map *l = GL(dl_ns)[nsid]._ns_loaded;
      38        while (l->l_next != NULL)
      39  	l = l->l_next;
      40        new->l_prev = l;
      41        /* new->l_next = NULL;   Would be necessary but we use calloc.  */
      42        l->l_next = new;
      43      }
      44    else
      45      GL(dl_ns)[nsid]._ns_loaded = new;
      46    ++GL(dl_ns)[nsid]._ns_nloaded;
      47    new->l_serial = GL(dl_load_adds);
      48    ++GL(dl_load_adds);
      49  
      50    __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
      51  }
      52  
      53  
      54  /* Allocate a `struct link_map' for a new object being loaded,
      55     and enter it into the _dl_loaded list.  */
      56  struct link_map *
      57  _dl_new_object (char *realname, const char *libname, int type,
      58  		struct link_map *loader, int mode, Lmid_t nsid)
      59  {
      60  #ifdef SHARED
      61    unsigned int naudit;
      62    if (__glibc_unlikely ((mode & (__RTLD_OPENEXEC | __RTLD_VDSO)) != 0))
      63      {
      64        if (mode & __RTLD_OPENEXEC)
      65  	{
      66  	  assert (type == lt_executable);
      67  	  assert (nsid == LM_ID_BASE);
      68  
      69  	  /* Ignore the specified libname for the main executable.  It is
      70  	     only known with an explicit loader invocation.  */
      71  	  libname = "";
      72  	}
      73  
      74        /* We create the map for the executable and vDSO before we know whether
      75  	 we have auditing libraries and if yes, how many.  Assume the
      76  	 worst.  */
      77        naudit = DL_NNS;
      78      }
      79    else
      80      naudit = GLRO (dl_naudit);
      81  #endif
      82  
      83    size_t libname_len = strlen (libname) + 1;
      84    struct link_map *new;
      85    struct libname_list *newname;
      86  #ifdef SHARED
      87    size_t audit_space = naudit * sizeof (struct auditstate);
      88  #else
      89  # define audit_space 0
      90  #endif
      91  
      92    new = (struct link_map *) calloc (sizeof (*new) + audit_space
      93  				    + sizeof (struct link_map *)
      94  				    + sizeof (*newname) + libname_len, 1);
      95    if (new == NULL)
      96      return NULL;
      97  
      98    new->l_real = new;
      99    new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1)
     100  							    + audit_space);
     101  
     102    new->l_libname = newname
     103      = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1);
     104    newname->name = (char *) memcpy (newname + 1, libname, libname_len);
     105    /* newname->next = NULL;	We use calloc therefore not necessary.  */
     106    newname->dont_free = 1;
     107  
     108    /* When we create the executable link map, or a VDSO link map, we start
     109       with "" for the l_name. In these cases "" points to ld.so rodata
     110       and won't get dumped during core file generation. Therefore to assist
     111       gdb and to create more self-contained core files we adjust l_name to
     112       point at the newly allocated copy (which will get dumped) instead of
     113       the ld.so rodata copy.
     114  
     115       Furthermore, in case of explicit loader invocation, discard the
     116       name of the main executable, to match the regular behavior, where
     117       name of the executable is not known.  */
     118  #ifdef SHARED
     119    if (*realname != '\0' && (mode & __RTLD_OPENEXEC) == 0)
     120  #else
     121    if (*realname != '\0')
     122  #endif
     123      new->l_name = realname;
     124    else
     125      new->l_name = (char *) newname->name + libname_len - 1;
     126  
     127    new->l_type = type;
     128    /* If we set the bit now since we know it is never used we avoid
     129       dirtying the cache line later.  */
     130    if ((GLRO(dl_debug_mask) & DL_DEBUG_UNUSED) == 0)
     131      new->l_used = 1;
     132    new->l_loader = loader;
     133  #if NO_TLS_OFFSET != 0
     134    new->l_tls_offset = NO_TLS_OFFSET;
     135  #endif
     136    new->l_ns = nsid;
     137  
     138  #ifdef SHARED
     139    for (unsigned int cnt = 0; cnt < naudit; ++cnt)
     140      /* No need to initialize bindflags due to calloc.  */
     141      link_map_audit_state (new, cnt)->cookie = (uintptr_t) new;
     142  #endif
     143  
     144    /* new->l_global = 0;	We use calloc therefore not necessary.  */
     145  
     146    /* Use the 'l_scope_mem' array by default for the 'l_scope'
     147       information.  If we need more entries we will allocate a large
     148       array dynamically.  */
     149    new->l_scope = new->l_scope_mem;
     150    new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
     151  
     152    /* Counter for the scopes we have to handle.  */
     153    int idx = 0;
     154  
     155    if (GL(dl_ns)[nsid]._ns_loaded != NULL)
     156      /* Add the global scope.  */
     157      new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist;
     158  
     159    /* If we have no loader the new object acts as it.  */
     160    if (loader == NULL)
     161      loader = new;
     162    else
     163      /* Determine the local scope.  */
     164      while (loader->l_loader != NULL)
     165        loader = loader->l_loader;
     166  
     167    /* Insert the scope if it isn't the global scope we already added.  */
     168    if (idx == 0 || &loader->l_searchlist != new->l_scope[0])
     169      {
     170        if ((mode & RTLD_DEEPBIND) != 0 && idx != 0)
     171  	{
     172  	  new->l_scope[1] = new->l_scope[0];
     173  	  idx = 0;
     174  	}
     175  
     176        new->l_scope[idx] = &loader->l_searchlist;
     177      }
     178  
     179    new->l_local_scope[0] = &new->l_searchlist;
     180  
     181    /* Determine the origin.  If allocating the link map for the main
     182       executable, the realname is not known and "".  In this case, the
     183       origin needs to be determined by other means.  However, in case
     184       of an explicit loader invocation, the pathname of the main
     185       executable is known and needs to be processed here: From the
     186       point of view of the kernel, the main executable is the
     187       dynamic loader, and this would lead to a computation of the wrong
     188       origin.  */
     189    if (realname[0] != '\0')
     190      {
     191        size_t realname_len = strlen (realname) + 1;
     192        char *origin;
     193        char *cp;
     194  
     195        if (realname[0] == '/')
     196  	{
     197  	  /* It is an absolute path.  Use it.  But we have to make a
     198  	     copy since we strip out the trailing slash.  */
     199  	  cp = origin = (char *) malloc (realname_len);
     200  	  if (origin == NULL)
     201  	    {
     202  	      origin = (char *) -1;
     203  	      goto out;
     204  	    }
     205  	}
     206        else
     207  	{
     208  	  size_t len = realname_len;
     209  	  char *result = NULL;
     210  
     211  	  /* Get the current directory name.  */
     212  	  origin = NULL;
     213  	  do
     214  	    {
     215  	      char *new_origin;
     216  
     217  	      len += 128;
     218  	      new_origin = (char *) realloc (origin, len);
     219  	      if (new_origin == NULL)
     220  		/* We exit the loop.  Note that result == NULL.  */
     221  		break;
     222  	      origin = new_origin;
     223  	    }
     224  	  while ((result = __getcwd (origin, len - realname_len)) == NULL
     225  		 && errno == ERANGE);
     226  
     227  	  if (result == NULL)
     228  	    {
     229  	      /* We were not able to determine the current directory.
     230  		 Note that free(origin) is OK if origin == NULL.  */
     231  	      free (origin);
     232  	      origin = (char *) -1;
     233  	      goto out;
     234  	    }
     235  
     236  	  /* Find the end of the path and see whether we have to add a
     237  	     slash.  We could use rawmemchr but this need not be
     238  	     fast.  */
     239  	  cp = (strchr) (origin, '\0');
     240  	  if (cp[-1] != '/')
     241  	    *cp++ = '/';
     242  	}
     243  
     244        /* Add the real file name.  */
     245        cp = __mempcpy (cp, realname, realname_len);
     246  
     247        /* Now remove the filename and the slash.  Leave the slash if
     248  	 the name is something like "/foo".  */
     249        do
     250  	--cp;
     251        while (*cp != '/');
     252  
     253        if (cp == origin)
     254  	/* Keep the only slash which is the first character.  */
     255  	++cp;
     256        *cp = '\0';
     257  
     258      out:
     259        new->l_origin = origin;
     260      }
     261  
     262    return new;
     263  }