1 /* Handle symbol and library versioning.
2    Copyright (C) 1997-2022 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))
find_needed(const char * name,struct link_map * map)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
match_symbol(const char * name,Lmid_t ns,ElfW (Word)hash,const char * string,struct link_map * map,int verbose,int weak)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
_dl_check_map_versions(struct link_map * map,int verbose,int trace_mode)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 dependecy.  */
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
_dl_check_all_versions(struct link_map * map,int verbose,int trace_mode)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 }
402