/[gentoo-projects]/pax-utils/scanelf.c
Gentoo

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.27 Revision 1.35
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/Attic/scanelf.c,v 1.27 2005/04/05 01:44:08 vapier Exp $ 5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.35 2005/04/14 00:17:30 solar 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
22 */ 22 */
23 23
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <sys/types.h> 26#include <sys/types.h>
27#define __USE_GNU
27#include <string.h> 28#include <string.h>
28#include <errno.h> 29#include <errno.h>
29#include <unistd.h> 30#include <unistd.h>
30#include <sys/stat.h> 31#include <sys/stat.h>
31#include <dirent.h> 32#include <dirent.h>
32#include <getopt.h> 33#include <getopt.h>
33#include <assert.h> 34#include <assert.h>
34 35
35#include "paxelf.h" 36#include "paxelf.h"
36 37
37static const char *rcsid = "$Id: scanelf.c,v 1.27 2005/04/05 01:44:08 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.35 2005/04/14 00:17:30 solar Exp $";
38 39
39 40
40/* helper functions for showing errors */ 41/* helper functions for showing errors */
41#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/ 42#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
42#define warn(fmt, args...) \ 43#define warn(fmt, args...) \
65static char dir_crossmount = 1; 66static char dir_crossmount = 1;
66static char show_pax = 0; 67static char show_pax = 0;
67static char show_stack = 0; 68static char show_stack = 0;
68static char show_textrel = 0; 69static char show_textrel = 0;
69static char show_rpath = 0; 70static char show_rpath = 0;
71static char show_needed = 0;
70static char show_banner = 1; 72static char show_banner = 1;
71static char be_quiet = 0; 73static char be_quiet = 0;
72static char be_verbose = 0; 74static char be_verbose = 0;
73static char *find_sym = NULL; 75static char *find_sym = NULL;
74 76
76 78
77/* scan an elf file and show all the fun stuff */ 79/* scan an elf file and show all the fun stuff */
78static void scanelf_file(const char *filename) 80static void scanelf_file(const char *filename)
79{ 81{
80 int i; 82 int i;
81 char found_pax, found_stack, found_relro, found_textrel, found_rpath, found_sym; 83 char found_pax, found_stack, found_relro, found_textrel,
84 found_rpath, found_needed, found_sym;
82 elfobj *elf; 85 elfobj *elf;
86 struct stat st;
83 87
88 /* make sure path exists */
89 if (lstat(filename, &st) == -1)
90 return;
91 if (!S_ISREG(st.st_mode))
92 return;
84 found_pax = found_stack = found_relro = found_textrel = found_rpath = found_sym = 0; 93 found_pax = found_stack = found_relro = found_textrel = \
94 found_rpath = found_needed = found_sym = 0;
85 95
86 /* verify this is real ELF */ 96 /* verify this is real ELF */
87 if ((elf = readelf(filename)) == NULL) { 97 if ((elf = readelf(filename)) == NULL) {
88 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 98 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
89 return; 99 return;
96 else if (be_verbose) 106 else if (be_verbose)
97 printf("%s: scanning file\n", filename); 107 printf("%s: scanning file\n", filename);
98 108
99 /* show the header */ 109 /* show the header */
100 if (!be_quiet && show_banner) { 110 if (!be_quiet && show_banner) {
101 printf(" TYPE "); 111 printf(" TYPE ");
102 if (show_pax) printf(" PAX "); 112 if (show_pax) printf(" PAX ");
103 if (show_stack) printf(" STK/REL "); 113 if (show_stack) printf("STK/REL ");
104 if (show_textrel) printf("TEXTREL "); 114 if (show_textrel) printf("TEXTREL ");
105 if (show_rpath) printf("RPATH "); 115 if (show_rpath) printf("RPATH ");
116 if (show_needed) printf("NEEDED ");
106 printf(" FILE\n"); 117 printf(" FILE\n");
107 show_banner = 0; 118 show_banner = 0;
108 } 119 }
109 120
110 /* dump all the good stuff */ 121 /* dump all the good stuff */
155 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 166 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
156 while (EGET(dyn->d_tag) != DT_NULL) { \ 167 while (EGET(dyn->d_tag) != DT_NULL) { \
157 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 168 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
158 found_textrel = 1; \ 169 found_textrel = 1; \
159 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 170 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
160 printf("TEXTREL "); \ 171 fputs("TEXTREL ", stdout); \
161 } \ 172 } \
162 ++dyn; \ 173 ++dyn; \
163 } \ 174 } \
164 } } 175 } }
165 SHOW_TEXTREL(32) 176 SHOW_TEXTREL(32)
166 SHOW_TEXTREL(64) 177 SHOW_TEXTREL(64)
167 if (!be_quiet && !found_textrel) printf("------- "); 178 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
168 } 179 }
169 180
170 /* rpath fun */ 181 /* rpath fun */
171 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 182 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
172 if (show_rpath) { 183 if (show_rpath) {
209 printf("%-5s ", (runpath ? runpath : rpath)); 220 printf("%-5s ", (runpath ? runpath : rpath));
210 else if (!be_quiet && !found_rpath) 221 else if (!be_quiet && !found_rpath)
211 printf(" - "); 222 printf(" - ");
212 } 223 }
213 224
214 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath) 225 /* print out all the NEEDED entries */
215 printf("%s\n", filename); 226 if (show_needed) {
227 char *needed;
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr");
216 229
230 if (strtbl_void) {
231#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
238 if (be_verbose && EGET(phdr[i].p_type) == PT_INTERP) { \
239 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
240 printf("%s\n", elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr)); \
241 exit(0); \
242 } \
243 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
248 if (found_needed) printf(","); \
249 printf("%s", needed); \
250 found_needed = 1; \
251 } \
252 ++dyn; \
253 } \
254 } }
255 SHOW_NEEDED(32)
256 SHOW_NEEDED(64)
257 }
258 if (!be_quiet && !found_needed)
259 printf(" - ");
260 else if (found_needed)
261 printf(" ");
262 }
263
264 /* search the symbol table for a specified symbol */
217 if (find_sym) { 265 if (find_sym) {
218 void *symtab_void, *strtab_void; 266 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269
270 len = strlen(find_sym) + 1;
271 versioned_symname = (char *)malloc(sizeof(char) * (len+1));
272 if (!versioned_symname) {
273 warnf("Could not malloc() mem for sym scan");
274 return;
275 }
276 sprintf(versioned_symname, "%s@", find_sym);
277
219 symtab_void = elf_findsecbyname(elf, ".symtab"); 278 symtab_void = elf_findsecbyname(elf, ".symtab");
220 strtab_void = elf_findsecbyname(elf, ".strtab"); 279 strtab_void = elf_findsecbyname(elf, ".strtab");
221 280
222 if (symtab_void && strtab_void) { 281 if (symtab_void && strtab_void) {
223#define FIND_SYM(B) \ 282#define FIND_SYM(B) \
225 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
226 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
227 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 286 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
228 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 287 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
229 char *symname; \ 288 char *symname; \
230 if (be_verbose > 1) \
231 printf("%s: .symtab has %i entries\n", filename, cnt); \
232 for (i = 0; i < cnt; ++i) { \ 289 for (i = 0; i < cnt; ++i) { \
233 if (sym->st_name) { \ 290 if (sym->st_name) { \
234 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 291 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
235 if (*find_sym == '*' || !strcmp(find_sym, symname)) \ 292 if (*find_sym == '*') { \
236 printf("%s: %5lX %15s %s\n", \ 293 printf("%s(%s) %5lX %15s %s\n", \
237 filename, \ 294 ((found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \
238 (long)sym->st_size, \ 296 (long)sym->st_size, \
239 (char *)get_elfstttype(sym->st_info & 0xF), \ 297 (char *)get_elfstttype(sym->st_info), \
240 symname); \ 298 symname); \
299 found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \
301 (strncmp(symname, versioned_symname, len) == 0)) \
302 found_sym++; \
241 } \ 303 } \
242 ++sym; \ 304 ++sym; \
243 } } 305 } }
244 FIND_SYM(32) 306 FIND_SYM(32)
245 FIND_SYM(64) 307 FIND_SYM(64)
246 } 308 }
309 free(versioned_symname);
310 if (*find_sym != '*') {
311 if (found_sym)
312 printf(" %s ", find_sym);
313 else if (!be_quiet)
314 fputs(" - ", stdout);
247 } 315 }
316 }
317
318 if (!be_quiet || found_pax || found_stack || found_textrel || \
319 found_rpath || found_needed || found_sym)
320 puts(filename);
248 321
249 unreadelf(elf); 322 unreadelf(elf);
250} 323}
251 324
252/* scan a directory for ET_EXEC files and print when we find one */ 325/* scan a directory for ET_EXEC files and print when we find one */
254{ 327{
255 register DIR *dir; 328 register DIR *dir;
256 register struct dirent *dentry; 329 register struct dirent *dentry;
257 struct stat st_top, st; 330 struct stat st_top, st;
258 char buf[_POSIX_PATH_MAX]; 331 char buf[_POSIX_PATH_MAX];
259 size_t len = 0; 332 size_t pathlen = 0, len = 0;
260 333
261 /* make sure path exists */ 334 /* make sure path exists */
262 if (lstat(path, &st_top) == -1) 335 if (lstat(path, &st_top) == -1)
263 return; 336 return;
264 337
273 warnf("could not opendir %s: %s", path, strerror(errno)); 346 warnf("could not opendir %s: %s", path, strerror(errno));
274 return; 347 return;
275 } 348 }
276 if (be_verbose) printf("%s: scanning dir\n", path); 349 if (be_verbose) printf("%s: scanning dir\n", path);
277 350
351 pathlen = strlen(path);
278 while ((dentry = readdir(dir))) { 352 while ((dentry = readdir(dir))) {
279 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 353 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
280 continue; 354 continue;
281 len = (strlen(path) + 2 + strlen(dentry->d_name)); 355 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
282 assert(len < sizeof(buf)); 356 if (len >= sizeof(buf)) {
283 strncpy(buf, path, len); 357 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
284 strncat(buf, "/", len); 358 continue;
285 strncat(buf, dentry->d_name, len); 359 }
286 buf[sizeof(buf)] = 0; 360 sprintf(buf, "%s/%s", path, dentry->d_name);
287 if (lstat(buf, &st) != -1) { 361 if (lstat(buf, &st) != -1) {
288 if (S_ISREG(st.st_mode)) 362 if (S_ISREG(st.st_mode))
289 scanelf_file(buf); 363 scanelf_file(buf);
290 else if (dir_recurse && S_ISDIR(st.st_mode)) { 364 else if (dir_recurse && S_ISDIR(st.st_mode)) {
291 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 365 if (dir_crossmount || (st_top.st_dev == st.st_dev))
306 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
307 err("Unable to open ld.so.conf: %s", strerror(errno)); 381 err("Unable to open ld.so.conf: %s", strerror(errno));
308 382
309 scan_l = scan_ul = scan_ull = 0; 383 scan_l = scan_ul = scan_ull = 0;
310 384
311 path = malloc(_POSIX_PATH_MAX); 385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) {
386 warn("Can not malloc() memory for ldpath scanning");
387 return;
388 }
312 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) 389 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
313 if (*path == '/') { 390 if (*path == '/') {
314 if ((p = strrchr(path, '\r')) != NULL) 391 if ((p = strrchr(path, '\r')) != NULL)
315 *p = 0; 392 *p = 0;
316 if ((p = strrchr(path, '\n')) != NULL) 393 if ((p = strrchr(path, '\n')) != NULL)
319 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 396 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
320 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 397 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
321 scanelf_dir(path); 398 scanelf_dir(path);
322 } 399 }
323 free(path); 400 free(path);
401 fclose(fp);
324 402
325 if (!scan_l) scanelf_dir("/lib"); 403 if (!scan_l) scanelf_dir("/lib");
326 if (!scan_ul) scanelf_dir("/usr/lib"); 404 if (!scan_ul) scanelf_dir("/usr/lib");
327 if (!scan_ull) scanelf_dir("/usr/local/lib"); 405 if (!scan_ull) scanelf_dir("/usr/local/lib");
328
329 fclose(fp);
330} 406}
331 407
332/* scan env PATH for paths */ 408/* scan env PATH for paths */
333static void scanelf_envpath() 409static void scanelf_envpath()
334{ 410{
337 path = getenv("PATH"); 413 path = getenv("PATH");
338 if (!path) 414 if (!path)
339 err("PATH is not set in your env !"); 415 err("PATH is not set in your env !");
340 416
341 if ((path = strdup(path)) == NULL) 417 if ((path = strdup(path)) == NULL)
342 err("stdup failed: %s", strerror(errno)); 418 err("strdup failed: %s", strerror(errno));
343 419
344 while ((p = strrchr(path, ':')) != NULL) { 420 while ((p = strrchr(path, ':')) != NULL) {
345 scanelf_dir(p + 1); 421 scanelf_dir(p + 1);
346 *p = 0; 422 *p = 0;
347 } 423 }
350} 426}
351 427
352 428
353 429
354/* usage / invocation handling functions */ 430/* usage / invocation handling functions */
355#define PARSE_FLAGS "plRmxetrs:aqvo:BhV" 431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV"
356#define a_argument required_argument 432#define a_argument required_argument
357static struct option const long_opts[] = { 433static struct option const long_opts[] = {
358 {"path", no_argument, NULL, 'p'}, 434 {"path", no_argument, NULL, 'p'},
359 {"ldpath", no_argument, NULL, 'l'}, 435 {"ldpath", no_argument, NULL, 'l'},
360 {"recursive", no_argument, NULL, 'R'}, 436 {"recursive", no_argument, NULL, 'R'},
361 {"mount", no_argument, NULL, 'm'}, 437 {"mount", no_argument, NULL, 'm'},
362 {"pax", no_argument, NULL, 'x'}, 438 {"pax", no_argument, NULL, 'x'},
363 {"header", no_argument, NULL, 'e'}, 439 {"header", no_argument, NULL, 'e'},
364 {"textrel", no_argument, NULL, 't'}, 440 {"textrel", no_argument, NULL, 't'},
365 {"rpath", no_argument, NULL, 'r'}, 441 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'},
366 {"symbol", a_argument, NULL, 's'}, 443 {"symbol", a_argument, NULL, 's'},
367 {"all", no_argument, NULL, 'a'}, 444 {"all", no_argument, NULL, 'a'},
368 {"quiet", no_argument, NULL, 'q'}, 445 {"quiet", no_argument, NULL, 'q'},
369 {"verbose", no_argument, NULL, 'v'}, 446 {"verbose", no_argument, NULL, 'v'},
370 {"file", a_argument, NULL, 'o'}, 447 {"file", a_argument, NULL, 'o'},
380 "Don't recursively cross mount points\n", 457 "Don't recursively cross mount points\n",
381 "Print PaX markings", 458 "Print PaX markings",
382 "Print GNU_STACK markings", 459 "Print GNU_STACK markings",
383 "Print TEXTREL information", 460 "Print TEXTREL information",
384 "Print RPATH information", 461 "Print RPATH information",
462 "Print NEEDED information",
385 "Find a specified symbol", 463 "Find a specified symbol",
386 "Print all scanned info (-x -e -t -r)\n", 464 "Print all scanned info (-x -e -t -r)\n",
387 "Only output 'bad' things", 465 "Only output 'bad' things",
388 "Be verbose (can be specified more than once)", 466 "Be verbose (can be specified more than once)",
389 "Write output stream to a filename", 467 "Write output stream to a filename",
396/* display usage and exit */ 474/* display usage and exit */
397static void usage(int status) 475static void usage(int status)
398{ 476{
399 int i; 477 int i;
400 printf(" Scan ELF binaries for stuff\n" 478 printf(" Scan ELF binaries for stuff\n"
401 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); 479 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
402 printf("Options:\n"); 480 printf("Options: -[%s]\n", PARSE_FLAGS);
403 for (i = 0; long_opts[i].name; ++i) 481 for (i = 0; long_opts[i].name; ++i)
404 if (long_opts[i].has_arg == no_argument) 482 if (long_opts[i].has_arg == no_argument)
405 printf(" -%c, --%-13s %s\n", long_opts[i].val, 483 printf(" -%c, --%-13s %s\n", long_opts[i].val,
406 long_opts[i].name, opts_help[i]); 484 long_opts[i].name, opts_help[i]);
407 else 485 else
445 case 'm': dir_crossmount = 0; break; 523 case 'm': dir_crossmount = 0; break;
446 case 'x': show_pax = 1; break; 524 case 'x': show_pax = 1; break;
447 case 'e': show_stack = 1; break; 525 case 'e': show_stack = 1; break;
448 case 't': show_textrel = 1; break; 526 case 't': show_textrel = 1; break;
449 case 'r': show_rpath = 1; break; 527 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break;
450 case 'q': be_quiet = 1; break; 529 case 'q': be_quiet = 1; break;
451 case 'v': be_verbose = (be_verbose % 20) + 1; break; 530 case 'v': be_verbose = (be_verbose % 20) + 1; break;
452 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break; 531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break;
453 532
454 case ':': 533 case ':':
455 warn("Option missing parameter"); 534 warn("Option missing parameter");
456 usage(EXIT_FAILURE); 535 usage(EXIT_FAILURE);
457 break; 536 break;

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.35

  ViewVC Help
Powered by ViewVC 1.1.20