(root)/
glibc-2.38/
elf/
dl-version.c
       1  /* Handle symbol and library versioning.
       2     Copyright (C) 1997-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 <elf.h>
      20  #include <errno.h>
      21  #include <libintl.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  #include <ldsodefs.h>
      25  #include <_itoa.h>
      26  
      27  #include <assert.h>
      28  
      29  static inline struct link_map *
      30  __attribute ((always_inline))
      31  find_needed (const char *name, struct link_map *map)
      32  {
      33    struct link_map *tmap;
      34    unsigned int n;
      35  
      36    for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
      37         tmap = tmap->l_next)
      38      if (_dl_name_match_p (name, tmap))
      39        return tmap;
      40  
      41    /* The required object is not in the global scope, look to see if it is
      42       a dependency of the current object.  */
      43    for (n = 0; n < map->l_searchlist.r_nlist; n++)
      44      if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
      45        return map->l_searchlist.r_list[n];
      46  
      47    /* Should never happen.  */
      48    return NULL;
      49  }
      50  
      51  
      52  static int
      53  match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
      54  	      struct link_map *map, int verbose, int weak)
      55  {
      56    const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
      57    ElfW(Addr) def_offset;
      58    ElfW(Verdef) *def;
      59    /* Initialize to make the compiler happy.  */
      60    int result = 0;
      61    struct dl_exception exception;
      62  
      63    /* Display information about what we are doing while debugging.  */
      64    if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
      65      _dl_debug_printf ("\
      66  checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
      67  		      string, DSO_FILENAME (map->l_name),
      68  		      map->l_ns, name, ns);
      69  
      70    if (__glibc_unlikely (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL))
      71      {
      72        /* The file has no symbol versioning.  I.e., the dependent
      73  	 object was linked against another version of this file.  We
      74  	 only print a message if verbose output is requested.  */
      75        if (verbose)
      76  	{
      77  	  /* XXX We cannot translate the messages.  */
      78  	  _dl_exception_create_format
      79  	    (&exception, DSO_FILENAME (map->l_name),
      80  	     "no version information available (required by %s)", name);
      81  	  goto call_cerror;
      82  	}
      83        return 0;
      84      }
      85  
      86    def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
      87    assert (def_offset != 0);
      88  
      89    def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
      90    while (1)
      91      {
      92        /* Currently the version number of the definition entry is 1.
      93  	 Make sure all we see is this version.  */
      94        if (__builtin_expect (def->vd_version, 1) != 1)
      95  	{
      96  	  char buf[20];
      97  	  buf[sizeof (buf) - 1] = '\0';
      98  	  /* XXX We cannot translate the message.  */
      99  	  _dl_exception_create_format
     100  	    (&exception, DSO_FILENAME (map->l_name),
     101  	     "unsupported version %s of Verdef record",
     102  	     _itoa (def->vd_version, &buf[sizeof (buf) - 1], 10, 0));
     103  	  result = 1;
     104  	  goto call_cerror;
     105  	}
     106  
     107        /* Compare the hash values.  */
     108        if (hash == def->vd_hash)
     109  	{
     110  	  ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
     111  
     112  	  /* To be safe, compare the string as well.  */
     113  	  if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
     114  	      == 0)
     115  	    /* Bingo!  */
     116  	    return 0;
     117  	}
     118  
     119        /* If no more definitions we failed to find what we want.  */
     120        if (def->vd_next == 0)
     121  	break;
     122  
     123        /* Next definition.  */
     124        def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
     125      }
     126  
     127    /* Symbol not found.  If it was a weak reference it is not fatal.  */
     128    if (__glibc_likely (weak))
     129      {
     130        if (verbose)
     131  	{
     132  	  /* XXX We cannot translate the message.  */
     133  	  _dl_exception_create_format
     134  	    (&exception, DSO_FILENAME (map->l_name),
     135  	     "weak version `%s' not found (required by %s)", string, name);
     136  	  goto call_cerror;
     137  	}
     138        return 0;
     139      }
     140  
     141    /* XXX We cannot translate the message.  */
     142    _dl_exception_create_format
     143      (&exception, DSO_FILENAME (map->l_name),
     144       "version `%s' not found (required by %s)", string, name);
     145    result = 1;
     146   call_cerror:
     147    _dl_signal_cexception (0, &exception, N_("version lookup error"));
     148    _dl_exception_free (&exception);
     149    return result;
     150  }
     151  
     152  
     153  int
     154  _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
     155  {
     156    int result = 0;
     157    const char *strtab;
     158    /* Pointer to section with needed versions.  */
     159    ElfW(Dyn) *dyn;
     160    /* Pointer to dynamic section with definitions.  */
     161    ElfW(Dyn) *def;
     162    /* We need to find out which is the highest version index used
     163      in a dependency.  */
     164    unsigned int ndx_high = 0;
     165    struct dl_exception exception;
     166    /* Initialize to make the compiler happy.  */
     167    int errval = 0;
     168  
     169    /* If we don't have a string table, we must be ok.  */
     170    if (map->l_info[DT_STRTAB] == NULL)
     171      return 0;
     172    strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     173  
     174    dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
     175    def = map->l_info[VERSYMIDX (DT_VERDEF)];
     176  
     177    if (dyn != NULL)
     178      {
     179        /* This file requires special versions from its dependencies.  */
     180        ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
     181  
     182        /* Currently the version number of the needed entry is 1.
     183  	 Make sure all we see is this version.  */
     184        if (__builtin_expect (ent->vn_version, 1) != 1)
     185  	{
     186  	  char buf[20];
     187  	  buf[sizeof (buf) - 1] = '\0';
     188  	  /* XXX We cannot translate the message.  */
     189  	  _dl_exception_create_format
     190  	    (&exception, DSO_FILENAME (map->l_name),
     191  	     "unsupported version %s of Verneed record",
     192  	     _itoa (ent->vn_version, &buf[sizeof (buf) - 1], 10, 0));
     193  	call_error:
     194  	  _dl_signal_exception (errval, &exception, NULL);
     195  	}
     196  
     197        while (1)
     198  	{
     199  	  ElfW(Vernaux) *aux;
     200  	  struct link_map *needed = find_needed (strtab + ent->vn_file, map);
     201  
     202  	  /* If NEEDED is NULL this means a dependency was not found
     203  	     and no stub entry was created.  This should never happen.  */
     204  	  assert (needed != NULL);
     205  
     206  	  /* Make sure this is no stub we created because of a missing
     207  	     dependency.  */
     208  	  if (__builtin_expect (! trace_mode, 1)
     209  	      || ! __builtin_expect (needed->l_faked, 0))
     210  	    {
     211  	      /* NEEDED is the map for the file we need.  Now look for the
     212  		 dependency symbols.  */
     213  	      aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
     214  	      while (1)
     215  		{
     216  		  /* Match the symbol.  */
     217  		  const char *string = strtab + aux->vna_name;
     218  		  result |= match_symbol (DSO_FILENAME (map->l_name),
     219  					  map->l_ns, aux->vna_hash,
     220  					  string, needed->l_real, verbose,
     221  					  aux->vna_flags & VER_FLG_WEAK);
     222  
     223  		  /* 0xfd0e42: _dl_elf_hash ("GLIBC_ABI_DT_RELR").  */
     224  		  if (aux->vna_hash == 0xfd0e42
     225  		      && __glibc_likely (strcmp (string,
     226  						 "GLIBC_ABI_DT_RELR")
     227  					 == 0))
     228  		    map->l_dt_relr_ref = 1;
     229  
     230  		  /* Compare the version index.  */
     231  		  if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
     232  		    ndx_high = aux->vna_other & 0x7fff;
     233  
     234  		  if (aux->vna_next == 0)
     235  		    /* No more symbols.  */
     236  		    break;
     237  
     238  		  /* Next symbol.  */
     239  		  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
     240  		}
     241  	    }
     242  
     243  	  if (ent->vn_next == 0)
     244  	    /* No more dependencies.  */
     245  	    break;
     246  
     247  	  /* Next dependency.  */
     248  	  ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
     249  	}
     250      }
     251  
     252    /* We also must store the names of the defined versions.  Determine
     253       the maximum index here as well.
     254  
     255       XXX We could avoid the loop by just taking the number of definitions
     256       as an upper bound of new indices.  */
     257    if (def != NULL)
     258      {
     259        ElfW(Verdef) *ent;
     260        ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
     261        while (1)
     262  	{
     263  	  if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
     264  	    ndx_high = ent->vd_ndx & 0x7fff;
     265  
     266  	  if (ent->vd_next == 0)
     267  	    /* No more definitions.  */
     268  	    break;
     269  
     270  	  ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
     271  	}
     272      }
     273  
     274    if (ndx_high > 0)
     275      {
     276        /* Now we are ready to build the array with the version names
     277  	 which can be indexed by the version index in the VERSYM
     278  	 section.  */
     279        map->l_versions = (struct r_found_version *)
     280  	calloc (ndx_high + 1, sizeof (*map->l_versions));
     281        if (__glibc_unlikely (map->l_versions == NULL))
     282  	{
     283  	  _dl_exception_create
     284  	    (&exception, DSO_FILENAME (map->l_name),
     285  	     N_("cannot allocate version reference table"));
     286  	  errval = ENOMEM;
     287  	  goto call_error;
     288  	}
     289  
     290        /* Store the number of available symbols.  */
     291        map->l_nversions = ndx_high + 1;
     292  
     293        /* Compute the pointer to the version symbols.  */
     294        map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
     295  
     296        if (dyn != NULL)
     297  	{
     298  	  ElfW(Verneed) *ent;
     299  	  ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
     300  	  while (1)
     301  	    {
     302  	      ElfW(Vernaux) *aux;
     303  	      aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
     304  	      while (1)
     305  		{
     306  		  ElfW(Half) ndx = aux->vna_other & 0x7fff;
     307  		  /* In trace mode, dependencies may be missing.  */
     308  		  if (__glibc_likely (ndx < map->l_nversions))
     309  		    {
     310  		      map->l_versions[ndx].hash = aux->vna_hash;
     311  		      map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
     312  		      map->l_versions[ndx].name = &strtab[aux->vna_name];
     313  		      map->l_versions[ndx].filename = &strtab[ent->vn_file];
     314  		    }
     315  
     316  		  if (aux->vna_next == 0)
     317  		    /* No more symbols.  */
     318  		    break;
     319  
     320  		  /* Advance to next symbol.  */
     321  		  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
     322  		}
     323  
     324  	      if (ent->vn_next == 0)
     325  		/* No more dependencies.  */
     326  		break;
     327  
     328  	      /* Advance to next dependency.  */
     329  	      ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
     330  	    }
     331  	}
     332  
     333        /* And insert the defined versions.  */
     334        if (def != NULL)
     335  	{
     336  	  ElfW(Verdef) *ent;
     337  	  ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
     338  	  while (1)
     339  	    {
     340  	      ElfW(Verdaux) *aux;
     341  	      aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
     342  
     343  	      if ((ent->vd_flags & VER_FLG_BASE) == 0)
     344  		{
     345  		  /* The name of the base version should not be
     346  		     available for matching a versioned symbol.  */
     347  		  ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
     348  		  map->l_versions[ndx].hash = ent->vd_hash;
     349  		  map->l_versions[ndx].name = &strtab[aux->vda_name];
     350  		  map->l_versions[ndx].filename = NULL;
     351  		}
     352  
     353  	      if (ent->vd_next == 0)
     354  		/* No more definitions.  */
     355  		break;
     356  
     357  	      ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
     358  	    }
     359  	}
     360      }
     361  
     362    /* When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue
     363       an error if there is a DT_RELR entry without GLIBC_ABI_DT_RELR
     364       dependency.  */
     365    if (dyn != NULL
     366        && map->l_info[DT_NEEDED] != NULL
     367        && map->l_info[DT_RELR] != NULL
     368        && __glibc_unlikely (!map->l_dt_relr_ref))
     369      {
     370        const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     371        const ElfW(Dyn) *d;
     372        for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
     373  	if (d->d_tag == DT_NEEDED)
     374  	  {
     375  	    const char *name = strtab + d->d_un.d_val;
     376  	    if (strncmp (name, "libc.so.", 8) == 0)
     377  	      {
     378  		_dl_exception_create
     379  		  (&exception, DSO_FILENAME (map->l_name),
     380  		   N_("DT_RELR without GLIBC_ABI_DT_RELR dependency"));
     381  		goto call_error;
     382  	      }
     383  	  }
     384      }
     385  
     386    return result;
     387  }
     388  
     389  
     390  int
     391  _dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
     392  {
     393    struct link_map *l;
     394    int result = 0;
     395  
     396    for (l = map; l != NULL; l = l->l_next)
     397      result |= (! l->l_faked
     398  	       && _dl_check_map_versions (l, verbose, trace_mode));
     399  
     400    return result;
     401  }