Branch data Line data Source code
1 : : /* Classification of ELF files.
2 : : Copyright (C) 2019 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of the GNU General Public License as published by
7 : : the Free Software Foundation; either version 3 of the License, or
8 : : (at your option) any later version.
9 : :
10 : : elfutils is distributed in the hope that it will be useful, but
11 : : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : GNU General Public License for more details.
14 : :
15 : : You should have received a copy of the GNU General Public License
16 : : along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 : :
18 : : #include <config.h>
19 : :
20 : : #include <argp.h>
21 : : #include <error.h>
22 : : #include <fcntl.h>
23 : : #include <gelf.h>
24 : : #include <stdbool.h>
25 : : #include <stddef.h>
26 : : #include <stdio.h>
27 : : #include <stdlib.h>
28 : : #include <string.h>
29 : : #include <sys/stat.h>
30 : : #include <unistd.h>
31 : :
32 : : #include ELFUTILS_HEADER(elf)
33 : : #include ELFUTILS_HEADER(dwelf)
34 : : #include "printversion.h"
35 : :
36 : : /* Name and version of program. */
37 : : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
38 : :
39 : : /* Bug report address. */
40 : : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
41 : :
42 : : /* Set by parse_opt. */
43 : : static int verbose;
44 : :
45 : : /* Set by the main function. */
46 : : static const char *current_path;
47 : :
48 : : /* Set by open_file. */
49 : : static int file_fd = -1;
50 : :
51 : : /* Set by issue or elf_issue. */
52 : : static bool issue_found;
53 : :
54 : : /* Non-fatal issue occurred while processing the current_path. */
55 : : static void
56 : 0 : issue (int e, const char *msg)
57 : : {
58 [ # # ]: 0 : if (verbose >= 0)
59 : : {
60 [ # # ]: 0 : if (current_path == NULL)
61 : 0 : error (0, e, "%s", msg);
62 : : else
63 : 0 : error (0, e, "%s '%s'", msg, current_path);
64 : : }
65 : 0 : issue_found = true;
66 : 0 : }
67 : :
68 : : /* Non-fatal issue occurred while processing the current ELF. */
69 : : static void
70 : 0 : elf_issue (const char *msg)
71 : : {
72 [ # # ]: 0 : if (verbose >= 0)
73 : 0 : error (0, 0, "%s: %s: '%s'", msg, elf_errmsg (-1), current_path);
74 : 0 : issue_found = true;
75 : 0 : }
76 : :
77 : : /* Set by parse_opt. */
78 : : static bool flag_only_regular_files;
79 : :
80 : : static bool
81 : 600 : open_file (void)
82 : : {
83 [ - + ]: 600 : if (verbose > 1)
84 : 0 : fprintf (stderr, "debug: processing file: %s\n", current_path);
85 : :
86 : 1200 : file_fd = open (current_path, O_RDONLY | (flag_only_regular_files
87 [ + - ]: 600 : ? O_NOFOLLOW : 0));
88 [ - + ]: 600 : if (file_fd < 0)
89 : : {
90 [ # # # # ]: 0 : if (!flag_only_regular_files || errno != ELOOP)
91 : 0 : issue (errno, N_("opening"));
92 : 0 : return false;
93 : : }
94 : :
95 : 600 : struct stat st;
96 [ - + ]: 600 : if (fstat (file_fd, &st) != 0)
97 : : {
98 : 0 : issue (errno, N_("reading"));
99 : 0 : return false;
100 : : }
101 : :
102 : : /* Don't even bother with directories. */
103 [ + - ]: 600 : if (S_ISDIR (st.st_mode)
104 [ - + - - ]: 600 : || (flag_only_regular_files && !S_ISREG (st.st_mode)))
105 : 0 : return false;
106 : :
107 : : return true;
108 : : }
109 : :
110 : : static void
111 : 600 : close_file (void)
112 : : {
113 [ + - ]: 600 : if (file_fd >= 0)
114 : : {
115 : 600 : close (file_fd);
116 : 600 : file_fd = -1;
117 : : }
118 : 600 : }
119 : :
120 : : /* Set by open_elf. */
121 : : static Elf *elf;
122 : :
123 : : /* Set by parse_opt. */
124 : : static bool flag_compressed;
125 : :
126 : : static bool
127 : 600 : open_elf (void)
128 : : {
129 [ - + ]: 600 : if (!open_file ())
130 : : {
131 : : /* Make sure the file descriptor is gone. */
132 : 0 : close_file ();
133 : 0 : return false;
134 : : }
135 : :
136 [ - + ]: 600 : if (flag_compressed)
137 : 0 : elf = dwelf_elf_begin (file_fd);
138 : : else
139 : 600 : elf = elf_begin (file_fd, ELF_C_READ, NULL);
140 : :
141 [ - + ]: 600 : if (elf == NULL)
142 : : {
143 : 0 : elf_issue ("opening ELF file");
144 : 0 : close_file ();
145 : 0 : return false;
146 : : }
147 : :
148 : : return true;
149 : : }
150 : :
151 : : static void
152 : 600 : close_elf (void)
153 : : {
154 [ + - ]: 600 : if (elf != NULL)
155 : : {
156 : 600 : elf_end (elf);
157 : 600 : elf = NULL;
158 : : }
159 : :
160 : 600 : close_file ();
161 : 600 : }
162 : :
163 : : static const char *
164 : 0 : elf_kind_string (int kind)
165 : : {
166 [ # # # # : 0 : switch (kind)
# ]
167 : : {
168 : : case ELF_K_NONE:
169 : : return "ELF_K_NONE";
170 : 0 : case ELF_K_AR:
171 : 0 : return "ELF_K_AR";
172 : 0 : case ELF_K_COFF:
173 : 0 : return "ELF_K_COFF"; /* libelf doesn't really support this. */
174 : 0 : case ELF_K_ELF:
175 : 0 : return "ELF_K_ELF";
176 : 0 : default:
177 : 0 : return "<unknown>";
178 : : }
179 : : }
180 : :
181 : : static const char *
182 : 0 : elf_type_string (int type)
183 : : {
184 [ # # # # : 0 : switch (type)
# # ]
185 : : {
186 : : case ET_NONE:
187 : : return "ET_NONE";
188 : 0 : case ET_REL:
189 : 0 : return "ET_REL";
190 : 0 : case ET_EXEC:
191 : 0 : return "ET_EXEC";
192 : 0 : case ET_DYN:
193 : 0 : return "ET_DYN";
194 : 0 : case ET_CORE:
195 : 0 : return "ET_CORE";
196 : 0 : default:
197 : 0 : return "<unknown>";
198 : : }
199 : : }
200 : :
201 : : static int elf_type;
202 : : static bool has_program_load;
203 : : static bool has_sections;
204 : : static bool has_bits_alloc;
205 : : static bool has_program_interpreter;
206 : : static bool has_dynamic;
207 : : static bool has_soname;
208 : : static bool has_pie_flag;
209 : : static bool has_dt_debug;
210 : : static bool has_symtab;
211 : : static bool has_debug_sections;
212 : : static bool has_modinfo;
213 : : static bool has_gnu_linkonce_this_module;
214 : :
215 : : static bool
216 : 600 : run_classify (void)
217 : : {
218 : : /* Reset to unanalyzed default. */
219 : 600 : elf_type = 0;
220 : 600 : has_program_load = false;
221 : 600 : has_sections = false;
222 : 600 : has_bits_alloc = false;
223 : 600 : has_program_interpreter = false;
224 : 600 : has_dynamic = false;
225 : 600 : has_soname = false;
226 : 600 : has_pie_flag = false;
227 : 600 : has_dt_debug = false;
228 : 600 : has_symtab = false;
229 : 600 : has_debug_sections = false;
230 : 600 : has_modinfo = false;
231 : 600 : has_gnu_linkonce_this_module = false;
232 : :
233 : 600 : int kind = elf_kind (elf);
234 [ - + ]: 600 : if (verbose > 0)
235 : 0 : fprintf (stderr, "info: %s: ELF kind: %s (0x%x)\n", current_path,
236 : : elf_kind_string (kind), kind);
237 [ + + ]: 600 : if (kind != ELF_K_ELF)
238 : : return true;
239 : :
240 : 590 : GElf_Ehdr ehdr_storage;
241 : 590 : GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_storage);
242 [ - + ]: 590 : if (ehdr == NULL)
243 : : {
244 : 0 : elf_issue (N_("ELF header"));
245 : 0 : return false;
246 : : }
247 : 590 : elf_type = ehdr->e_type;
248 : :
249 : : /* Examine program headers. */
250 : 590 : GElf_Phdr dyn_seg = { .p_type = 0 };
251 : : {
252 : 590 : size_t nphdrs;
253 [ - + ]: 590 : if (elf_getphdrnum (elf, &nphdrs) != 0)
254 : : {
255 : 0 : elf_issue (N_("program headers"));
256 : 0 : return false;
257 : : }
258 [ + + ]: 4178 : for (size_t phdr_idx = 0; phdr_idx < nphdrs; ++phdr_idx)
259 : : {
260 : 3588 : GElf_Phdr phdr_storage;
261 : 3588 : GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_storage);
262 [ - + ]: 3588 : if (phdr == NULL)
263 : : {
264 : 0 : elf_issue (N_("program header"));
265 : 0 : return false;
266 : : }
267 [ + + ]: 3588 : if (phdr->p_type == PT_DYNAMIC)
268 : : {
269 : 252 : dyn_seg = *phdr;
270 : 252 : has_dynamic = true;
271 : : }
272 [ + + ]: 3588 : if (phdr->p_type == PT_INTERP)
273 : 132 : has_program_interpreter = true;
274 [ + + ]: 3588 : if (phdr->p_type == PT_LOAD)
275 : 2002 : has_program_load = true;
276 : : }
277 : : }
278 : :
279 : : /* Do we have sections? */
280 : : {
281 : 590 : size_t nshdrs;
282 [ - + ]: 590 : if (elf_getshdrnum (elf, &nshdrs) != 0)
283 : : {
284 : 0 : elf_issue (N_("section headers"));
285 : 0 : return false;
286 : : }
287 [ + + ]: 590 : if (nshdrs > 0)
288 : 470 : has_sections = true;
289 : : }
290 : :
291 : : {
292 : 590 : size_t shstrndx;
293 [ - + ]: 590 : if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
294 : : {
295 : 0 : elf_issue (N_("section header string table index"));
296 : 0 : return false;
297 : : }
298 : :
299 : : Elf_Scn *scn = NULL;
300 : 26822 : while (true)
301 : 13116 : {
302 : 13706 : scn = elf_nextscn (elf, scn);
303 [ + + ]: 13706 : if (scn == NULL)
304 : : break;
305 : 13116 : GElf_Shdr shdr_storage;
306 : 13116 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
307 [ - + ]: 13116 : if (shdr == NULL)
308 : : {
309 : 0 : elf_issue (N_("could not obtain section header"));
310 : 0 : return false;
311 : : }
312 : 13116 : const char *section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
313 [ - + ]: 13116 : if (section_name == NULL)
314 : : {
315 : 0 : elf_issue(N_("could not obtain section name"));
316 : 0 : return false;
317 : : }
318 [ - + ]: 13116 : if (verbose > 2)
319 : 0 : fprintf (stderr, "debug: section header %s (type %d) found\n",
320 : : section_name, shdr->sh_type);
321 [ + + ]: 13116 : if (shdr->sh_type == SHT_SYMTAB)
322 : : {
323 [ - + ]: 430 : if (verbose > 1)
324 : 0 : fputs ("debug: symtab section found\n", stderr);
325 : 430 : has_symtab = true;
326 : : }
327 : : /* NOBITS and NOTE sections can be in any file. We want to be
328 : : sure there is at least one other allocated section. */
329 : 13116 : if (shdr->sh_type != SHT_NOBITS
330 [ + + ]: 13116 : && shdr->sh_type != SHT_NOTE
331 [ + + ]: 10040 : && (shdr->sh_flags & SHF_ALLOC) != 0)
332 : : {
333 [ - + - - ]: 4706 : if (verbose > 1 && !has_bits_alloc)
334 : 0 : fputs ("debug: allocated (non-nobits/note) section found\n",
335 : : stderr);
336 : 4706 : has_bits_alloc = true;
337 : : }
338 : 13116 : const char *debug_prefix = ".debug_";
339 : 13116 : const char *zdebug_prefix = ".zdebug_";
340 [ + + ]: 13116 : if (strncmp (section_name, debug_prefix, strlen (debug_prefix)) == 0
341 [ + + ]: 11248 : || strncmp (section_name, zdebug_prefix,
342 : : strlen (zdebug_prefix)) == 0)
343 : : {
344 [ - + - - ]: 2274 : if (verbose > 1 && !has_debug_sections)
345 : 0 : fputs ("debug: .debug_* section found\n", stderr);
346 : 2274 : has_debug_sections = true;
347 : : }
348 [ + + ]: 13116 : if (strcmp (section_name, ".modinfo") == 0)
349 : : {
350 [ - + ]: 80 : if (verbose > 1)
351 : 0 : fputs ("debug: .modinfo section found\n", stderr);
352 : 80 : has_modinfo = true;
353 : : }
354 [ + + ]: 13116 : if (strcmp (section_name, ".gnu.linkonce.this_module") == 0)
355 : : {
356 [ - + ]: 80 : if (verbose > 1)
357 : 0 : fputs ("debug: .gnu.linkonce.this_module section found\n",
358 : : stderr);
359 : 80 : has_gnu_linkonce_this_module = true;
360 : : }
361 : : }
362 : : }
363 : :
364 : : /* Examine the dynamic section. */
365 [ + + ]: 590 : if (has_dynamic)
366 : : {
367 : 252 : Elf_Data *data = elf_getdata_rawchunk (elf, dyn_seg.p_offset,
368 : : dyn_seg.p_filesz,
369 : : ELF_T_DYN);
370 [ + + ]: 252 : if (data != NULL)
371 : 5270 : for (int dyn_idx = 0; ; ++dyn_idx)
372 : 5270 : {
373 : 5510 : GElf_Dyn dyn_storage;
374 : 5510 : GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage);
375 [ + + ]: 5510 : if (dyn == NULL)
376 : : break;
377 [ - + ]: 5458 : if (verbose > 2)
378 : 5458 : fprintf (stderr, "debug: dynamic entry %d"
379 : : " with tag %llu found\n",
380 : 0 : dyn_idx, (unsigned long long int) dyn->d_tag);
381 [ + + ]: 5458 : if (dyn->d_tag == DT_SONAME)
382 : 16 : has_soname = true;
383 [ + + + - ]: 5458 : if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE))
384 : 32 : has_pie_flag = true;
385 [ + + ]: 5458 : if (dyn->d_tag == DT_DEBUG)
386 : 72 : has_dt_debug = true;
387 [ + + ]: 5458 : if (dyn->d_tag == DT_NULL)
388 : : break;
389 : : }
390 : : }
391 : :
392 [ - + ]: 590 : if (verbose > 0)
393 : : {
394 : 0 : fprintf (stderr, "info: %s: ELF type: %s (0x%x)\n", current_path,
395 : : elf_type_string (elf_type), elf_type);
396 [ # # ]: 0 : if (has_program_load)
397 : 0 : fprintf (stderr, "info: %s: PT_LOAD found\n", current_path);
398 [ # # ]: 0 : if (has_sections)
399 : 0 : fprintf (stderr, "info: %s: has sections\n", current_path);
400 [ # # ]: 0 : if (has_bits_alloc)
401 : 0 : fprintf (stderr, "info: %s: allocated (real) section found\n",
402 : : current_path);
403 [ # # ]: 0 : if (has_program_interpreter)
404 : 0 : fprintf (stderr, "info: %s: program interpreter found\n",
405 : : current_path);
406 [ # # ]: 0 : if (has_dynamic)
407 : 0 : fprintf (stderr, "info: %s: dynamic segment found\n", current_path);
408 [ # # ]: 0 : if (has_soname)
409 : 0 : fprintf (stderr, "info: %s: soname found\n", current_path);
410 [ # # ]: 0 : if (has_pie_flag)
411 : 0 : fprintf (stderr, "info: %s: DF_1_PIE flag found\n", current_path);
412 [ # # ]: 0 : if (has_dt_debug)
413 : 0 : fprintf (stderr, "info: %s: DT_DEBUG found\n", current_path);
414 [ # # ]: 0 : if (has_symtab)
415 : 0 : fprintf (stderr, "info: %s: symbol table found\n", current_path);
416 [ # # ]: 0 : if (has_debug_sections)
417 : 0 : fprintf (stderr, "info: %s: .debug_* section found\n", current_path);
418 [ # # ]: 0 : if (has_modinfo)
419 : 0 : fprintf (stderr, "info: %s: .modinfo section found\n", current_path);
420 [ # # ]: 0 : if (has_gnu_linkonce_this_module)
421 : 0 : fprintf (stderr,
422 : : "info: %s: .gnu.linkonce.this_module section found\n",
423 : : current_path);
424 : : }
425 : :
426 : : return true;
427 : : }
428 : :
429 : : static bool
430 : 600 : is_elf (void)
431 : : {
432 : 600 : return elf_kind (elf) != ELF_K_NONE;
433 : : }
434 : :
435 : : static bool
436 : 600 : is_elf_file (void)
437 : : {
438 : 600 : return elf_kind (elf) == ELF_K_ELF;
439 : : }
440 : :
441 : : static bool
442 : 600 : is_elf_archive (void)
443 : : {
444 : 600 : return elf_kind (elf) == ELF_K_AR;
445 : : }
446 : :
447 : : static bool
448 : 600 : is_core (void)
449 : : {
450 [ + + + + ]: 600 : return elf_kind (elf) == ELF_K_ELF && elf_type == ET_CORE;
451 : : }
452 : :
453 : : /* Return true if the file is a loadable object, which basically means
454 : : it is an ELF file, but not a relocatable object or a core dump
455 : : file. (The kernel and various userspace components can load ET_REL
456 : : files, but we disregard that for our classification purposes.) */
457 : : static bool
458 : 2814 : is_loadable (void)
459 : : {
460 : 2814 : return elf_kind (elf) == ELF_K_ELF
461 [ + + ]: 2774 : && (elf_type == ET_EXEC || elf_type == ET_DYN)
462 [ + - ]: 1582 : && has_program_load
463 [ + + + + : 4396 : && (!has_sections || has_bits_alloc); /* It isn't debug-only. */
+ + ]
464 : : }
465 : :
466 : : /* Return true if the file is an ELF file which has a symbol table or
467 : : .debug_* sections (and thus can be stripped further). */
468 : : static bool
469 : 600 : is_unstripped (void)
470 : : {
471 : 600 : return elf_kind (elf) != ELF_K_NONE
472 [ + + ]: 600 : && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
473 [ + - + + : 1090 : && (has_symtab || has_debug_sections);
+ - ]
474 : : }
475 : :
476 : : /* Return true if the file contains only debuginfo, but no loadable
477 : : program bits. Then it is most likely a separate .debug file, a dwz
478 : : multi-file or a .dwo file. Note that it can still be loadable,
479 : : but in that case the phdrs shouldn't be trusted. */
480 : : static bool
481 : 600 : is_debug_only (void)
482 : : {
483 : 600 : return elf_kind (elf) != ELF_K_NONE
484 [ + + ]: 600 : && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
485 [ + + + + ]: 490 : && (has_debug_sections || has_symtab)
486 [ + - + + ]: 1030 : && !has_bits_alloc;
487 : : }
488 : :
489 : : static bool
490 : 808 : is_shared (void)
491 : : {
492 [ + + ]: 808 : if (!is_loadable ())
493 : : return false;
494 : :
495 : : /* The ELF type is very clear: this is an executable. */
496 [ + + ]: 416 : if (elf_type == ET_EXEC)
497 : : return false;
498 : :
499 : : /* If there is no dynamic section, the file cannot be loaded as a
500 : : shared object. */
501 [ + - ]: 316 : if (!has_dynamic)
502 : : return false;
503 : :
504 : : /* If the object is marked as PIE, it is definitely an executable,
505 : : and not a loadlable shared object. */
506 [ + + ]: 316 : if (has_pie_flag)
507 : : return false;
508 : :
509 : : /* Treat a DT_SONAME tag as a strong indicator that this is a shared
510 : : object. */
511 [ + + ]: 252 : if (has_soname)
512 : : return true;
513 : :
514 : : /* This is probably a PIE program: there is no soname, but a program
515 : : interpreter. In theory, this file could be also a DSO with a
516 : : soname implied by its file name that can be run as a program.
517 : : This situation is impossible to resolve in the general case. */
518 [ + + ]: 220 : if (has_program_interpreter)
519 : : return false;
520 : :
521 : : /* Roland McGrath mentions in
522 : : <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
523 : : that “we defined a PIE as an ET_DYN with a DT_DEBUG”. This
524 : : matches current binutils behavior (version 2.32). DT_DEBUG is
525 : : added if bfd_link_executable returns true or if bfd_link_pic
526 : : returns false, depending on the architectures. However, DT_DEBUG
527 : : is not documented as being specific to executables, therefore use
528 : : it only as a low-priority discriminator. */
529 [ - + ]: 160 : if (has_dt_debug)
530 : 0 : return false;
531 : :
532 : : return true;
533 : : }
534 : :
535 : : static bool
536 : 600 : is_executable (void)
537 : : {
538 [ + + ]: 600 : if (!is_loadable ())
539 : : return false;
540 : :
541 : : /* A loadable object which is not a shared object is treated as an
542 : : executable. */
543 : 208 : return !is_shared ();
544 : : }
545 : :
546 : : /* Like is_executable, but the object can also be a shared library at
547 : : the same time. */
548 : : static bool
549 : 600 : is_program (void)
550 : : {
551 [ + + ]: 600 : if (!is_loadable ())
552 : : return false;
553 : :
554 : : /* The ELF type is very clear: this is an executable. */
555 [ + + ]: 208 : if (elf_type == ET_EXEC)
556 : : return true;
557 : :
558 : : /* If the object is marked as PIE, it is definitely an executable,
559 : : and not a loadlable shared object. */
560 [ + + ]: 158 : if (has_pie_flag)
561 : : return true;
562 : :
563 : : /* This is probably a PIE program. It isn't ET_EXEC, but has a
564 : : program interpreter. In theory, this file could be also a DSO
565 : : with a soname. This situation is impossible to resolve in the
566 : : general case. See is_shared. This is different from
567 : : is_executable. */
568 [ + + ]: 126 : if (has_program_interpreter)
569 : : return true;
570 : :
571 : : /* Roland McGrath mentions in
572 : : <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
573 : : that “we defined a PIE as an ET_DYN with a DT_DEBUG”. This
574 : : matches current binutils behavior (version 2.32). DT_DEBUG is
575 : : added if bfd_link_executable returns true or if bfd_link_pic
576 : : returns false, depending on the architectures. However, DT_DEBUG
577 : : is not documented as being specific to executables, therefore use
578 : : it only as a low-priority discriminator. */
579 [ - + ]: 96 : if (has_dt_debug)
580 : 0 : return true;
581 : :
582 : : return false;
583 : : }
584 : :
585 : : /* Like is_shared but the library could also be an executable. */
586 : : static bool
587 : 600 : is_library (void)
588 : : {
589 : : /* Only ET_DYN can be shared libraries. */
590 [ + + ]: 600 : if (elf_type != ET_DYN)
591 : : return false;
592 : :
593 [ + + ]: 206 : if (!is_loadable ())
594 : : return false;
595 : :
596 : : /* Without a PT_DYNAMIC segment the library cannot be loaded. */
597 [ + - ]: 158 : if (!has_dynamic)
598 : : return false;
599 : :
600 : : /* This really is a (PIE) executable. See is_shared. */
601 [ + + + + ]: 158 : if (has_pie_flag || has_dt_debug)
602 : 62 : return false;
603 : :
604 : : /* It could still (also) be a (PIE) executable, but most likely you
605 : : can dlopen it just fine. */
606 : : return true;
607 : : }
608 : :
609 : : /* Returns true if the file is a linux kernel module (is ET_REL and
610 : : has the two magic sections .modinfo and .gnu.linkonce.this_module). */
611 : : static bool
612 : 600 : is_linux_kernel_module (void)
613 : : {
614 : 600 : return (elf_kind (elf) == ELF_K_ELF
615 [ + + ]: 590 : && elf_type == ET_REL
616 [ + + ]: 198 : && has_modinfo
617 [ + + - + ]: 680 : && has_gnu_linkonce_this_module);
618 : : }
619 : :
620 : : enum classify_requirement { do_not_care, required, forbidden };
621 : :
622 : : enum classify_check
623 : : {
624 : : classify_elf,
625 : : classify_elf_file,
626 : : classify_elf_archive,
627 : : classify_core,
628 : : classify_unstripped,
629 : : classify_executable,
630 : : classify_program,
631 : : classify_shared,
632 : : classify_library,
633 : : classify_linux_kernel_module,
634 : : classify_debug_only,
635 : : classify_loadable,
636 : :
637 : : classify_check_last = classify_loadable
638 : : };
639 : :
640 : : enum
641 : : {
642 : : classify_check_offset = 1000,
643 : : classify_check_not_offset = 2000,
644 : :
645 : : classify_flag_stdin = 3000,
646 : : classify_flag_stdin0,
647 : : classify_flag_no_stdin,
648 : : classify_flag_print,
649 : : classify_flag_print0,
650 : : classify_flag_no_print,
651 : : classify_flag_matching,
652 : : classify_flag_not_matching,
653 : : };
654 : :
655 : : static bool
656 : 842 : classify_check_positive (int key)
657 : : {
658 : 842 : return key >= classify_check_offset
659 : 842 : && key <= classify_check_offset + classify_check_last;
660 : : }
661 : :
662 : : static bool
663 : 782 : classify_check_negative (int key)
664 : : {
665 : 782 : return key >= classify_check_not_offset
666 : 782 : && key <= classify_check_not_offset + classify_check_last;
667 : : }
668 : :
669 : : /* Set by parse_opt. */
670 : : static enum classify_requirement requirements[classify_check_last + 1];
671 : : static enum { no_stdin, do_stdin, do_stdin0 } flag_stdin;
672 : : static enum { no_print, do_print, do_print0 } flag_print;
673 : : static bool flag_print_matching = true;
674 : :
675 : : static error_t
676 : 842 : parse_opt (int key, char *arg __attribute__ ((unused)),
677 : : struct argp_state *state __attribute__ ((unused)))
678 : : {
679 [ + + ]: 842 : if (classify_check_positive (key))
680 : 60 : requirements[key - classify_check_offset] = required;
681 [ + + ]: 782 : else if (classify_check_negative (key))
682 : 74 : requirements[key - classify_check_not_offset] = forbidden;
683 : : else
684 [ - - - - : 708 : switch (key)
- - - + -
- - - + ]
685 : : {
686 : 0 : case 'v':
687 : 0 : ++verbose;
688 : 0 : break;
689 : :
690 : 0 : case 'q':
691 : 0 : --verbose;
692 : 0 : break;
693 : :
694 : 0 : case 'z':
695 : 0 : flag_compressed = true;
696 : 0 : break;
697 : :
698 : 0 : case 'f':
699 : 0 : flag_only_regular_files = true;
700 : 0 : break;
701 : :
702 : 0 : case classify_flag_stdin:
703 : 0 : flag_stdin = do_stdin;
704 : 0 : break;
705 : :
706 : 0 : case classify_flag_stdin0:
707 : 0 : flag_stdin = do_stdin0;
708 : 0 : break;
709 : :
710 : 0 : case classify_flag_no_stdin:
711 : 0 : flag_stdin = no_stdin;
712 : 0 : break;
713 : :
714 : 38 : case classify_flag_print:
715 : 38 : flag_print = do_print;
716 : 38 : break;
717 : :
718 : 0 : case classify_flag_print0:
719 : 0 : flag_print = do_print0;
720 : 0 : break;
721 : :
722 : 0 : case classify_flag_no_print:
723 : 0 : flag_print = no_print;
724 : 0 : break;
725 : :
726 : 0 : case classify_flag_matching:
727 : 0 : flag_print_matching = true;
728 : 0 : break;
729 : :
730 : 0 : case classify_flag_not_matching:
731 : 0 : flag_print_matching = false;
732 : 0 : break;
733 : :
734 : : default:
735 : : return ARGP_ERR_UNKNOWN;
736 : : }
737 : :
738 : : return 0;
739 : : }
740 : :
741 : : /* Perform requested checks against the file at current_path. If
742 : : necessary, sets *STATUS to 1 if checks failed. */
743 : : static void
744 : 600 : process_current_path (int *status)
745 : : {
746 : 600 : bool checks_passed = true;
747 : :
748 [ + - + - ]: 600 : if (open_elf () && run_classify ())
749 : 600 : {
750 : 600 : bool checks[] =
751 : : {
752 : : [classify_elf] = is_elf (),
753 : : [classify_elf_file] = is_elf_file (),
754 : : [classify_elf_archive] = is_elf_archive (),
755 : 600 : [classify_core] = is_core (),
756 : 600 : [classify_unstripped] = is_unstripped (),
757 : 600 : [classify_executable] = is_executable (),
758 : 600 : [classify_program] = is_program (),
759 : 600 : [classify_shared] = is_shared (),
760 : 600 : [classify_library] = is_library (),
761 : 600 : [classify_linux_kernel_module] = is_linux_kernel_module (),
762 : 600 : [classify_debug_only] = is_debug_only (),
763 : 600 : [classify_loadable] = is_loadable (),
764 : : };
765 : :
766 [ - + ]: 600 : if (verbose > 1)
767 : : {
768 [ # # ]: 0 : if (checks[classify_elf])
769 : 0 : fprintf (stderr, "debug: %s: elf\n", current_path);
770 [ # # ]: 0 : if (checks[classify_elf_file])
771 : 0 : fprintf (stderr, "debug: %s: elf_file\n", current_path);
772 [ # # ]: 0 : if (checks[classify_elf_archive])
773 : 0 : fprintf (stderr, "debug: %s: elf_archive\n", current_path);
774 [ # # ]: 0 : if (checks[classify_core])
775 : 0 : fprintf (stderr, "debug: %s: core\n", current_path);
776 [ # # ]: 0 : if (checks[classify_unstripped])
777 : 0 : fprintf (stderr, "debug: %s: unstripped\n", current_path);
778 [ # # ]: 0 : if (checks[classify_executable])
779 : 0 : fprintf (stderr, "debug: %s: executable\n", current_path);
780 [ # # ]: 0 : if (checks[classify_program])
781 : 0 : fprintf (stderr, "debug: %s: program\n", current_path);
782 [ # # ]: 0 : if (checks[classify_shared])
783 : 0 : fprintf (stderr, "debug: %s: shared\n", current_path);
784 [ # # ]: 0 : if (checks[classify_library])
785 : 0 : fprintf (stderr, "debug: %s: library\n", current_path);
786 [ # # ]: 0 : if (checks[classify_linux_kernel_module])
787 : 0 : fprintf (stderr, "debug: %s: linux kernel module\n", current_path);
788 [ # # ]: 0 : if (checks[classify_debug_only])
789 : 0 : fprintf (stderr, "debug: %s: debug-only\n", current_path);
790 [ # # ]: 0 : if (checks[classify_loadable])
791 : 0 : fprintf (stderr, "debug: %s: loadable\n", current_path);
792 : : }
793 : :
794 : 600 : for (enum classify_check check = 0;
795 [ + + ]: 7800 : check <= classify_check_last; ++check)
796 [ + + + ]: 7200 : switch (requirements[check])
797 : : {
798 : 856 : case required:
799 [ - + ]: 856 : if (!checks[check])
800 : 0 : checks_passed = false;
801 : : break;
802 : 344 : case forbidden:
803 [ - + ]: 344 : if (checks[check])
804 : 0 : checks_passed = false;
805 : : break;
806 : : case do_not_care:
807 : : break;
808 : : }
809 : 7200 : }
810 [ # # ]: 0 : else if (file_fd == -1)
811 : : checks_passed = false; /* There is nothing to check, bad file. */
812 : : else
813 : : {
814 : 0 : for (enum classify_check check = 0;
815 [ # # ]: 0 : check <= classify_check_last; ++check)
816 [ # # ]: 0 : if (requirements[check] == required)
817 : 0 : checks_passed = false;
818 : : }
819 : :
820 : 600 : close_elf ();
821 : :
822 [ + - + - ]: 600 : switch (flag_print)
823 : : {
824 : 270 : case do_print:
825 [ + - ]: 270 : if (checks_passed == flag_print_matching)
826 : 270 : puts (current_path);
827 : : break;
828 : 0 : case do_print0:
829 [ # # ]: 0 : if (checks_passed == flag_print_matching)
830 [ # # ]: 0 : if (fwrite (current_path, strlen (current_path) + 1, 1, stdout) < 1)
831 : 0 : issue (errno, N_("writing to standard output"));
832 : : break;
833 : 330 : case no_print:
834 [ - + ]: 330 : if (!checks_passed)
835 : 0 : *status = 1;
836 : : break;
837 : : }
838 : 600 : }
839 : :
840 : : /* Called to process standard input if flag_stdin is not no_stdin. */
841 : : static void
842 : 0 : process_stdin (int *status)
843 : : {
844 : 0 : char delim;
845 [ # # ]: 0 : if (flag_stdin == do_stdin0)
846 : : delim = '\0';
847 : : else
848 : 0 : delim = '\n';
849 : :
850 : 0 : char *buffer = NULL;
851 : 0 : size_t buffer_size = 0;
852 : 0 : while (true)
853 : 0 : {
854 : 0 : ssize_t ret = getdelim (&buffer, &buffer_size, delim, stdin);
855 [ # # ]: 0 : if (ferror (stdin))
856 : : {
857 : 0 : current_path = NULL;
858 : 0 : issue (errno, N_("reading from standard input"));
859 : 0 : break;
860 : : }
861 [ # # ]: 0 : if (feof (stdin))
862 : : break;
863 [ # # ]: 0 : if (ret < 0)
864 : 0 : abort (); /* Cannot happen due to error checks above. */
865 [ # # # # ]: 0 : if (delim != '\0' && ret > 0 && buffer[ret - 1] == '\n')
866 : 0 : buffer[ret - 1] = '\0';
867 : 0 : current_path = buffer;
868 : 0 : process_current_path (status);
869 : : }
870 : :
871 : 0 : free (buffer);
872 : 0 : }
873 : :
874 : : int
875 : 134 : main (int argc, char **argv)
876 : : {
877 : 134 : const struct argp_option options[] =
878 : : {
879 : : { NULL, 0, NULL, OPTION_DOC, N_("Classification options"), 1 },
880 : : { "elf", classify_check_offset + classify_elf, NULL, 0,
881 : : N_("File looks like an ELF object or archive/static library (default)")
882 : : , 1 },
883 : : { "elf-file", classify_check_offset + classify_elf_file, NULL, 0,
884 : : N_("File is an regular ELF object (not an archive/static library)")
885 : : , 1 },
886 : : { "elf-archive", classify_check_offset + classify_elf_archive, NULL, 0,
887 : : N_("File is an ELF archive or static library")
888 : : , 1 },
889 : : { "core", classify_check_offset + classify_core, NULL, 0,
890 : : N_("File is an ELF core dump file")
891 : : , 1 },
892 : : { "unstripped", classify_check_offset + classify_unstripped, NULL, 0,
893 : : N_("File is an ELF file with symbol table or .debug_* sections \
894 : : and can be stripped further"), 1 },
895 : : { "executable", classify_check_offset + classify_executable, NULL, 0,
896 : : N_("File is (primarily) an ELF program executable \
897 : : (not primarily a DSO)"), 1 },
898 : : { "program", classify_check_offset + classify_program, NULL, 0,
899 : : N_("File is an ELF program executable \
900 : : (might also be a DSO)"), 1 },
901 : : { "shared", classify_check_offset + classify_shared, NULL, 0,
902 : : N_("File is (primarily) an ELF shared object (DSO) \
903 : : (not primarily an executable)"), 1 },
904 : : { "library", classify_check_offset + classify_library, NULL, 0,
905 : : N_("File is an ELF shared object (DSO) \
906 : : (might also be an executable)"), 1 },
907 : : { "linux-kernel-module", (classify_check_offset
908 : : + classify_linux_kernel_module), NULL, 0,
909 : : N_("File is a linux kernel module"), 1 },
910 : : { "debug-only", (classify_check_offset + classify_debug_only), NULL, 0,
911 : : N_("File is a debug only ELF file \
912 : : (separate .debug, .dwo or dwz multi-file)"), 1 },
913 : : { "loadable", classify_check_offset + classify_loadable, NULL, 0,
914 : : N_("File is a loadable ELF object (program or shared object)"), 1 },
915 : :
916 : : /* Negated versions of the above. */
917 : : { "not-elf", classify_check_not_offset + classify_elf,
918 : : NULL, OPTION_HIDDEN, NULL, 1 },
919 : : { "not-elf-file", classify_check_not_offset + classify_elf_file,
920 : : NULL, OPTION_HIDDEN, NULL, 1 },
921 : : { "not-elf-archive", classify_check_not_offset + classify_elf_archive,
922 : : NULL, OPTION_HIDDEN, NULL, 1 },
923 : : { "not-core", classify_check_not_offset + classify_core,
924 : : NULL, OPTION_HIDDEN, NULL, 1 },
925 : : { "not-unstripped", classify_check_not_offset + classify_unstripped,
926 : : NULL, OPTION_HIDDEN, NULL, 1 },
927 : : { "not-executable", classify_check_not_offset + classify_executable,
928 : : NULL, OPTION_HIDDEN, NULL, 1 },
929 : : { "not-program", classify_check_not_offset + classify_program,
930 : : NULL, OPTION_HIDDEN, NULL, 1 },
931 : : { "not-shared", classify_check_not_offset + classify_shared,
932 : : NULL, OPTION_HIDDEN, NULL, 1 },
933 : : { "not-library", classify_check_not_offset + classify_library,
934 : : NULL, OPTION_HIDDEN, NULL, 1 },
935 : : { "not-linux-kernel-module", (classify_check_not_offset
936 : : + classify_linux_kernel_module),
937 : : NULL, OPTION_HIDDEN, NULL, 1 },
938 : : { "not-debug-only", (classify_check_not_offset + classify_debug_only),
939 : : NULL, OPTION_HIDDEN, NULL, 1 },
940 : : { "not-loadable", classify_check_not_offset + classify_loadable,
941 : : NULL, OPTION_HIDDEN, NULL, 1 },
942 : :
943 : : { NULL, 0, NULL, OPTION_DOC, N_("Input flags"), 2 },
944 : : { "file", 'f', NULL, 0,
945 : : N_("Only classify regular (not symlink nor special device) files"), 2 },
946 : : { "stdin", classify_flag_stdin, NULL, 0,
947 : : N_("Also read file names to process from standard input, \
948 : : separated by newlines"), 2 },
949 : : { "stdin0", classify_flag_stdin0, NULL, 0,
950 : : N_("Also read file names to process from standard input, \
951 : : separated by ASCII NUL bytes"), 2 },
952 : : { "no-stdin", classify_flag_stdin, NULL, 0,
953 : : N_("Do not read files from standard input (default)"), 2 },
954 : : { "compressed", 'z', NULL, 0,
955 : : N_("Try to open compressed files or embedded (kernel) ELF images"),
956 : : 2 },
957 : :
958 : : { NULL, 0, NULL, OPTION_DOC, N_("Output flags"), 3 },
959 : : { "print", classify_flag_print, NULL, 0,
960 : : N_("Output names of files, separated by newline"), 3 },
961 : : { "print0", classify_flag_print0, NULL, 0,
962 : : N_("Output names of files, separated by ASCII NUL"), 3 },
963 : : { "no-print", classify_flag_no_print, NULL, 0,
964 : : N_("Do not output file names"), 3 },
965 : : { "matching", classify_flag_matching, NULL, 0,
966 : : N_("If printing file names, print matching files (default)"), 3 },
967 : : { "not-matching", classify_flag_not_matching, NULL, 0,
968 : : N_("If printing file names, print files that do not match"), 3 },
969 : :
970 : : { NULL, 0, NULL, OPTION_DOC, N_("Additional flags"), 4 },
971 : : { "verbose", 'v', NULL, 0,
972 : : N_("Output additional information (can be specified multiple times)"), 4 },
973 : : { "quiet", 'q', NULL, 0,
974 : : N_("Suppress some error output (counterpart to --verbose)"), 4 },
975 : : { NULL, 0, NULL, 0, NULL, 0 }
976 : : };
977 : :
978 : 134 : const struct argp argp =
979 : : {
980 : : .options = options,
981 : : .parser = parse_opt,
982 : : .args_doc = N_("FILE..."),
983 : : .doc = N_("\
984 : : Determine the type of an ELF file.\
985 : : \n\n\
986 : : All of the classification options must apply at the same time to a \
987 : : particular file. Classification options can be negated using a \
988 : : \"--not-\" prefix.\
989 : : \n\n\
990 : : Since modern ELF does not clearly distinguish between programs and \
991 : : dynamic shared objects, you should normally use either --executable or \
992 : : --shared to identify the primary purpose of a file. \
993 : : Only one of the --shared and --executable checks can pass for a file.\
994 : : \n\n\
995 : : If you want to know whether an ELF object might a program or a \
996 : : shared library (but could be both), then use --program or --library. \
997 : : Some ELF files will classify as both a program and a library.\
998 : : \n\n\
999 : : If you just want to know whether an ELF file is loadable (as program \
1000 : : or library) use --loadable. Note that files that only contain \
1001 : : (separate) debug information (--debug-only) are never --loadable (even \
1002 : : though they might contain program headers). Linux kernel modules are \
1003 : : also not --loadable (in the normal sense).\
1004 : : \n\n\
1005 : : Without any of the --print options, the program exits with status 0 \
1006 : : if the requested checks pass for all input files, with 1 if a check \
1007 : : fails for any file, and 2 if there is an environmental issue (such \
1008 : : as a file read error or a memory allocation error).\
1009 : : \n\n\
1010 : : When printing file names, the program exits with status 0 even if \
1011 : : no file names are printed, and exits with status 2 if there is an \
1012 : : environmental issue.\
1013 : : \n\n\
1014 : : On usage error (e.g. a bad option was given), the program exits with \
1015 : : a status code larger than 2.\
1016 : : \n\n\
1017 : : The --quiet or -q option suppresses some error warning output, but \
1018 : : doesn't change the exit status.\
1019 : : ")
1020 : : };
1021 : :
1022 : : /* Require that the file is an ELF file by default. User can
1023 : : disable with --not-elf. */
1024 : 134 : requirements[classify_elf] = required;
1025 : :
1026 : 134 : int remaining;
1027 [ + - ]: 134 : if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
1028 : : return 2;
1029 : :
1030 : 134 : elf_version (EV_CURRENT);
1031 : :
1032 : 134 : int status = 0;
1033 : :
1034 [ + + ]: 734 : for (int i = remaining; i < argc; ++i)
1035 : : {
1036 : 600 : current_path = argv[i];
1037 : 600 : process_current_path (&status);
1038 : : }
1039 : :
1040 [ - + ]: 134 : if (flag_stdin != no_stdin)
1041 : 0 : process_stdin (&status);
1042 : :
1043 [ + - ]: 134 : if (issue_found)
1044 : : return 2;
1045 : :
1046 : 134 : return status;
1047 : : }
|