1 /* Handle symbol and library versioning.
2    Copyright (C) 1997-2021 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 		  result |= match_symbol (DSO_FILENAME (map->l_name),
218 					  map->l_ns, aux->vna_hash,
219 					  strtab + aux->vna_name,
220 					  needed->l_real, verbose,
221 					  aux->vna_flags & VER_FLG_WEAK);
222 
223 		  /* Compare the version index.  */
224 		  if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
225 		    ndx_high = aux->vna_other & 0x7fff;
226 
227 		  if (aux->vna_next == 0)
228 		    /* No more symbols.  */
229 		    break;
230 
231 		  /* Next symbol.  */
232 		  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
233 		}
234 	    }
235 
236 	  if (ent->vn_next == 0)
237 	    /* No more dependencies.  */
238 	    break;
239 
240 	  /* Next dependency.  */
241 	  ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
242 	}
243     }
244 
245   /* We also must store the names of the defined versions.  Determine
246      the maximum index here as well.
247 
248      XXX We could avoid the loop by just taking the number of definitions
249      as an upper bound of new indices.  */
250   if (def != NULL)
251     {
252       ElfW(Verdef) *ent;
253       ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
254       while (1)
255 	{
256 	  if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
257 	    ndx_high = ent->vd_ndx & 0x7fff;
258 
259 	  if (ent->vd_next == 0)
260 	    /* No more definitions.  */
261 	    break;
262 
263 	  ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
264 	}
265     }
266 
267   if (ndx_high > 0)
268     {
269       /* Now we are ready to build the array with the version names
270 	 which can be indexed by the version index in the VERSYM
271 	 section.  */
272       map->l_versions = (struct r_found_version *)
273 	calloc (ndx_high + 1, sizeof (*map->l_versions));
274       if (__glibc_unlikely (map->l_versions == NULL))
275 	{
276 	  _dl_exception_create
277 	    (&exception, DSO_FILENAME (map->l_name),
278 	     N_("cannot allocate version reference table"));
279 	  errval = ENOMEM;
280 	  goto call_error;
281 	}
282 
283       /* Store the number of available symbols.  */
284       map->l_nversions = ndx_high + 1;
285 
286       /* Compute the pointer to the version symbols.  */
287       map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
288 
289       if (dyn != NULL)
290 	{
291 	  ElfW(Verneed) *ent;
292 	  ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
293 	  while (1)
294 	    {
295 	      ElfW(Vernaux) *aux;
296 	      aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
297 	      while (1)
298 		{
299 		  ElfW(Half) ndx = aux->vna_other & 0x7fff;
300 		  /* In trace mode, dependencies may be missing.  */
301 		  if (__glibc_likely (ndx < map->l_nversions))
302 		    {
303 		      map->l_versions[ndx].hash = aux->vna_hash;
304 		      map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
305 		      map->l_versions[ndx].name = &strtab[aux->vna_name];
306 		      map->l_versions[ndx].filename = &strtab[ent->vn_file];
307 		    }
308 
309 		  if (aux->vna_next == 0)
310 		    /* No more symbols.  */
311 		    break;
312 
313 		  /* Advance to next symbol.  */
314 		  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
315 		}
316 
317 	      if (ent->vn_next == 0)
318 		/* No more dependencies.  */
319 		break;
320 
321 	      /* Advance to next dependency.  */
322 	      ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
323 	    }
324 	}
325 
326       /* And insert the defined versions.  */
327       if (def != NULL)
328 	{
329 	  ElfW(Verdef) *ent;
330 	  ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
331 	  while (1)
332 	    {
333 	      ElfW(Verdaux) *aux;
334 	      aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
335 
336 	      if ((ent->vd_flags & VER_FLG_BASE) == 0)
337 		{
338 		  /* The name of the base version should not be
339 		     available for matching a versioned symbol.  */
340 		  ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
341 		  map->l_versions[ndx].hash = ent->vd_hash;
342 		  map->l_versions[ndx].name = &strtab[aux->vda_name];
343 		  map->l_versions[ndx].filename = NULL;
344 		}
345 
346 	      if (ent->vd_next == 0)
347 		/* No more definitions.  */
348 		break;
349 
350 	      ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
351 	    }
352 	}
353     }
354 
355   return result;
356 }
357 
358 
359 int
_dl_check_all_versions(struct link_map * map,int verbose,int trace_mode)360 _dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
361 {
362   struct link_map *l;
363   int result = 0;
364 
365   for (l = map; l != NULL; l = l->l_next)
366     result |= (! l->l_faked
367 	       && _dl_check_map_versions (l, verbose, trace_mode));
368 
369   return result;
370 }
371