Branch data Line data Source code
1 : : /* Return symbol table of archive.
2 : : Copyright (C) 1998-2000, 2002, 2005, 2009, 2012, 2014, 2015 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <assert.h>
35 : : #include <errno.h>
36 : : #include <stdbool.h>
37 : : #include <stdint.h>
38 : : #include <stdlib.h>
39 : : #include <string.h>
40 : :
41 : : #include <dl-hash.h>
42 : : #include "libelfP.h"
43 : :
44 : :
45 : : static int
46 : 12 : read_number_entries (uint64_t *nump, Elf *elf, size_t *offp, bool index64_p)
47 : : {
48 : 12 : union u
49 : : {
50 : : uint64_t ret64;
51 : : uint32_t ret32;
52 : : } u;
53 : :
54 [ + + ]: 12 : size_t w = index64_p ? 8 : 4;
55 [ + + ]: 12 : if (elf->map_address != NULL)
56 : : /* Use memcpy instead of pointer dereference so as not to assume the
57 : : field is naturally aligned within the file. */
58 : 4 : memcpy (&u, elf->map_address + *offp, sizeof u);
59 [ + - ]: 8 : else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
60 : : return -1;
61 : :
62 : 12 : *offp += w;
63 : :
64 : 12 : if (BYTE_ORDER == LITTLE_ENDIAN)
65 [ + + ]: 12 : *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32);
66 : : else
67 : : *nump = index64_p ? u.ret64 : u.ret32;
68 : :
69 : 12 : return 0;
70 : : }
71 : :
72 : : Elf_Arsym *
73 : 12 : elf_getarsym (Elf *elf, size_t *ptr)
74 : : {
75 [ - + ]: 12 : if (elf->kind != ELF_K_AR)
76 : : {
77 : : /* This is no archive. */
78 : 0 : __libelf_seterrno (ELF_E_NO_ARCHIVE);
79 : 0 : return NULL;
80 : : }
81 : :
82 [ + - ]: 12 : if (ptr != NULL)
83 : : /* In case of an error or when we know the value store the expected
84 : : value now. Doing this allows us easier exits in an error case. */
85 : 12 : *ptr = elf->state.ar.ar_sym_num;
86 : :
87 [ - + ]: 12 : if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
88 : : {
89 : : /* There is no index. */
90 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
91 : 0 : return NULL;
92 : : }
93 : :
94 : 12 : Elf_Arsym *result = elf->state.ar.ar_sym;
95 [ + - ]: 12 : if (result == NULL)
96 : : {
97 : : /* We have not yet read the index. */
98 : 12 : rwlock_wrlock (elf->lock);
99 : :
100 : : /* In case we find no index remember this for the next call. */
101 : 12 : elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
102 : :
103 : : /* We might have to allocate some temporary data for reading. */
104 : 12 : void *temp_data = NULL;
105 : :
106 : 12 : struct ar_hdr *index_hdr;
107 [ + + ]: 12 : if (elf->map_address == NULL)
108 : : {
109 : : /* We must read index from the file. */
110 [ - + ]: 8 : assert (elf->fildes != -1);
111 [ - + ]: 8 : if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
112 : 8 : sizeof (struct ar_hdr), elf->start_offset + SARMAG)
113 : : != sizeof (struct ar_hdr))
114 : : {
115 : : /* It is not possible to read the index. Maybe it does not
116 : : exist. */
117 : 0 : __libelf_seterrno (ELF_E_READ_ERROR);
118 : 0 : goto out;
119 : : }
120 : :
121 : : index_hdr = &elf->state.ar.ar_hdr;
122 : : }
123 : : else
124 : : {
125 [ - + ]: 4 : if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
126 : : {
127 : : /* There is no room for the full archive. */
128 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
129 : 0 : goto out;
130 : : }
131 : :
132 : 4 : index_hdr = (struct ar_hdr *) (elf->map_address
133 : 4 : + elf->start_offset + SARMAG);
134 : : }
135 : :
136 : : /* Now test whether this really is an archive. */
137 [ - + ]: 12 : if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
138 : : {
139 : : /* Invalid magic bytes. */
140 : 0 : __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
141 : 0 : goto out;
142 : : }
143 : :
144 : 12 : bool index64_p;
145 : : /* Now test whether this is the index. If the name is "/", this
146 : : is 32-bit index, if it's "/SYM64/", it's 64-bit index.
147 : :
148 : : XXX This is not entirely true. There are some more forms.
149 : : Which of them shall we handle? */
150 [ + + ]: 12 : if (memcmp (index_hdr->ar_name, "/ ", 16) == 0)
151 : : index64_p = false;
152 [ - + ]: 2 : else if (memcmp (index_hdr->ar_name, "/SYM64/ ", 16) == 0)
153 : : index64_p = true;
154 : : else
155 : : {
156 : : /* If the index is not the first entry, there is no index.
157 : :
158 : : XXX Is this true? */
159 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
160 : 0 : goto out;
161 : : }
162 : 12 : int w = index64_p ? 8 : 4;
163 : :
164 : : /* We have an archive. The first word in there is the number of
165 : : entries in the table. */
166 : 12 : uint64_t n = 0;
167 : 12 : size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
168 [ - + ]: 12 : if (read_number_entries (&n, elf, &off, index64_p) < 0)
169 : : {
170 : : /* Cannot read the number of entries. */
171 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
172 : 0 : goto out;
173 : : }
174 : :
175 : : /* Now we can perform some first tests on whether all the data
176 : : needed for the index is available. */
177 : 12 : char tmpbuf[17];
178 : 12 : memcpy (tmpbuf, index_hdr->ar_size, 10);
179 : 12 : tmpbuf[10] = '\0';
180 : 12 : size_t index_size = atol (tmpbuf);
181 : :
182 [ + - ]: 12 : if (index_size > elf->maximum_size
183 [ + - ]: 12 : || elf->maximum_size - index_size < SARMAG + sizeof (struct ar_hdr)
184 : : #if SIZE_MAX <= 4294967295U
185 : : || n >= SIZE_MAX / sizeof (Elf_Arsym)
186 : : #endif
187 [ - + ]: 12 : || n > index_size / w)
188 : : {
189 : : /* This index table cannot be right since it does not fit into
190 : : the file. */
191 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
192 : 0 : goto out;
193 : : }
194 : :
195 : : /* Now we can allocate the arrays needed to store the index. */
196 : 12 : size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
197 : 12 : elf->state.ar.ar_sym = malloc (ar_sym_len);
198 [ + - ]: 12 : if (elf->state.ar.ar_sym != NULL)
199 : : {
200 : 12 : void *file_data; /* unit32_t[n] or uint64_t[n] */
201 : 12 : char *str_data;
202 : 12 : char *str_end;
203 : 12 : size_t sz = n * w;
204 : :
205 [ + + ]: 12 : if (elf->map_address == NULL)
206 : : {
207 : 8 : temp_data = malloc (sz);
208 [ - + ]: 8 : if (unlikely (temp_data == NULL))
209 : : {
210 : 0 : __libelf_seterrno (ELF_E_NOMEM);
211 : 0 : goto out;
212 : : }
213 : 8 : file_data = temp_data;
214 : :
215 : 8 : ar_sym_len += index_size - n * w;
216 : 8 : Elf_Arsym *newp = realloc (elf->state.ar.ar_sym, ar_sym_len);
217 [ - + ]: 8 : if (newp == NULL)
218 : : {
219 : 0 : free (elf->state.ar.ar_sym);
220 : 0 : elf->state.ar.ar_sym = NULL;
221 : 0 : __libelf_seterrno (ELF_E_NOMEM);
222 : 0 : goto out;
223 : : }
224 : 8 : elf->state.ar.ar_sym = newp;
225 : :
226 : 8 : char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
227 : :
228 : : /* Now read the data from the file. */
229 [ + - ]: 8 : if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
230 : 16 : || ((size_t) pread_retry (elf->fildes, new_str,
231 : 8 : index_size - sz, off + sz)
232 [ - + ]: 8 : != index_size - sz))
233 : : {
234 : : /* We were not able to read the data. */
235 : 0 : free (elf->state.ar.ar_sym);
236 : 0 : elf->state.ar.ar_sym = NULL;
237 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
238 : 0 : goto out;
239 : : }
240 : :
241 : 8 : str_data = (char *) new_str;
242 : 8 : str_end = new_str + (index_size - sz);
243 : : }
244 : : else
245 : : {
246 : 4 : file_data = (void *) (elf->map_address + off);
247 : 4 : if (!ALLOW_UNALIGNED
248 : : && ((uintptr_t) file_data & -(uintptr_t) n) != 0)
249 : : {
250 : : temp_data = malloc (sz);
251 : : if (unlikely (temp_data == NULL))
252 : : {
253 : : __libelf_seterrno (ELF_E_NOMEM);
254 : : goto out;
255 : : }
256 : : file_data = memcpy (temp_data, elf->map_address + off, sz);
257 : : }
258 : 4 : str_data = (char *) (elf->map_address + off + sz);
259 : 4 : str_end = (char *) (elf->map_address + off + index_size - w);
260 : : }
261 : :
262 : : /* Now we can build the data structure. */
263 : 12 : Elf_Arsym *arsym = elf->state.ar.ar_sym;
264 : 12 : uint64_t (*u64)[n] = file_data;
265 : 12 : uint32_t (*u32)[n] = file_data;
266 [ + + ]: 424 : for (size_t cnt = 0; cnt < n; ++cnt)
267 : : {
268 : 412 : arsym[cnt].as_name = str_data;
269 [ + + ]: 412 : if (index64_p)
270 : : {
271 : 12 : uint64_t tmp = (*u64)[cnt];
272 : 12 : if (BYTE_ORDER == LITTLE_ENDIAN)
273 : 12 : tmp = bswap_64 (tmp);
274 : :
275 : 12 : arsym[cnt].as_off = tmp;
276 : :
277 : : /* Check whether 64-bit offset fits into 32-bit
278 : : size_t. */
279 : 12 : if (sizeof (arsym[cnt].as_off) < 8
280 : : && arsym[cnt].as_off != tmp)
281 : : {
282 : : if (elf->map_address == NULL)
283 : : {
284 : : free (elf->state.ar.ar_sym);
285 : : elf->state.ar.ar_sym = NULL;
286 : : }
287 : :
288 : : __libelf_seterrno (ELF_E_RANGE);
289 : : goto out;
290 : : }
291 : : }
292 : 400 : else if (BYTE_ORDER == LITTLE_ENDIAN)
293 : 400 : arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
294 : : else
295 : : arsym[cnt].as_off = (*u32)[cnt];
296 : :
297 : : /* The symbol name must be NUL terminated within the string
298 : : table. Otherwise the archive symbol table is corrupt and
299 : : hashing or scanning the name would read out of bounds. */
300 : 824 : char *endp = (str_data < str_end
301 : 412 : ? memchr (str_data, '\0', str_end - str_data)
302 [ + - ]: 412 : : NULL);
303 [ - + ]: 412 : if (unlikely (endp == NULL))
304 : : {
305 [ # # ]: 0 : if (elf->map_address == NULL)
306 : : {
307 : 0 : free (elf->state.ar.ar_sym);
308 : 0 : elf->state.ar.ar_sym = NULL;
309 : : }
310 : 0 : __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
311 : 0 : goto out;
312 : : }
313 : :
314 : 412 : arsym[cnt].as_hash = _dl_elf_hash (str_data);
315 : 412 : str_data = endp + 1;
316 : : }
317 : :
318 : : /* At the end a special entry. */
319 : 12 : arsym[n].as_name = NULL;
320 : 12 : arsym[n].as_off = 0;
321 : 12 : arsym[n].as_hash = ~0UL;
322 : :
323 : : /* Tell the caller how many entries we have. */
324 : 12 : elf->state.ar.ar_sym_num = n + 1;
325 : : }
326 : :
327 : 12 : result = elf->state.ar.ar_sym;
328 : :
329 : 12 : out:
330 : 12 : free (temp_data);
331 : 12 : rwlock_unlock (elf->lock);
332 : : }
333 : :
334 [ + - ]: 12 : if (ptr != NULL)
335 : 12 : *ptr = elf->state.ar.ar_sym_num;
336 : :
337 : : return result;
338 : : }
|