| 1 | /* |
1 | /* |
| 2 | * Copyright 2003 Ned Ludd <solar@gentoo.org> |
2 | * Copyright 2003 Ned Ludd <solar@gentoo.org> |
| 3 | * Copyright 1999-2005 Gentoo Foundation |
3 | * Copyright 1999-2005 Gentoo Foundation |
| 4 | * Distributed under the terms of the GNU General Public License v2 |
4 | * Distributed under the terms of the GNU General Public License v2 |
| 5 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.26 2005/04/05 00:51:33 vapier Exp $ |
5 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.27 2005/04/05 01:44:08 vapier Exp $ |
| 6 | * |
6 | * |
| 7 | ******************************************************************** |
7 | ******************************************************************** |
| 8 | * This program is free software; you can redistribute it and/or |
8 | * This program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public License as |
9 | * modify it under the terms of the GNU General Public License as |
| 10 | * published by the Free Software Foundation; either version 2 of the |
10 | * published by the Free Software Foundation; either version 2 of the |
| … | |
… | |
| 32 | #include <getopt.h> |
32 | #include <getopt.h> |
| 33 | #include <assert.h> |
33 | #include <assert.h> |
| 34 | |
34 | |
| 35 | #include "paxelf.h" |
35 | #include "paxelf.h" |
| 36 | |
36 | |
| 37 | static const char *rcsid = "$Id: scanelf.c,v 1.26 2005/04/05 00:51:33 vapier Exp $"; |
37 | static const char *rcsid = "$Id: scanelf.c,v 1.27 2005/04/05 01:44:08 vapier Exp $"; |
| 38 | |
38 | |
| 39 | |
39 | |
| 40 | /* helper functions for showing errors */ |
40 | /* helper functions for showing errors */ |
| 41 | #define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/ |
41 | #define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/ |
| 42 | #define warn(fmt, args...) \ |
42 | #define warn(fmt, args...) \ |
| … | |
… | |
| 68 | static char show_textrel = 0; |
68 | static char show_textrel = 0; |
| 69 | static char show_rpath = 0; |
69 | static char show_rpath = 0; |
| 70 | static char show_banner = 1; |
70 | static char show_banner = 1; |
| 71 | static char be_quiet = 0; |
71 | static char be_quiet = 0; |
| 72 | static char be_verbose = 0; |
72 | static char be_verbose = 0; |
|
|
73 | static char *find_sym = NULL; |
| 73 | |
74 | |
| 74 | |
75 | |
| 75 | |
76 | |
| 76 | /* scan an elf file and show all the fun stuff */ |
77 | /* scan an elf file and show all the fun stuff */ |
| 77 | static void scanelf_file(const char *filename) |
78 | static void scanelf_file(const char *filename) |
| 78 | { |
79 | { |
| 79 | int i; |
80 | int i; |
| 80 | char found_pax, found_stack, found_relro, found_textrel, found_rpath; |
81 | char found_pax, found_stack, found_relro, found_textrel, found_rpath, found_sym; |
| 81 | elfobj *elf; |
82 | elfobj *elf; |
| 82 | |
83 | |
| 83 | found_pax = found_stack = found_relro = found_textrel = found_rpath = 0; |
84 | found_pax = found_stack = found_relro = found_textrel = found_rpath = found_sym = 0; |
| 84 | |
85 | |
| 85 | /* verify this is real ELF */ |
86 | /* verify this is real ELF */ |
| 86 | if ((elf = readelf(filename)) == NULL) { |
87 | if ((elf = readelf(filename)) == NULL) { |
| 87 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
88 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
| 88 | return; |
89 | return; |
| … | |
… | |
| 209 | else if (!be_quiet && !found_rpath) |
210 | else if (!be_quiet && !found_rpath) |
| 210 | printf(" - "); |
211 | printf(" - "); |
| 211 | } |
212 | } |
| 212 | |
213 | |
| 213 | if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath) |
214 | if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath) |
| 214 | puts(filename); |
215 | printf("%s\n", filename); |
|
|
216 | |
|
|
217 | if (find_sym) { |
|
|
218 | void *symtab_void, *strtab_void; |
|
|
219 | symtab_void = elf_findsecbyname(elf, ".symtab"); |
|
|
220 | strtab_void = elf_findsecbyname(elf, ".strtab"); |
|
|
221 | |
|
|
222 | if (symtab_void && strtab_void) { |
|
|
223 | #define FIND_SYM(B) \ |
|
|
224 | if (elf->elf_class == ELFCLASS ## B) { \ |
|
|
225 | Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ |
|
|
226 | Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ |
|
|
227 | Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ |
|
|
228 | int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ |
|
|
229 | char *symname; \ |
|
|
230 | if (be_verbose > 1) \ |
|
|
231 | printf("%s: .symtab has %i entries\n", filename, cnt); \ |
|
|
232 | for (i = 0; i < cnt; ++i) { \ |
|
|
233 | if (sym->st_name) { \ |
|
|
234 | symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ |
|
|
235 | if (*find_sym == '*' || !strcmp(find_sym, symname)) \ |
|
|
236 | printf("%s: %5lX %15s %s\n", \ |
|
|
237 | filename, \ |
|
|
238 | (long)sym->st_size, \ |
|
|
239 | (char *)get_elfstttype(sym->st_info & 0xF), \ |
|
|
240 | symname); \ |
|
|
241 | } \ |
|
|
242 | ++sym; \ |
|
|
243 | } } |
|
|
244 | FIND_SYM(32) |
|
|
245 | FIND_SYM(64) |
|
|
246 | } |
|
|
247 | } |
| 215 | |
248 | |
| 216 | unreadelf(elf); |
249 | unreadelf(elf); |
| 217 | } |
250 | } |
| 218 | |
251 | |
| 219 | /* scan a directory for ET_EXEC files and print when we find one */ |
252 | /* scan a directory for ET_EXEC files and print when we find one */ |
| … | |
… | |
| 317 | } |
350 | } |
| 318 | |
351 | |
| 319 | |
352 | |
| 320 | |
353 | |
| 321 | /* usage / invocation handling functions */ |
354 | /* usage / invocation handling functions */ |
| 322 | #define PARSE_FLAGS "plRmxetraqvo:BhV" |
355 | #define PARSE_FLAGS "plRmxetrs:aqvo:BhV" |
|
|
356 | #define a_argument required_argument |
| 323 | static struct option const long_opts[] = { |
357 | static struct option const long_opts[] = { |
| 324 | {"path", no_argument, NULL, 'p'}, |
358 | {"path", no_argument, NULL, 'p'}, |
| 325 | {"ldpath", no_argument, NULL, 'l'}, |
359 | {"ldpath", no_argument, NULL, 'l'}, |
| 326 | {"recursive", no_argument, NULL, 'R'}, |
360 | {"recursive", no_argument, NULL, 'R'}, |
| 327 | {"mount", no_argument, NULL, 'm'}, |
361 | {"mount", no_argument, NULL, 'm'}, |
| 328 | {"pax", no_argument, NULL, 'x'}, |
362 | {"pax", no_argument, NULL, 'x'}, |
| 329 | {"header", no_argument, NULL, 'e'}, |
363 | {"header", no_argument, NULL, 'e'}, |
| 330 | {"textrel", no_argument, NULL, 't'}, |
364 | {"textrel", no_argument, NULL, 't'}, |
| 331 | {"rpath", no_argument, NULL, 'r'}, |
365 | {"rpath", no_argument, NULL, 'r'}, |
|
|
366 | {"symbol", a_argument, NULL, 's'}, |
| 332 | {"all", no_argument, NULL, 'a'}, |
367 | {"all", no_argument, NULL, 'a'}, |
| 333 | {"quiet", no_argument, NULL, 'q'}, |
368 | {"quiet", no_argument, NULL, 'q'}, |
| 334 | {"verbose", no_argument, NULL, 'v'}, |
369 | {"verbose", no_argument, NULL, 'v'}, |
| 335 | {"file",required_argument, NULL, 'o'}, |
370 | {"file", a_argument, NULL, 'o'}, |
| 336 | {"nobanner", no_argument, NULL, 'B'}, |
371 | {"nobanner", no_argument, NULL, 'B'}, |
| 337 | {"help", no_argument, NULL, 'h'}, |
372 | {"help", no_argument, NULL, 'h'}, |
| 338 | {"version", no_argument, NULL, 'V'}, |
373 | {"version", no_argument, NULL, 'V'}, |
| 339 | {NULL, no_argument, NULL, 0x0} |
374 | {NULL, no_argument, NULL, 0x0} |
| 340 | }; |
375 | }; |
| … | |
… | |
| 345 | "Don't recursively cross mount points\n", |
380 | "Don't recursively cross mount points\n", |
| 346 | "Print PaX markings", |
381 | "Print PaX markings", |
| 347 | "Print GNU_STACK markings", |
382 | "Print GNU_STACK markings", |
| 348 | "Print TEXTREL information", |
383 | "Print TEXTREL information", |
| 349 | "Print RPATH information", |
384 | "Print RPATH information", |
|
|
385 | "Find a specified symbol", |
| 350 | "Print all scanned info (-x -e -t -r)\n", |
386 | "Print all scanned info (-x -e -t -r)\n", |
| 351 | "Only output 'bad' things", |
387 | "Only output 'bad' things", |
| 352 | "Be verbose (can be specified more than once)", |
388 | "Be verbose (can be specified more than once)", |
| 353 | "Write output stream to a filename", |
389 | "Write output stream to a filename", |
| 354 | "Don't display the header", |
390 | "Don't display the header", |
| … | |
… | |
| 359 | |
395 | |
| 360 | /* display usage and exit */ |
396 | /* display usage and exit */ |
| 361 | static void usage(int status) |
397 | static void usage(int status) |
| 362 | { |
398 | { |
| 363 | int i; |
399 | int i; |
| 364 | printf("¤ Scan ELF binaries for stuff\n\n" |
400 | printf("¤ Scan ELF binaries for stuff\n" |
| 365 | "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); |
401 | "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); |
| 366 | printf("Options:\n"); |
402 | printf("Options:\n"); |
| 367 | for (i = 0; long_opts[i].name; ++i) |
403 | for (i = 0; long_opts[i].name; ++i) |
|
|
404 | if (long_opts[i].has_arg == no_argument) |
| 368 | printf(" -%c, --%-12s× %s\n", long_opts[i].val, |
405 | printf(" -%c, --%-13s× %s\n", long_opts[i].val, |
| 369 | long_opts[i].name, opts_help[i]); |
406 | long_opts[i].name, opts_help[i]); |
| 370 | #ifdef MANLYPAGE |
407 | else |
| 371 | for (i = 0; long_opts[i].name; ++i) |
408 | printf(" -%c, --%-6s <arg> × %s\n", long_opts[i].val, |
| 372 | printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val, |
|
|
| 373 | long_opts[i].name, opts_help[i]); |
409 | long_opts[i].name, opts_help[i]); |
| 374 | #endif |
|
|
| 375 | exit(status); |
410 | exit(status); |
| 376 | } |
411 | } |
| 377 | |
412 | |
| 378 | /* parse command line arguments and preform needed actions */ |
413 | /* parse command line arguments and preform needed actions */ |
| 379 | static void parseargs(int argc, char *argv[]) |
414 | static void parseargs(int argc, char *argv[]) |
| … | |
… | |
| 388 | printf("%s compiled %s\n%s\n" |
423 | printf("%s compiled %s\n%s\n" |
| 389 | "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", |
424 | "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", |
| 390 | __FILE__, __DATE__, rcsid, argv0); |
425 | __FILE__, __DATE__, rcsid, argv0); |
| 391 | exit(EXIT_SUCCESS); |
426 | exit(EXIT_SUCCESS); |
| 392 | break; |
427 | break; |
| 393 | case 's': /* reserved for -s, --symbol= */ |
|
|
| 394 | case 'h': usage(EXIT_SUCCESS); break; |
428 | case 'h': usage(EXIT_SUCCESS); break; |
| 395 | |
429 | |
| 396 | case 'o': { |
430 | case 'o': { |
| 397 | FILE *fp = NULL; |
431 | FILE *fp = NULL; |
| 398 | fp = freopen(optarg, "w", stdout); |
432 | fp = freopen(optarg, "w", stdout); |
| 399 | if (fp == NULL) |
433 | if (fp == NULL) |
| 400 | err("Could not open output stream '%s': %s", optarg, strerror(errno)); |
434 | err("Could not open output stream '%s': %s", optarg, strerror(errno)); |
| 401 | stdout = fp; |
435 | stdout = fp; |
| 402 | break; |
436 | break; |
| 403 | } |
437 | } |
|
|
438 | |
|
|
439 | case 's': find_sym = strdup(optarg); break; |
| 404 | |
440 | |
| 405 | case 'B': show_banner = 0; break; |
441 | case 'B': show_banner = 0; break; |
| 406 | case 'l': scan_ldpath = 1; break; |
442 | case 'l': scan_ldpath = 1; break; |
| 407 | case 'p': scan_envpath = 1; break; |
443 | case 'p': scan_envpath = 1; break; |
| 408 | case 'R': dir_recurse = 1; break; |
444 | case 'R': dir_recurse = 1; break; |
| … | |
… | |
| 436 | if (scan_envpath) scanelf_envpath(); |
472 | if (scan_envpath) scanelf_envpath(); |
| 437 | if (optind == argc && !scan_ldpath && !scan_envpath) |
473 | if (optind == argc && !scan_ldpath && !scan_envpath) |
| 438 | err("Nothing to scan !?"); |
474 | err("Nothing to scan !?"); |
| 439 | while (optind < argc) |
475 | while (optind < argc) |
| 440 | scanelf_dir(argv[optind++]); |
476 | scanelf_dir(argv[optind++]); |
|
|
477 | |
|
|
478 | if (find_sym) free(find_sym); |
| 441 | } |
479 | } |
| 442 | |
480 | |
| 443 | |
481 | |
| 444 | |
482 | |
| 445 | int main(int argc, char *argv[]) |
483 | int main(int argc, char *argv[]) |