Branch data Line data Source code
1 : : /* Sniff out modules from ELF headers visible in memory segments.
2 : : Copyright (C) 2008-2012, 2014, 2015, 2018 Red Hat, Inc.
3 : : Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
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 : : #include <config.h>
31 : : #include "libelfP.h" /* For NOTE_ALIGN4 and NOTE_ALIGN8. */
32 : : #include "libdwflP.h"
33 : : #include "common.h"
34 : :
35 : : #include <elf.h>
36 : : #include <gelf.h>
37 : : #include <inttypes.h>
38 : : #include <fcntl.h>
39 : :
40 : : #include <system.h>
41 : :
42 : :
43 : : /* A good size for the initial read from memory, if it's not too costly.
44 : : This more than covers the phdrs and note segment in the average 64-bit
45 : : binary. */
46 : :
47 : : #define INITIAL_READ 1024
48 : :
49 : : #if BYTE_ORDER == LITTLE_ENDIAN
50 : : # define MY_ELFDATA ELFDATA2LSB
51 : : #else
52 : : # define MY_ELFDATA ELFDATA2MSB
53 : : #endif
54 : :
55 : : struct elf_build_id
56 : : {
57 : : void *memory;
58 : : size_t len;
59 : : GElf_Addr vaddr;
60 : : };
61 : :
62 : : struct read_state
63 : : {
64 : : Dwfl *dwfl;
65 : : Dwfl_Memory_Callback *memory_callback;
66 : : void *memory_callback_arg;
67 : : void **buffer;
68 : : size_t *buffer_available;
69 : : };
70 : :
71 : : /* Return user segment index closest to ADDR but not above it.
72 : : If NEXT, return the closest to ADDR but not below it. */
73 : : static int
74 : 380 : addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
75 : : {
76 : 380 : int ndx = -1;
77 : 1186 : do
78 : : {
79 [ + + ]: 1186 : if (dwfl->lookup_segndx[segment] >= 0)
80 : 1110 : ndx = dwfl->lookup_segndx[segment];
81 [ + + ]: 1186 : if (++segment >= dwfl->lookup_elts - 1)
82 [ + - ]: 2 : return next ? ndx + 1 : ndx;
83 : : }
84 [ + + ]: 1184 : while (dwfl->lookup_addr[segment] < addr);
85 : :
86 [ + + ]: 378 : if (next)
87 : : {
88 [ + + ]: 436 : while (dwfl->lookup_segndx[segment] < 0)
89 [ - + ]: 206 : if (++segment >= dwfl->lookup_elts - 1)
90 : 0 : return ndx + 1;
91 : : ndx = dwfl->lookup_segndx[segment];
92 : : }
93 : :
94 : : return ndx;
95 : : }
96 : :
97 : : /* Return whether there is SZ bytes available at PTR till END. */
98 : :
99 : : static bool
100 : 7274 : buf_has_data (const void *ptr, const void *end, size_t sz)
101 : : {
102 [ - + ]: 7274 : return ptr < end && (size_t) (end - ptr) >= sz;
103 : : }
104 : :
105 : : /* Read SZ bytes into *RETP from *PTRP (limited by END) in format EI_DATA.
106 : : Function comes from src/readelf.c . */
107 : :
108 : : static bool
109 : 7274 : buf_read_ulong (unsigned char ei_data, size_t sz,
110 : : const void **ptrp, const void *end, uint64_t *retp)
111 : : {
112 [ + - + - ]: 14548 : if (! buf_has_data (*ptrp, end, sz))
113 : : return false;
114 : :
115 : 7274 : union
116 : : {
117 : : uint64_t u64;
118 : : uint32_t u32;
119 : : } u;
120 : :
121 [ + + ]: 7274 : memcpy (&u, *ptrp, sz);
122 : 7274 : (*ptrp) += sz;
123 : :
124 [ + + ]: 7274 : if (retp == NULL)
125 : : return true;
126 : :
127 [ + + ]: 7096 : if (MY_ELFDATA != ei_data)
128 : : {
129 [ + - ]: 22 : if (sz == 4)
130 : 22 : CONVERT (u.u32);
131 : : else
132 : 0 : CONVERT (u.u64);
133 : : }
134 [ + + ]: 7096 : if (sz == 4)
135 : 78 : *retp = u.u32;
136 : : else
137 : 7018 : *retp = u.u64;
138 : : return true;
139 : : }
140 : :
141 : : /* Try to find matching entry for module from address MODULE_START to
142 : : MODULE_END in NT_FILE note located at NOTE_FILE of NOTE_FILE_SIZE
143 : : bytes in format EI_CLASS and EI_DATA. */
144 : :
145 : : static const char *
146 : 232 : handle_file_note (GElf_Addr module_start, GElf_Addr module_end,
147 : : unsigned char ei_class, unsigned char ei_data,
148 : : const void *note_file, size_t note_file_size)
149 : : {
150 [ + + ]: 232 : if (note_file == NULL)
151 : : return NULL;
152 : :
153 : 178 : size_t sz;
154 [ - + + ]: 178 : switch (ei_class)
155 : : {
156 : : case ELFCLASS32:
157 : : sz = 4;
158 : : break;
159 : 166 : case ELFCLASS64:
160 : 166 : sz = 8;
161 : 166 : break;
162 : : default:
163 : : return NULL;
164 : : }
165 : :
166 : 178 : const void *ptr = note_file;
167 : 178 : const void *end = note_file + note_file_size;
168 : 178 : uint64_t count;
169 [ - + ]: 178 : if (! buf_read_ulong (ei_data, sz, &ptr, end, &count))
170 : : return NULL;
171 [ - + ]: 178 : if (! buf_read_ulong (ei_data, sz, &ptr, end, NULL)) // page_size
172 : : return NULL;
173 : :
174 : 178 : uint64_t maxcount = (size_t) (end - ptr) / (3 * sz);
175 [ - + ]: 178 : if (count > maxcount)
176 : : return NULL;
177 : :
178 : : /* Where file names are stored. */
179 : 178 : const char *fptr = ptr + 3 * count * sz;
180 : :
181 : 178 : ssize_t firstix = -1;
182 : 178 : ssize_t lastix = -1;
183 [ + + ]: 2382 : for (size_t mix = 0; mix < count; mix++)
184 : : {
185 : 2306 : uint64_t mstart, mend, moffset;
186 [ + - ]: 2306 : if (! buf_read_ulong (ei_data, sz, &ptr, fptr, &mstart)
187 [ + - ]: 2306 : || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &mend)
188 [ - + ]: 2306 : || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &moffset))
189 : 0 : return NULL;
190 [ + + + - ]: 2306 : if (mstart == module_start && moffset == 0)
191 : 134 : firstix = lastix = mix;
192 [ + + + + ]: 2306 : if (firstix != -1 && mstart < module_end)
193 : 480 : lastix = mix;
194 [ + + ]: 2306 : if (mend >= module_end)
195 : : break;
196 : : }
197 [ + + ]: 178 : if (firstix == -1)
198 : : return NULL;
199 : :
200 : : const char *retval = NULL;
201 [ + + ]: 1794 : for (ssize_t mix = 0; mix <= lastix; mix++)
202 : : {
203 : 1660 : const char *fnext = memchr (fptr, 0, (const char *) end - fptr);
204 [ - + ]: 1660 : if (fnext == NULL)
205 : : return NULL;
206 [ + + ]: 1660 : if (mix == firstix)
207 : 134 : retval = fptr;
208 [ + + - + ]: 1660 : if (firstix < mix && mix <= lastix && strcmp (fptr, retval) != 0)
209 : : return NULL;
210 : 1660 : fptr = fnext + 1;
211 : : }
212 : : return retval;
213 : : }
214 : :
215 : : /* Return true iff we are certain ELF cannot match BUILD_ID of
216 : : BUILD_ID_LEN bytes. Pass DISK_FILE_HAS_BUILD_ID as false if it is
217 : : certain ELF does not contain build-id (it is only a performance hit
218 : : to pass it always as true). */
219 : :
220 : : static bool
221 : 114 : invalid_elf (Elf *elf, bool disk_file_has_build_id,
222 : : struct elf_build_id *build_id)
223 : : {
224 [ + + + - ]: 114 : if (! disk_file_has_build_id && build_id->len > 0)
225 : : {
226 : : /* Module found in segments with build-id is more reliable
227 : : than a module found via DT_DEBUG on disk without any
228 : : build-id. */
229 : : return true;
230 : : }
231 [ - + ]: 112 : if (disk_file_has_build_id && build_id->len > 0)
232 : : {
233 : 112 : const void *elf_build_id;
234 : 112 : ssize_t elf_build_id_len;
235 : :
236 : : /* If there is a build id in the elf file, check it. */
237 : 112 : elf_build_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id);
238 [ + - ]: 112 : if (elf_build_id_len > 0)
239 : : {
240 [ + - ]: 112 : if (build_id->len != (size_t) elf_build_id_len
241 [ + + ]: 112 : || memcmp (build_id->memory, elf_build_id, build_id->len) != 0)
242 : 24 : return true;
243 : : }
244 : : }
245 : : return false;
246 : : }
247 : :
248 : : static void
249 : 1100 : finish_portion (struct read_state *read_state,
250 : : void **data, size_t *data_size)
251 : : {
252 [ + + + - ]: 1100 : if (*data_size != 0 && *data != NULL)
253 : 140 : (*read_state->memory_callback) (read_state->dwfl, -1, data, data_size,
254 : : 0, 0, read_state->memory_callback_arg);
255 : 1100 : }
256 : :
257 : : static inline bool
258 : 904 : read_portion (struct read_state *read_state,
259 : : void **data, size_t *data_size,
260 : : GElf_Addr start, size_t segment,
261 : : GElf_Addr vaddr, size_t filesz)
262 : : {
263 : : /* Check whether we will have to read the segment data, or if it
264 : : can be returned from the existing buffer. */
265 [ + - ]: 904 : if (filesz > *read_state->buffer_available
266 [ + + ]: 904 : || vaddr - start > *read_state->buffer_available - filesz
267 : : /* If we're in string mode, then don't consider the buffer we have
268 : : sufficient unless it contains the terminator of the string. */
269 [ + + ]: 764 : || (filesz == 0 && memchr (vaddr - start + *read_state->buffer, '\0',
270 : : (*read_state->buffer_available
271 [ - + ]: 62 : - (vaddr - start))) == NULL))
272 : : {
273 : 140 : *data = NULL;
274 : 140 : *data_size = filesz;
275 : 140 : return !(*read_state->memory_callback) (read_state->dwfl,
276 : : addr_segndx (read_state->dwfl,
277 : : segment, vaddr,
278 : : false),
279 : : data, data_size, vaddr, filesz,
280 : 140 : read_state->memory_callback_arg);
281 : : }
282 : :
283 : : /* We already have this whole note segment from our initial read. */
284 : 764 : *data = vaddr - start + (*read_state->buffer);
285 : 764 : *data_size = 0;
286 : 764 : return false;
287 : : }
288 : :
289 : : int
290 : 790 : dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
291 : : Dwfl_Memory_Callback *memory_callback,
292 : : void *memory_callback_arg,
293 : : Dwfl_Module_Callback *read_eagerly,
294 : : void *read_eagerly_arg,
295 : : size_t maxread,
296 : : const void *note_file, size_t note_file_size,
297 : : const struct r_debug_info *r_debug_info)
298 : : {
299 : 790 : size_t segment = ndx;
300 : 790 : struct read_state read_state;
301 : :
302 [ - + ]: 790 : if (segment >= dwfl->lookup_elts)
303 : 0 : segment = dwfl->lookup_elts - 1;
304 : :
305 : : while (segment > 0
306 [ + + + + ]: 1038 : && (dwfl->lookup_segndx[segment] > ndx
307 [ + + ]: 910 : || dwfl->lookup_segndx[segment] == -1))
308 : 248 : --segment;
309 : :
310 [ + + ]: 3630 : while (dwfl->lookup_segndx[segment] < ndx)
311 [ + - ]: 2840 : if (++segment == dwfl->lookup_elts)
312 : : return 0;
313 : :
314 : 790 : GElf_Addr start = dwfl->lookup_addr[segment];
315 : :
316 : : /* First read in the file header and check its sanity. */
317 : :
318 : 790 : void *buffer = NULL;
319 : 790 : size_t buffer_available = INITIAL_READ;
320 : 790 : Elf *elf = NULL;
321 : 790 : int fd = -1;
322 : :
323 : 790 : read_state.dwfl = dwfl;
324 : 790 : read_state.memory_callback = memory_callback;
325 : 790 : read_state.memory_callback_arg = memory_callback_arg;
326 : 790 : read_state.buffer = &buffer;
327 : 790 : read_state.buffer_available = &buffer_available;
328 : :
329 : : /* We might have to reserve some memory for the phdrs. Set to NULL
330 : : here so we can always safely free it. */
331 : 790 : void *phdrsp = NULL;
332 : :
333 : : /* Collect the build ID bits here. */
334 : 790 : struct elf_build_id build_id;
335 : 790 : build_id.memory = NULL;
336 : 790 : build_id.len = 0;
337 : 790 : build_id.vaddr = 0;
338 : :
339 [ + + ]: 790 : if (! (*memory_callback) (dwfl, ndx, &buffer, &buffer_available,
340 : : start, sizeof (Elf64_Ehdr), memory_callback_arg)
341 [ + + ]: 752 : || memcmp (buffer, ELFMAG, SELFMAG) != 0)
342 : 470 : goto out;
343 : :
344 : : /* Extract the information we need from the file header. */
345 : 320 : const unsigned char *e_ident;
346 : 320 : unsigned char ei_class;
347 : 320 : unsigned char ei_data;
348 : 320 : uint16_t e_type;
349 : 320 : union
350 : : {
351 : : Elf32_Ehdr e32;
352 : : Elf64_Ehdr e64;
353 : : } ehdr;
354 : 320 : GElf_Off phoff;
355 : 320 : uint_fast16_t phnum;
356 : 320 : uint_fast16_t phentsize;
357 : 320 : GElf_Off shdrs_end;
358 : 320 : Elf_Data xlatefrom =
359 : : {
360 : : .d_type = ELF_T_EHDR,
361 : : .d_buf = (void *) buffer,
362 : : .d_version = EV_CURRENT,
363 : : };
364 : 320 : Elf_Data xlateto =
365 : : {
366 : : .d_type = ELF_T_EHDR,
367 : : .d_buf = &ehdr,
368 : : .d_size = sizeof ehdr,
369 : : .d_version = EV_CURRENT,
370 : : };
371 : 320 : e_ident = ((const unsigned char *) buffer);
372 : 320 : ei_class = e_ident[EI_CLASS];
373 : 320 : ei_data = e_ident[EI_DATA];
374 : : /* buffer may be unaligned, in which case xlatetom would not work.
375 : : xlatetom does work when the in and out d_buf are equal (but not
376 : : for any other overlap). */
377 : 640 : size_t ehdr_align = (ei_class == ELFCLASS32
378 : : ? __alignof__ (Elf32_Ehdr)
379 [ + + ]: 320 : : __alignof__ (Elf64_Ehdr));
380 [ - + ]: 320 : if (((uintptr_t) buffer & (ehdr_align - 1)) != 0)
381 : : {
382 [ # # ]: 0 : memcpy (&ehdr, buffer,
383 : : (ei_class == ELFCLASS32
384 : : ? sizeof (Elf32_Ehdr)
385 : : : sizeof (Elf64_Ehdr)));
386 : 0 : xlatefrom.d_buf = &ehdr;
387 : : }
388 [ + + - ]: 320 : switch (ei_class)
389 : : {
390 : 42 : case ELFCLASS32:
391 : 42 : xlatefrom.d_size = sizeof (Elf32_Ehdr);
392 [ - + ]: 42 : if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
393 : 0 : goto out;
394 : 42 : e_type = ehdr.e32.e_type;
395 : 42 : phoff = ehdr.e32.e_phoff;
396 : 42 : phnum = ehdr.e32.e_phnum;
397 : 42 : phentsize = ehdr.e32.e_phentsize;
398 [ - + ]: 42 : if (phentsize != sizeof (Elf32_Phdr))
399 : 0 : goto out;
400 : : /* NOTE if the number of sections is > 0xff00 then e_shnum
401 : : is zero and the actual number would come from the section
402 : : zero sh_size field. We ignore this here because getting shdrs
403 : : is just a nice bonus (see below in the type == PT_LOAD case
404 : : where we trim the last segment). */
405 : 42 : shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * sizeof (Elf32_Shdr);
406 : 42 : break;
407 : :
408 : 278 : case ELFCLASS64:
409 : 278 : xlatefrom.d_size = sizeof (Elf64_Ehdr);
410 [ - + ]: 278 : if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
411 : 0 : goto out;
412 : 278 : e_type = ehdr.e64.e_type;
413 : 278 : phoff = ehdr.e64.e_phoff;
414 : 278 : phnum = ehdr.e64.e_phnum;
415 : 278 : phentsize = ehdr.e64.e_phentsize;
416 [ - + ]: 278 : if (phentsize != sizeof (Elf64_Phdr))
417 : 0 : goto out;
418 : : /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum. */
419 : 278 : shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * sizeof (Elf64_Shdr);
420 : 278 : break;
421 : :
422 : 0 : default:
423 : 0 : goto out;
424 : : }
425 : :
426 : : /* The file header tells where to find the program headers.
427 : : These are what we need to find the boundaries of the module.
428 : : Without them, we don't have a module to report. */
429 : :
430 [ - + ]: 320 : if (phnum == 0)
431 : 0 : goto out;
432 : :
433 : 320 : xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
434 : 320 : xlatefrom.d_size = phnum * phentsize;
435 : :
436 : 320 : void *ph_buffer = NULL;
437 : 320 : size_t ph_buffer_size = 0;
438 [ - + ]: 320 : if (read_portion (&read_state, &ph_buffer, &ph_buffer_size,
439 : : start, segment,
440 : : start + phoff, xlatefrom.d_size))
441 : 0 : goto out;
442 : :
443 : 320 : xlatefrom.d_buf = ph_buffer;
444 : :
445 : 320 : bool class32 = ei_class == ELFCLASS32;
446 [ + + ]: 320 : size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
447 [ - + ]: 320 : if (unlikely (phnum > SIZE_MAX / phdr_size))
448 : 0 : goto out;
449 : 320 : const size_t phdrsp_bytes = phnum * phdr_size;
450 : 320 : phdrsp = malloc (phdrsp_bytes);
451 [ - + ]: 320 : if (unlikely (phdrsp == NULL))
452 : 0 : goto out;
453 : :
454 : 320 : xlateto.d_buf = phdrsp;
455 : 320 : xlateto.d_size = phdrsp_bytes;
456 : :
457 : : /* ph_ buffer may be unaligned, in which case xlatetom would not work.
458 : : xlatetom does work when the in and out d_buf are equal (but not
459 : : for any other overlap). */
460 : 320 : size_t phdr_align = (class32
461 : : ? __alignof__ (Elf32_Phdr)
462 : : : __alignof__ (Elf64_Phdr));
463 [ - + ]: 320 : if (((uintptr_t) ph_buffer & (phdr_align - 1)) != 0)
464 : : {
465 : 0 : memcpy (phdrsp, ph_buffer, phdrsp_bytes);
466 : 0 : xlatefrom.d_buf = phdrsp;
467 : : }
468 : :
469 : : /* Track the bounds of the file visible in memory. */
470 : 320 : GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */
471 : 320 : GElf_Off file_end = 0; /* Rounded up to effective page size. */
472 : 320 : GElf_Off contiguous = 0; /* Visible as contiguous file from START. */
473 : 320 : GElf_Off total_filesz = 0; /* Total size of data to read. */
474 : :
475 : : /* Collect the bias between START and the containing PT_LOAD's p_vaddr. */
476 : 320 : GElf_Addr bias = 0;
477 : 320 : bool found_bias = false;
478 : :
479 : : /* Collect the unbiased bounds of the module here. */
480 : 320 : GElf_Addr module_start = -1l;
481 : 320 : GElf_Addr module_end = 0;
482 : 320 : GElf_Addr module_address_sync = 0;
483 : :
484 : : /* If we see PT_DYNAMIC, record it here. */
485 : 320 : GElf_Addr dyn_vaddr = 0;
486 : 320 : GElf_Xword dyn_filesz = 0;
487 : :
488 : 320 : Elf32_Phdr *p32 = phdrsp;
489 : 320 : Elf64_Phdr *p64 = phdrsp;
490 [ + + ]: 320 : if ((ei_class == ELFCLASS32
491 [ + - ]: 42 : && elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
492 [ + + ]: 320 : || (ei_class == ELFCLASS64
493 [ - + ]: 278 : && elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL))
494 : : {
495 : : found_bias = false; /* Trigger error check */
496 : : }
497 : : else
498 : : {
499 : : /* Consider each of the program headers we've read from the image. */
500 [ + + ]: 2636 : for (uint_fast16_t i = 0; i < phnum; ++i)
501 : : {
502 : 2316 : bool is32 = (ei_class == ELFCLASS32);
503 [ + + ]: 2316 : GElf_Word type = is32 ? p32[i].p_type : p64[i].p_type;
504 [ + + ]: 2316 : GElf_Addr vaddr = is32 ? p32[i].p_vaddr : p64[i].p_vaddr;
505 [ + + ]: 2316 : GElf_Xword memsz = is32 ? p32[i].p_memsz : p64[i].p_memsz;
506 [ + + ]: 2316 : GElf_Off offset = is32 ? p32[i].p_offset : p64[i].p_offset;
507 [ + + ]: 2316 : GElf_Xword filesz = is32 ? p32[i].p_filesz : p64[i].p_filesz;
508 [ + + ]: 2316 : GElf_Xword align = is32 ? p32[i].p_align : p64[i].p_align;
509 : :
510 [ + + ]: 2316 : if (type == PT_DYNAMIC)
511 : : {
512 : : dyn_vaddr = vaddr;
513 : : dyn_filesz = filesz;
514 : : }
515 [ + + ]: 2022 : else if (type == PT_NOTE)
516 : : {
517 : : /* If we have already seen a build ID, we don't care any more. */
518 [ + - - + ]: 316 : if (build_id.memory != NULL || filesz == 0)
519 : 0 : continue; /* Next header */
520 : :
521 : : /* We calculate from the p_offset of the note segment,
522 : : because we don't yet know the bias for its p_vaddr. */
523 : 316 : const GElf_Addr note_vaddr = start + offset;
524 : 316 : void *data = NULL;
525 : 316 : size_t data_size = 0;
526 [ - + ]: 316 : if (read_portion (&read_state, &data, &data_size,
527 : : start, segment, note_vaddr, filesz))
528 : 0 : continue; /* Next header */
529 : :
530 [ - + ]: 316 : if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr))
531 : 0 : continue;
532 : :
533 : 316 : assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
534 : :
535 : 316 : void *notes;
536 [ + + ]: 316 : if (ei_data == MY_ELFDATA
537 [ - + ]: 272 : && (uintptr_t) data == (align == 8
538 : 0 : ? NOTE_ALIGN8 ((uintptr_t) data)
539 [ - + ]: 272 : : NOTE_ALIGN4 ((uintptr_t) data)))
540 : : notes = data;
541 : : else
542 : : {
543 : 44 : const unsigned int xencoding = ehdr.e32.e_ident[EI_DATA];
544 : :
545 : 44 : if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr))
546 : : continue;
547 : 44 : notes = malloc (filesz);
548 [ - + ]: 44 : if (unlikely (notes == NULL))
549 : 0 : continue; /* Next header */
550 : 88 : xlatefrom.d_type = xlateto.d_type = (align == 8
551 : : ? ELF_T_NHDR8
552 [ + - ]: 44 : : ELF_T_NHDR);
553 : 44 : xlatefrom.d_buf = (void *) data;
554 : 44 : xlatefrom.d_size = filesz;
555 : 44 : xlateto.d_buf = notes;
556 : 44 : xlateto.d_size = filesz;
557 : :
558 : : /* data may be unaligned, in which case xlatetom would not work.
559 : : xlatetom does work when the in and out d_buf are equal (but not
560 : : for any other overlap). */
561 [ - + ]: 44 : if ((uintptr_t) data != (align == 8
562 : 0 : ? NOTE_ALIGN8 ((uintptr_t) data)
563 [ - + ]: 44 : : NOTE_ALIGN4 ((uintptr_t) data)))
564 : : {
565 : 0 : memcpy (notes, data, filesz);
566 : 0 : xlatefrom.d_buf = notes;
567 : : }
568 : :
569 [ - + ]: 44 : if (elf32_xlatetom (&xlateto, &xlatefrom, xencoding) == NULL)
570 : : {
571 : 0 : free (notes);
572 : 0 : finish_portion (&read_state, &data, &data_size);
573 : 0 : continue;
574 : : }
575 : : }
576 : :
577 : 316 : const GElf_Nhdr *nh = notes;
578 : 316 : size_t len = 0;
579 [ + - ]: 472 : while (filesz - len > sizeof (*nh))
580 : : {
581 : 472 : len += sizeof (*nh);
582 : :
583 : 472 : size_t namesz = nh->n_namesz;
584 [ - + ]: 472 : namesz = align == 8 ? NOTE_ALIGN8 (namesz) : NOTE_ALIGN4 (namesz);
585 [ + - + - ]: 472 : if (namesz > filesz - len || len + namesz < namesz)
586 : : break;
587 : :
588 : 472 : void *note_name = notes + len;
589 : 472 : len += namesz;
590 : :
591 : 472 : size_t descsz = nh->n_descsz;
592 [ - + ]: 472 : descsz = align == 8 ? NOTE_ALIGN8 (descsz) : NOTE_ALIGN4 (descsz);
593 [ + - + - ]: 472 : if (descsz > filesz - len || len + descsz < descsz)
594 : : break;
595 : :
596 : 472 : void *note_desc = notes + len;
597 : 472 : len += descsz;
598 : :
599 : : /* We don't handle very short or really large build-ids. We need at
600 : : at least 3 and allow for up to 64 (normally ids are 20 long). */
601 : : #define MIN_BUILD_ID_BYTES 3
602 : : #define MAX_BUILD_ID_BYTES 64
603 [ + + ]: 472 : if (nh->n_type == NT_GNU_BUILD_ID
604 [ + - ]: 316 : && nh->n_descsz >= MIN_BUILD_ID_BYTES
605 [ + - ]: 316 : && nh->n_descsz <= MAX_BUILD_ID_BYTES
606 [ + - ]: 316 : && nh->n_namesz == sizeof "GNU"
607 [ + - ]: 316 : && !memcmp (note_name, "GNU", sizeof "GNU"))
608 : : {
609 : 316 : build_id.vaddr = (note_desc
610 : : - (const void *) notes
611 : 316 : + note_vaddr);
612 : 316 : build_id.len = nh->n_descsz;
613 : 316 : build_id.memory = malloc (build_id.len);
614 [ + - ]: 316 : if (likely (build_id.memory != NULL))
615 : 316 : memcpy (build_id.memory, note_desc, build_id.len);
616 : : break;
617 : : }
618 : :
619 : 156 : nh = (void *) notes + len;
620 : : }
621 : :
622 [ + + ]: 316 : if (notes != data)
623 : 44 : free (notes);
624 : 316 : finish_portion (&read_state, &data, &data_size);
625 : : }
626 [ + + ]: 1706 : else if (type == PT_LOAD)
627 : : {
628 : 1160 : align = (dwfl->segment_align > 1
629 [ - + ]: 580 : ? dwfl->segment_align : (align ?: 1));
630 : :
631 : 580 : GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
632 : 1160 : GElf_Addr filesz_vaddr = (filesz < memsz
633 [ + + ]: 580 : ? vaddr + filesz : vaddr_end);
634 : 580 : GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
635 : :
636 [ + + ]: 580 : if (file_trimmed_end < offset + filesz)
637 : : {
638 : 564 : file_trimmed_end = offset + filesz;
639 : :
640 : : /* Trim the last segment so we don't bother with zeros
641 : : in the last page that are off the end of the file.
642 : : However, if the extra bit in that page includes the
643 : : section headers, keep them. */
644 : 564 : if (shdrs_end <= filesz_offset
645 [ + + ]: 564 : && shdrs_end > file_trimmed_end)
646 : : {
647 : 44 : filesz += shdrs_end - file_trimmed_end;
648 : 44 : file_trimmed_end = shdrs_end;
649 : : }
650 : : }
651 : :
652 : 580 : total_filesz += filesz;
653 : :
654 [ + + ]: 580 : if (file_end < filesz_offset)
655 : : {
656 : 552 : file_end = filesz_offset;
657 [ + + ]: 552 : if (filesz_vaddr - start == filesz_offset)
658 : 230 : contiguous = file_end;
659 : : }
660 : :
661 [ + + + - ]: 580 : if (!found_bias && (offset & -align) == 0
662 [ + - ]: 320 : && likely (filesz_offset >= phoff + phnum * phentsize))
663 : : {
664 : 320 : bias = start - vaddr;
665 : 320 : found_bias = true;
666 : : }
667 : :
668 [ + + ]: 580 : if ((vaddr & -align) < module_start)
669 : : {
670 : 320 : module_start = vaddr & -align;
671 : 320 : module_address_sync = vaddr + memsz;
672 : : }
673 : :
674 : 580 : if (module_end < vaddr_end)
675 : : module_end = vaddr_end;
676 : : }
677 : : }
678 : : }
679 : :
680 : 320 : finish_portion (&read_state, &ph_buffer, &ph_buffer_size);
681 : :
682 : : /* We must have seen the segment covering offset 0, or else the ELF
683 : : header we read at START was not produced by these program headers. */
684 [ - + ]: 320 : if (unlikely (!found_bias))
685 : 0 : goto out;
686 : :
687 : : /* Now we know enough to report a module for sure: its bounds. */
688 : 320 : module_start += bias;
689 : 320 : module_end += bias;
690 : :
691 : 320 : dyn_vaddr += bias;
692 : :
693 : : /* NAME found from link map has precedence over DT_SONAME possibly read
694 : : below. */
695 : 320 : bool name_is_final = false;
696 : :
697 : : /* Try to match up DYN_VADDR against L_LD as found in link map.
698 : : Segments sniffing may guess invalid address as the first read-only memory
699 : : mapping may not be dumped to the core file (if ELF headers are not dumped)
700 : : and the ELF header is dumped first with the read/write mapping of the same
701 : : file at higher addresses. */
702 [ + - ]: 320 : if (r_debug_info != NULL)
703 : 320 : for (const struct r_debug_info_module *module = r_debug_info->module;
704 [ + + ]: 1168 : module != NULL; module = module->next)
705 [ + + + + ]: 1106 : if (module_start <= module->l_ld && module->l_ld < module_end)
706 : : {
707 : : /* L_LD read from link map must be right while DYN_VADDR is unsafe.
708 : : Therefore subtract DYN_VADDR and add L_LD to get a possibly
709 : : corrective displacement for all addresses computed so far. */
710 : 258 : GElf_Addr fixup = module->l_ld - dyn_vaddr;
711 [ + - ]: 258 : if ((fixup & (dwfl->segment_align - 1)) == 0
712 [ + - ]: 258 : && module_start + fixup <= module->l_ld
713 [ + - ]: 258 : && module->l_ld < module_end + fixup)
714 : : {
715 : 258 : module_start += fixup;
716 : 258 : module_end += fixup;
717 : 258 : dyn_vaddr += fixup;
718 : 258 : bias += fixup;
719 [ + + ]: 258 : if (module->name[0] != '\0')
720 : : {
721 : 216 : name = basename (module->name);
722 : 216 : name_is_final = true;
723 : : }
724 : : break;
725 : : }
726 : : }
727 : :
728 [ + - ]: 320 : if (r_debug_info != NULL)
729 : : {
730 : 320 : bool skip_this_module = false;
731 : 320 : for (struct r_debug_info_module *module = r_debug_info->module;
732 [ + + ]: 1970 : module != NULL; module = module->next)
733 [ + + + + ]: 1650 : if ((module_end > module->start && module_start < module->end)
734 [ + + ]: 1536 : || dyn_vaddr == module->l_ld)
735 : : {
736 [ + + ]: 260 : if (module->elf != NULL
737 [ + + ]: 112 : && invalid_elf (module->elf, module->disk_file_has_build_id,
738 : : &build_id))
739 : : {
740 : 24 : elf_end (module->elf);
741 : 24 : close (module->fd);
742 : 24 : module->elf = NULL;
743 : 24 : module->fd = -1;
744 : : }
745 [ + + ]: 260 : if (module->elf != NULL)
746 : : {
747 : : /* Ignore this found module if it would conflict in address
748 : : space with any already existing module of DWFL. */
749 : 1650 : skip_this_module = true;
750 : : }
751 : : }
752 [ + + ]: 320 : if (skip_this_module)
753 : 88 : goto out;
754 : : }
755 : :
756 : 232 : const char *file_note_name = handle_file_note (module_start, module_end,
757 : : ei_class, ei_data,
758 : : note_file, note_file_size);
759 [ + + ]: 232 : if (file_note_name)
760 : : {
761 : 134 : name = file_note_name;
762 : 134 : name_is_final = true;
763 : 134 : bool invalid = false;
764 : 134 : fd = open (name, O_RDONLY);
765 [ + + ]: 134 : if (fd >= 0)
766 : : {
767 : 2 : Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
768 [ + - ]: 2 : if (error == DWFL_E_NOERROR)
769 : 2 : invalid = invalid_elf (elf, true /* disk_file_has_build_id */,
770 : : &build_id);
771 : : }
772 [ + - ]: 2 : if (invalid)
773 : : {
774 : : /* The file was there, but the build_id didn't match. We
775 : : still want to report the module, but need to get the ELF
776 : : some other way if possible. */
777 : 0 : close (fd);
778 : 0 : fd = -1;
779 : 0 : elf_end (elf);
780 : 0 : elf = NULL;
781 : : }
782 : : }
783 : :
784 : : /* Our return value now says to skip the segments contained
785 : : within the module. */
786 : 232 : ndx = addr_segndx (dwfl, segment, module_end, true);
787 : :
788 : : /* Examine its .dynamic section to get more interesting details.
789 : : If it has DT_SONAME, we'll use that as the module name.
790 : : If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
791 : : We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
792 : : and they also tell us the essential portion of the file
793 : : for fetching symbols. */
794 : 232 : GElf_Addr soname_stroff = 0;
795 : 232 : GElf_Addr dynstr_vaddr = 0;
796 : 232 : GElf_Xword dynstrsz = 0;
797 : 232 : bool execlike = false;
798 : 464 : const size_t dyn_entsize = (ei_class == ELFCLASS32
799 [ + + ]: 232 : ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
800 : 232 : void *dyn_data = NULL;
801 : 232 : size_t dyn_data_size = 0;
802 [ + + - + ]: 232 : if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
803 [ - + ]: 206 : && ! read_portion (&read_state, &dyn_data, &dyn_data_size,
804 : : start, segment, dyn_vaddr, dyn_filesz))
805 : : {
806 [ + - ]: 206 : if ((dyn_filesz / dyn_entsize) == 0
807 [ - + ]: 206 : || dyn_filesz > (SIZE_MAX / dyn_entsize))
808 : 0 : goto out;
809 : 206 : void *dyns = malloc (dyn_filesz);
810 : 206 : Elf32_Dyn *d32 = dyns;
811 : 206 : Elf64_Dyn *d64 = dyns;
812 [ - + ]: 206 : if (unlikely (dyns == NULL))
813 : 0 : goto out;
814 : :
815 : 206 : xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
816 : 206 : xlatefrom.d_buf = (void *) dyn_data;
817 : 206 : xlatefrom.d_size = dyn_filesz;
818 : 206 : xlateto.d_buf = dyns;
819 : 206 : xlateto.d_size = dyn_filesz;
820 : :
821 : : /* dyn_data may be unaligned, in which case xlatetom would not work.
822 : : xlatetom does work when the in and out d_buf are equal (but not
823 : : for any other overlap). */
824 : 206 : bool is32 = (ei_class == ELFCLASS32);
825 : 206 : size_t dyn_align = (is32
826 : : ? __alignof__ (Elf32_Dyn)
827 : : : __alignof__ (Elf64_Dyn));
828 [ - + ]: 206 : if (((uintptr_t) dyn_data & (dyn_align - 1)) != 0)
829 : : {
830 : 0 : memcpy (dyns, dyn_data, dyn_filesz);
831 : 0 : xlatefrom.d_buf = dyns;
832 : : }
833 : :
834 [ + + - + ]: 206 : if ((is32 && elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
835 [ - + ]: 174 : || (!is32 && elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL))
836 : : {
837 : 412 : size_t n = (is32
838 : : ? (dyn_filesz / sizeof (Elf32_Dyn))
839 [ + + ]: 206 : : (dyn_filesz / sizeof (Elf64_Dyn)));
840 [ + + ]: 2164 : for (size_t i = 0; i < n; ++i)
841 : : {
842 [ + + ]: 2150 : GElf_Sxword tag = is32 ? d32[i].d_tag : d64[i].d_tag;
843 [ + + ]: 2150 : GElf_Xword val = is32 ? d32[i].d_un.d_val : d64[i].d_un.d_val;
844 : :
845 [ + + ]: 2150 : if (tag == DT_DEBUG)
846 : : execlike = true;
847 [ + + + + ]: 2140 : else if (tag == DT_SONAME)
848 : : soname_stroff = val;
849 : : else if (tag == DT_STRTAB)
850 : : dynstr_vaddr = val;
851 : 1536 : else if (tag == DT_STRSZ)
852 : : dynstrsz = val;
853 : : else
854 : 1536 : continue;
855 : :
856 [ + + + + ]: 614 : if (soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0)
857 : : break;
858 : : }
859 : : }
860 : 206 : free (dyns);
861 : : }
862 : 232 : finish_portion (&read_state, &dyn_data, &dyn_data_size);
863 : :
864 : : /* We'll use the name passed in or a stupid default if not DT_SONAME. */
865 [ + + ]: 232 : if (name == NULL)
866 [ + + + + ]: 82 : name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
867 : :
868 : 232 : void *soname = NULL;
869 : 232 : size_t soname_size = 0;
870 [ + + + - ]: 232 : if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0)
871 : : {
872 : : /* We know the bounds of the .dynstr section.
873 : :
874 : : The DYNSTR_VADDR pointer comes from the .dynamic section
875 : : (DT_STRTAB, detected above). Ordinarily the dynamic linker
876 : : will have adjusted this pointer in place so it's now an
877 : : absolute address. But sometimes .dynamic is read-only (in
878 : : vDSOs and odd architectures), and sometimes the adjustment
879 : : just hasn't happened yet in the memory image we looked at.
880 : : So treat DYNSTR_VADDR as an absolute address if it falls
881 : : within the module bounds, or try applying the phdr bias
882 : : when that adjusts it to fall within the module bounds. */
883 : :
884 [ + + ]: 72 : if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
885 [ - + ]: 56 : && dynstr_vaddr + bias >= module_start
886 [ - + ]: 56 : && dynstr_vaddr + bias < module_end)
887 : 72 : dynstr_vaddr += bias;
888 : :
889 [ - + ]: 72 : if (unlikely (dynstr_vaddr + dynstrsz > module_end))
890 : 0 : dynstrsz = 0;
891 : :
892 : : /* Try to get the DT_SONAME string. */
893 [ + + - + ]: 72 : if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
894 [ - + ]: 62 : && ! read_portion (&read_state, &soname, &soname_size,
895 : : start, segment,
896 : : dynstr_vaddr + soname_stroff, 0))
897 : 62 : name = soname;
898 : : }
899 : :
900 : : /* Now that we have chosen the module's name and bounds, report it.
901 : : If we found a build ID, report that too. */
902 : :
903 : 232 : Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
904 : : module_start, module_end);
905 : :
906 : : // !execlike && ET_EXEC is PIE.
907 : : // execlike && !ET_EXEC is a static executable.
908 [ + - + + : 232 : if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC))
+ + ]
909 : 36 : mod->is_executable = true;
910 : :
911 [ - + + + ]: 232 : if (likely (mod != NULL) && build_id.memory != NULL
912 [ + - ]: 230 : && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
913 : : build_id.memory,
914 : : build_id.len,
915 : : build_id.vaddr)))
916 : : {
917 : 0 : mod->gc = true;
918 : 0 : mod = NULL;
919 : : }
920 : :
921 : : /* At this point we do not need BUILD_ID or NAME any more.
922 : : They have been copied. */
923 : 232 : free (build_id.memory);
924 : 232 : build_id.memory = NULL;
925 : 232 : finish_portion (&read_state, &soname, &soname_size);
926 : :
927 [ - + ]: 232 : if (unlikely (mod == NULL))
928 : : {
929 : 0 : ndx = -1;
930 : 0 : goto out;
931 : : }
932 : :
933 : : /* We have reported the module. Now let the caller decide whether we
934 : : should read the whole thing in right now. */
935 : :
936 : 464 : const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
937 [ + + ]: 232 : : buffer_available >= contiguous ? 0
938 [ + + ]: 16 : : contiguous - buffer_available);
939 : 464 : const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
940 [ + + ]: 232 : : dynstr_vaddr + dynstrsz - start);
941 : 232 : const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
942 : :
943 [ + + ]: 232 : if (elf == NULL
944 [ + + ]: 230 : && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
945 : : cost, worthwhile, whole, contiguous,
946 : : read_eagerly_arg, &elf)
947 [ + + ]: 74 : && elf == NULL)
948 : : {
949 : : /* The caller wants to read the whole file in right now, but hasn't
950 : : done it for us. Fill in a local image of the virtual file. */
951 : :
952 : 6 : if (file_trimmed_end > maxread)
953 : : file_trimmed_end = maxread;
954 : :
955 : 6 : void *contents = calloc (1, file_trimmed_end);
956 [ - + ]: 6 : if (unlikely (contents == NULL))
957 : 0 : goto out;
958 : :
959 [ + + ]: 6 : if (contiguous < file_trimmed_end)
960 : : {
961 : : /* We can't use the memory image verbatim as the file image.
962 : : So we'll be reading into a local image of the virtual file. */
963 [ + + ]: 36 : for (uint_fast16_t i = 0; i < phnum; ++i)
964 : : {
965 : 32 : bool is32 = (ei_class == ELFCLASS32);
966 [ - + ]: 32 : GElf_Word type = is32 ? p32[i].p_type : p64[i].p_type;
967 : :
968 [ + + ]: 32 : if (type != PT_LOAD)
969 : 24 : continue;
970 : :
971 [ - + ]: 8 : GElf_Addr vaddr = is32 ? p32[i].p_vaddr : p64[i].p_vaddr;
972 [ - + ]: 8 : GElf_Off offset = is32 ? p32[i].p_offset : p64[i].p_offset;
973 [ - + ]: 8 : GElf_Xword filesz = is32 ? p32[i].p_filesz : p64[i].p_filesz;
974 : :
975 : : /* Don't try to read beyond the actual end of file. */
976 [ - + ]: 8 : if (offset >= file_trimmed_end)
977 : 0 : continue;
978 : :
979 : 8 : void *into = contents + offset;
980 : 8 : size_t read_size = MIN (filesz, file_trimmed_end - offset);
981 : 8 : (*memory_callback) (dwfl, addr_segndx (dwfl, segment,
982 : : vaddr + bias, false),
983 : : &into, &read_size, vaddr + bias, read_size,
984 : : memory_callback_arg);
985 : : }
986 : : }
987 : : else
988 : : {
989 : : /* The whole file sits contiguous in memory,
990 : : but the caller didn't want to just do it. */
991 : :
992 : 2 : const size_t have = MIN (buffer_available, file_trimmed_end);
993 [ - + ]: 2 : memcpy (contents, buffer, have);
994 : :
995 [ - + ]: 2 : if (have < file_trimmed_end)
996 : : {
997 : 0 : void *into = contents + have;
998 : 0 : size_t read_size = file_trimmed_end - have;
999 : 0 : (*memory_callback) (dwfl,
1000 : : addr_segndx (dwfl, segment,
1001 : : start + have, false),
1002 : : &into, &read_size, start + have,
1003 : : read_size, memory_callback_arg);
1004 : : }
1005 : : }
1006 : :
1007 : 6 : elf = elf_memory (contents, file_trimmed_end);
1008 [ - + ]: 6 : if (unlikely (elf == NULL))
1009 : 0 : free (contents);
1010 : : else
1011 : 6 : elf->flags |= ELF_F_MALLOCED;
1012 : : }
1013 : :
1014 [ + + - + ]: 232 : if (elf != NULL && mod->main.elf == NULL)
1015 : : {
1016 : : /* Install the file in the module. */
1017 : 76 : mod->main.elf = elf;
1018 : 76 : mod->main.fd = fd;
1019 : 76 : elf = NULL;
1020 : 76 : fd = -1;
1021 : 76 : mod->main.vaddr = module_start - bias;
1022 : 76 : mod->main.address_sync = module_address_sync;
1023 : 76 : mod->main_bias = bias;
1024 : : }
1025 : :
1026 : 156 : out:
1027 [ + + ]: 790 : if (build_id.memory != NULL)
1028 : 86 : free (build_id.memory);
1029 : 790 : free (phdrsp);
1030 [ + + ]: 790 : if (buffer != NULL)
1031 : 684 : (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
1032 : : memory_callback_arg);
1033 : :
1034 [ - + ]: 790 : if (elf != NULL)
1035 : 0 : elf_end (elf);
1036 [ - + ]: 790 : if (fd != -1)
1037 : 0 : close (fd);
1038 : : return ndx;
1039 : : }
|