1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include <elf.h>
22: #include <errno.h>
23: #include <libintl.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include <ldsodefs.h>
27: #include <stdio-common/_itoa.h>
28:
29: #include <assert.h>
30:
31:
32: #ifndef VERSYMIDX
33: # define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
34: #endif
35:
36:
37: #define make_string(string, rest...) \
38: ({ \
39: const char *all[] = { string, ## rest }; \
40: size_t len, cnt; \
41: char *result, *cp; \
42: \
43: len = 1; \
44: for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
45: len += strlen (all[cnt]); \
46: \
47: cp = result = alloca (len); \
48: for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
49: cp = __stpcpy (cp, all[cnt]); \
50: \
51: result; \
52: })
53:
54:
55: static inline struct link_map *
56: __attribute ((always_inline))
57: find_needed (const char *name, struct link_map *map)
58: {
59: struct link_map *tmap;
60: unsigned int n;
61:
62: for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
63: tmap = tmap->l_next)
64: if (_dl_name_match_p (name, tmap))
65: return tmap;
66:
67:
68:
69: for (n = 0; n < map->l_searchlist.r_nlist; n++)
70: if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
71: return map->l_searchlist.r_list[n];
72:
73:
74: return NULL;
75: }
76:
77:
78: static int
79: internal_function
80: match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
81: struct link_map *map, int verbose, int weak)
82: {
83: const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
84: ElfW(Addr) def_offset;
85: ElfW(Verdef) *def;
86:
87: const char *errstring = NULL;
88: int result = 0;
89:
90:
91: if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS, 0))
92: _dl_debug_printf ("\
93: checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
94: string, map->l_name[0] ? map->l_name : rtld_progname,
95: map->l_ns, name, ns);
96:
97: if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0))
98: {
99:
100:
101:
102: if (verbose)
103: {
104:
105: errstring = make_string ("\
106: no version information available (required by ", name, ")");
107: goto call_cerror;
108: }
109: return 0;
110: }
111:
112: def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
113: assert (def_offset != 0);
114:
115: def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
116: while (1)
117: {
118:
119:
120: if (__builtin_expect (def->vd_version, 1) != 1)
121: {
122: char buf[20];
123: buf[sizeof (buf) - 1] = '\0';
124:
125: errstring = make_string ("unsupported version ",
126: _itoa (def->vd_version,
127: &buf[sizeof (buf) - 1], 10, 0),
128: " of Verdef record");
129: result = 1;
130: goto call_cerror;
131: }
132:
133:
134: if (hash == def->vd_hash)
135: {
136: ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
137:
138:
139: if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
140: == 0)
141:
142: return 0;
143: }
144:
145:
146: if (def->vd_next == 0)
147: break;
148:
149:
150: def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
151: }
152:
153:
154: if (__builtin_expect (weak, 1))
155: {
156: if (verbose)
157: {
158:
159: errstring = make_string ("weak version `", string,
160: "' not found (required by ", name, ")");
161: goto call_cerror;
162: }
163: return 0;
164: }
165:
166:
167: errstring = make_string ("version `", string, "' not found (required by ",
168: name, ")");
169: result = 1;
170: call_cerror:
171: _dl_signal_cerror (0, map->l_name[0] ? map->l_name : rtld_progname,
172: NULL, errstring);
173: return result;
174: }
175:
176:
177: int
178: internal_function
179: _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
180: {
181: int result = 0;
182: const char *strtab;
183:
184: ElfW(Dyn) *dyn;
185:
186: ElfW(Dyn) *def;
187:
188:
189: unsigned int ndx_high = 0;
190:
191: const char *errstring = NULL;
192: int errval = 0;
193:
194:
195: if (map->l_info[DT_STRTAB] == NULL)
196: return 0;
197: strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
198:
199: dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
200: def = map->l_info[VERSYMIDX (DT_VERDEF)];
201:
202: if (dyn != NULL)
203: {
204:
205: ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
206:
207:
208:
209: if (__builtin_expect (ent->vn_version, 1) != 1)
210: {
211: char buf[20];
212: buf[sizeof (buf) - 1] = '\0';
213:
214: errstring = make_string ("unsupported version ",
215: _itoa (ent->vn_version,
216: &buf[sizeof (buf) - 1], 10, 0),
217: " of Verneed record\n");
218: call_error:
219: _dl_signal_error (errval, *map->l_name ? map->l_name : rtld_progname,
220: NULL, errstring);
221: }
222:
223: while (1)
224: {
225: ElfW(Vernaux) *aux;
226: struct link_map *needed = find_needed (strtab + ent->vn_file, map);
227:
228:
229:
230: assert (needed != NULL);
231:
232:
233:
234: if (__builtin_expect (! trace_mode, 1)
235: || ! __builtin_expect (needed->l_faked, 0))
236: {
237:
238:
239: aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
240: while (1)
241: {
242:
243: result |= match_symbol ((*map->l_name
244: ? map->l_name : rtld_progname),
245: map->l_ns, aux->vna_hash,
246: strtab + aux->vna_name,
247: needed->l_real, verbose,
248: aux->vna_flags & VER_FLG_WEAK);
249:
250:
251: if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
252: ndx_high = aux->vna_other & 0x7fff;
253:
254: if (aux->vna_next == 0)
255:
256: break;
257:
258:
259: aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
260: }
261: }
262:
263: if (ent->vn_next == 0)
264:
265: break;
266:
267:
268: ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
269: }
270: }
271:
272:
273:
274:
275:
276:
277: if (def != NULL)
278: {
279: ElfW(Verdef) *ent;
280: ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
281: while (1)
282: {
283: if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
284: ndx_high = ent->vd_ndx & 0x7fff;
285:
286: if (ent->vd_next == 0)
287:
288: break;
289:
290: ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
291: }
292: }
293:
294: if (ndx_high > 0)
295: {
296:
297:
298:
299: map->l_versions = (struct r_found_version *)
300: calloc (ndx_high + 1, sizeof (*map->l_versions));
301: if (__builtin_expect (map->l_versions == NULL, 0))
302: {
303: errstring = N_("cannot allocate version reference table");
304: errval = ENOMEM;
305: goto call_error;
306: }
307:
308:
309: map->l_nversions = ndx_high + 1;
310:
311:
312: map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
313:
314: if (dyn != NULL)
315: {
316: ElfW(Verneed) *ent;
317: ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
318: while (1)
319: {
320: ElfW(Vernaux) *aux;
321: aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
322: while (1)
323: {
324: ElfW(Half) ndx = aux->vna_other & 0x7fff;
325: map->l_versions[ndx].hash = aux->vna_hash;
326: map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
327: map->l_versions[ndx].name = &strtab[aux->vna_name];
328: map->l_versions[ndx].filename = &strtab[ent->vn_file];
329:
330: if (aux->vna_next == 0)
331:
332: break;
333:
334:
335: aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
336: }
337:
338: if (ent->vn_next == 0)
339:
340: break;
341:
342:
343: ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
344: }
345: }
346:
347:
348: if (def != NULL)
349: {
350: ElfW(Verdef) *ent;
351: ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
352: while (1)
353: {
354: ElfW(Verdaux) *aux;
355: aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
356:
357: if ((ent->vd_flags & VER_FLG_BASE) == 0)
358: {
359:
360:
361: ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
362: map->l_versions[ndx].hash = ent->vd_hash;
363: map->l_versions[ndx].name = &strtab[aux->vda_name];
364: map->l_versions[ndx].filename = NULL;
365: }
366:
367: if (ent->vd_next == 0)
368:
369: break;
370:
371: ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
372: }
373: }
374: }
375:
376: return result;
377: }
378:
379:
380: int
381: internal_function
382: _dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
383: {
384: struct link_map *l;
385: int result = 0;
386:
387: for (l = map; l != NULL; l = l->l_next)
388: result |= (! l->l_faked
389: && _dl_check_map_versions (l, verbose, trace_mode));
390:
391: return result;
392: }