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 occured 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 occured 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 600 : 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 : close_file (void)
112 : {
113 600 : if (file_fd >= 0)
114 : {
115 600 : close (file_fd);
116 600 : file_fd = -1;
117 : }
118 : }
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 : 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 : 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 4274 : for (size_t phdr_idx = 0; phdr_idx < nphdrs; ++phdr_idx)
259 : {
260 3684 : GElf_Phdr phdr_storage;
261 3684 : GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_storage);
262 3684 : if (phdr == NULL)
263 : {
264 0 : elf_issue (N_("program header"));
265 0 : return false;
266 : }
267 3684 : if (phdr->p_type == PT_DYNAMIC)
268 : {
269 252 : dyn_seg = *phdr;
270 252 : has_dynamic = true;
271 : }
272 3684 : if (phdr->p_type == PT_INTERP)
273 132 : has_program_interpreter = true;
274 3684 : if (phdr->p_type == PT_LOAD)
275 2098 : 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 13784 : while (true)
301 13194 : {
302 13784 : scn = elf_nextscn (elf, scn);
303 13784 : if (scn == NULL)
304 : break;
305 13194 : GElf_Shdr shdr_storage;
306 13194 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
307 13194 : if (shdr == NULL)
308 : {
309 0 : elf_issue (N_("could not obtain section header"));
310 0 : return false;
311 : }
312 13194 : const char *section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
313 13194 : if (section_name == NULL)
314 : {
315 0 : elf_issue(N_("could not obtain section name"));
316 0 : return false;
317 : }
318 13194 : if (verbose > 2)
319 0 : fprintf (stderr, "debug: section header %s (type %d) found\n",
320 : section_name, shdr->sh_type);
321 13194 : 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 26388 : if (shdr->sh_type != SHT_NOBITS
330 13194 : && shdr->sh_type != SHT_NOTE
331 10118 : && (shdr->sh_flags & SHF_ALLOC) != 0)
332 : {
333 4772 : if (verbose > 1 && !has_bits_alloc)
334 0 : fputs ("debug: allocated (non-nobits/note) section found\n",
335 : stderr);
336 4772 : has_bits_alloc = true;
337 : }
338 13194 : const char *debug_prefix = ".debug_";
339 13194 : const char *zdebug_prefix = ".zdebug_";
340 13194 : if (strncmp (section_name, debug_prefix, strlen (debug_prefix)) == 0
341 11326 : || 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 13194 : 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 13194 : 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 5262 : for (int dyn_idx = 0; ; ++dyn_idx)
372 5262 : {
373 5502 : GElf_Dyn dyn_storage;
374 5502 : GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage);
375 5502 : if (dyn == NULL)
376 : break;
377 5450 : if (verbose > 2)
378 0 : fprintf (stderr, "debug: dynamic entry %d"
379 : " with tag %llu found\n",
380 0 : dyn_idx, (unsigned long long int) dyn->d_tag);
381 5450 : if (dyn->d_tag == DT_SONAME)
382 16 : has_soname = true;
383 5450 : if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE))
384 32 : has_pie_flag = true;
385 5450 : if (dyn->d_tag == DT_DEBUG)
386 72 : has_dt_debug = true;
387 5450 : 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 : is_elf (void)
431 : {
432 600 : return elf_kind (elf) != ELF_K_NONE;
433 : }
434 :
435 : static bool
436 : is_elf_file (void)
437 : {
438 600 : return elf_kind (elf) == ELF_K_ELF;
439 : }
440 :
441 : static bool
442 : is_elf_archive (void)
443 : {
444 600 : return elf_kind (elf) == ELF_K_AR;
445 : }
446 :
447 : static bool
448 : is_core (void)
449 : {
450 590 : 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 futher). */
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 : 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 : 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 7800 : bool checks[] =
751 : {
752 600 : [classify_elf] = is_elf (),
753 600 : [classify_elf_file] = is_elf_file (),
754 600 : [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 7800 : for (enum classify_check check = 0;
795 7200 : 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 : fwrite (current_path, strlen (current_path) + 1, 1, stdout);
831 : break;
832 330 : case no_print:
833 330 : if (!checks_passed)
834 0 : *status = 1;
835 : break;
836 : }
837 600 : }
838 :
839 : /* Called to process standard input if flag_stdin is not no_stdin. */
840 : static void
841 0 : process_stdin (int *status)
842 : {
843 0 : char delim;
844 0 : if (flag_stdin == do_stdin0)
845 : delim = '\0';
846 : else
847 0 : delim = '\n';
848 :
849 0 : char *buffer = NULL;
850 0 : size_t buffer_size = 0;
851 0 : while (true)
852 0 : {
853 0 : ssize_t ret = getdelim (&buffer, &buffer_size, delim, stdin);
854 0 : if (ferror (stdin))
855 : {
856 0 : current_path = NULL;
857 0 : issue (errno, N_("reading from standard input"));
858 0 : break;
859 : }
860 0 : if (feof (stdin))
861 : break;
862 0 : if (ret < 0)
863 0 : abort (); /* Cannot happen due to error checks above. */
864 0 : if (delim != '\0' && ret > 0 && buffer[ret - 1] == '\n')
865 0 : buffer[ret - 1] = '\0';
866 0 : current_path = buffer;
867 0 : process_current_path (status);
868 : }
869 :
870 0 : free (buffer);
871 0 : }
872 :
873 : int
874 134 : main (int argc, char **argv)
875 : {
876 134 : const struct argp_option options[] =
877 : {
878 : { NULL, 0, NULL, OPTION_DOC, N_("Classification options"), 1 },
879 : { "elf", classify_check_offset + classify_elf, NULL, 0,
880 : N_("File looks like an ELF object or archive/static library (default)")
881 : , 1 },
882 : { "elf-file", classify_check_offset + classify_elf_file, NULL, 0,
883 : N_("File is an regular ELF object (not an archive/static library)")
884 : , 1 },
885 : { "elf-archive", classify_check_offset + classify_elf_archive, NULL, 0,
886 : N_("File is an ELF archive or static library")
887 : , 1 },
888 : { "core", classify_check_offset + classify_core, NULL, 0,
889 : N_("File is an ELF core dump file")
890 : , 1 },
891 : { "unstripped", classify_check_offset + classify_unstripped, NULL, 0,
892 : N_("File is an ELF file with symbol table or .debug_* sections \
893 : and can be stripped further"), 1 },
894 : { "executable", classify_check_offset + classify_executable, NULL, 0,
895 : N_("File is (primarily) an ELF program executable \
896 : (not primarily a DSO)"), 1 },
897 : { "program", classify_check_offset + classify_program, NULL, 0,
898 : N_("File is an ELF program executable \
899 : (might also be a DSO)"), 1 },
900 : { "shared", classify_check_offset + classify_shared, NULL, 0,
901 : N_("File is (primarily) an ELF shared object (DSO) \
902 : (not primarily an executable)"), 1 },
903 : { "library", classify_check_offset + classify_library, NULL, 0,
904 : N_("File is an ELF shared object (DSO) \
905 : (might also be an executable)"), 1 },
906 : { "linux-kernel-module", (classify_check_offset
907 : + classify_linux_kernel_module), NULL, 0,
908 : N_("File is a linux kernel module"), 1 },
909 : { "debug-only", (classify_check_offset + classify_debug_only), NULL, 0,
910 : N_("File is a debug only ELF file \
911 : (separate .debug, .dwo or dwz multi-file)"), 1 },
912 : { "loadable", classify_check_offset + classify_loadable, NULL, 0,
913 : N_("File is a loadable ELF object (program or shared object)"), 1 },
914 :
915 : /* Negated versions of the above. */
916 : { "not-elf", classify_check_not_offset + classify_elf,
917 : NULL, OPTION_HIDDEN, NULL, 1 },
918 : { "not-elf-file", classify_check_not_offset + classify_elf_file,
919 : NULL, OPTION_HIDDEN, NULL, 1 },
920 : { "not-elf-archive", classify_check_not_offset + classify_elf_archive,
921 : NULL, OPTION_HIDDEN, NULL, 1 },
922 : { "not-core", classify_check_not_offset + classify_core,
923 : NULL, OPTION_HIDDEN, NULL, 1 },
924 : { "not-unstripped", classify_check_not_offset + classify_unstripped,
925 : NULL, OPTION_HIDDEN, NULL, 1 },
926 : { "not-executable", classify_check_not_offset + classify_executable,
927 : NULL, OPTION_HIDDEN, NULL, 1 },
928 : { "not-program", classify_check_not_offset + classify_program,
929 : NULL, OPTION_HIDDEN, NULL, 1 },
930 : { "not-shared", classify_check_not_offset + classify_shared,
931 : NULL, OPTION_HIDDEN, NULL, 1 },
932 : { "not-library", classify_check_not_offset + classify_library,
933 : NULL, OPTION_HIDDEN, NULL, 1 },
934 : { "not-linux-kernel-module", (classify_check_not_offset
935 : + classify_linux_kernel_module),
936 : NULL, OPTION_HIDDEN, NULL, 1 },
937 : { "not-debug-only", (classify_check_not_offset + classify_debug_only),
938 : NULL, OPTION_HIDDEN, NULL, 1 },
939 : { "not-loadable", classify_check_not_offset + classify_loadable,
940 : NULL, OPTION_HIDDEN, NULL, 1 },
941 :
942 : { NULL, 0, NULL, OPTION_DOC, N_("Input flags"), 2 },
943 : { "file", 'f', NULL, 0,
944 : N_("Only classify regular (not symlink nor special device) files"), 2 },
945 : { "stdin", classify_flag_stdin, NULL, 0,
946 : N_("Also read file names to process from standard input, \
947 : separated by newlines"), 2 },
948 : { "stdin0", classify_flag_stdin0, NULL, 0,
949 : N_("Also read file names to process from standard input, \
950 : separated by ASCII NUL bytes"), 2 },
951 : { "no-stdin", classify_flag_stdin, NULL, 0,
952 : N_("Do not read files from standard input (default)"), 2 },
953 : { "compressed", 'z', NULL, 0,
954 : N_("Try to open compressed files or embedded (kernel) ELF images"),
955 : 2 },
956 :
957 : { NULL, 0, NULL, OPTION_DOC, N_("Output flags"), 3 },
958 : { "print", classify_flag_print, NULL, 0,
959 : N_("Output names of files, separated by newline"), 3 },
960 : { "print0", classify_flag_print0, NULL, 0,
961 : N_("Output names of files, separated by ASCII NUL"), 3 },
962 : { "no-print", classify_flag_no_print, NULL, 0,
963 : N_("Do not output file names"), 3 },
964 : { "matching", classify_flag_matching, NULL, 0,
965 : N_("If printing file names, print matching files (default)"), 3 },
966 : { "not-matching", classify_flag_not_matching, NULL, 0,
967 : N_("If printing file names, print files that do not match"), 3 },
968 :
969 : { NULL, 0, NULL, OPTION_DOC, N_("Additional flags"), 4 },
970 : { "verbose", 'v', NULL, 0,
971 : N_("Output additional information (can be specified multiple times)"), 4 },
972 : { "quiet", 'q', NULL, 0,
973 : N_("Suppress some error output (counterpart to --verbose)"), 4 },
974 : { NULL, 0, NULL, 0, NULL, 0 }
975 : };
976 :
977 134 : const struct argp argp =
978 : {
979 : .options = options,
980 : .parser = parse_opt,
981 : .args_doc = N_("FILE..."),
982 : .doc = N_("\
983 : Determine the type of an ELF file.\
984 : \n\n\
985 : All of the classification options must apply at the same time to a \
986 : particular file. Classification options can be negated using a \
987 : \"--not-\" prefix.\
988 : \n\n\
989 : Since modern ELF does not clearly distinguish between programs and \
990 : dynamic shared objects, you should normally use either --executable or \
991 : --shared to identify the primary purpose of a file. \
992 : Only one of the --shared and --executable checks can pass for a file.\
993 : \n\n\
994 : If you want to know whether an ELF object might a program or a \
995 : shared library (but could be both), then use --program or --library. \
996 : Some ELF files will classify as both a program and a library.\
997 : \n\n\
998 : If you just want to know whether an ELF file is loadable (as program \
999 : or library) use --loadable. Note that files that only contain \
1000 : (separate) debug information (--debug-only) are never --loadable (even \
1001 : though they might contain program headers). Linux kernel modules are \
1002 : also not --loadable (in the normal sense).\
1003 : \n\n\
1004 : Without any of the --print options, the program exits with status 0 \
1005 : if the requested checks pass for all input files, with 1 if a check \
1006 : fails for any file, and 2 if there is an environmental issue (such \
1007 : as a file read error or a memory allocation error).\
1008 : \n\n\
1009 : When printing file names, the program exits with status 0 even if \
1010 : no file names are printed, and exits with status 2 if there is an \
1011 : environmental issue.\
1012 : \n\n\
1013 : On usage error (e.g. a bad option was given), the program exits with \
1014 : a status code larger than 2.\
1015 : \n\n\
1016 : The --quiet or -q option suppresses some error warning output, but \
1017 : doesn't change the exit status.\
1018 : ")
1019 : };
1020 :
1021 : /* Require that the file is an ELF file by default. User can
1022 : disable with --not-elf. */
1023 134 : requirements[classify_elf] = required;
1024 :
1025 134 : int remaining;
1026 134 : if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
1027 : return 2;
1028 :
1029 134 : elf_version (EV_CURRENT);
1030 :
1031 134 : int status = 0;
1032 :
1033 734 : for (int i = remaining; i < argc; ++i)
1034 : {
1035 600 : current_path = argv[i];
1036 600 : process_current_path (&status);
1037 : }
1038 :
1039 134 : if (flag_stdin != no_stdin)
1040 0 : process_stdin (&status);
1041 :
1042 134 : if (issue_found)
1043 : return 2;
1044 :
1045 134 : return status;
1046 : }
|