/[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.143 Revision 1.188
1/* 1/*
2 * Copyright 2003-2006 Gentoo Foundation 2 * Copyright 2003-2007 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.143 2006/05/11 05:44:22 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.188 2007/08/31 17:45:24 solar Exp $
5 * 5 *
6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10static const char *rcsid = "$Id: scanelf.c,v 1.188 2007/08/31 17:45:24 solar Exp $";
11const char * const argv0 = "scanelf";
12
10#include "paxinc.h" 13#include "paxinc.h"
11#if defined(__GLIBC__) || defined(__UCLIBC__)
12 #include <glob.h>
13#endif
14#if defined(__FreeBSD__) || defined(__DragonFly__)
15 #include <elf-hints.h>
16#endif
17
18static const char *rcsid = "$Id: scanelf.c,v 1.143 2006/05/11 05:44:22 solar Exp $";
19#define argv0 "scanelf"
20 14
21#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
22
23#define do_state(option, flag) \
24 if (islower(option)) { \
25 flags &= ~PF_##flag; \
26 flags |= PF_NO##flag; \
27 } else { \
28 flags &= ~PF_NO##flag; \
29 flags |= PF_##flag; \
30 }
31
32 16
33/* prototypes */ 17/* prototypes */
34static int file_matches_list(const char *filename, char **matchlist); 18static int file_matches_list(const char *filename, char **matchlist);
35static int scanelf_elfobj(elfobj *elf); 19static int scanelf_elfobj(elfobj *elf);
36static int scanelf_elf(const char *filename, int fd, size_t len); 20static int scanelf_elf(const char *filename, int fd, size_t len);
37static int scanelf_archive(const char *filename, int fd, size_t len); 21static int scanelf_archive(const char *filename, int fd, size_t len);
38static void scanelf_file(const char *filename); 22static int scanelf_file(const char *filename, const struct stat *st_cache);
39static void scanelf_dir(const char *path); 23static int scanelf_dir(const char *path);
40static void scanelf_ldpath(void); 24static void scanelf_ldpath(void);
41static void scanelf_envpath(void); 25static void scanelf_envpath(void);
42static void usage(int status); 26static void usage(int status);
43static char **get_split_env(const char *envvar); 27static char **get_split_env(const char *envvar);
44static void parseenv(void); 28static void parseenv(void);
45static void parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
46static char *xstrdup(const char *s); 30static int rematch(const char *regex, const char *match, int cflags);
47static void *xmalloc(size_t size);
48static void *xrealloc(void *ptr, size_t size);
49static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
50#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
51static inline void xchrcat(char **dst, const char append, size_t *curr_len);
52 31
53/* variables to control behavior */ 32/* variables to control behavior */
54static char match_etypes[126] = ""; 33static char match_etypes[126] = "";
55static char *ldpaths[256]; 34static char *ldpaths[256];
56static char scan_ldpath = 0; 35static char scan_ldpath = 0;
58static char scan_symlink = 1; 37static char scan_symlink = 1;
59static char scan_archives = 0; 38static char scan_archives = 0;
60static char dir_recurse = 0; 39static char dir_recurse = 0;
61static char dir_crossmount = 1; 40static char dir_crossmount = 1;
62static char show_pax = 0; 41static char show_pax = 0;
42static char show_perms = 0;
63static char show_phdr = 0; 43static char show_phdr = 0;
64static char show_textrel = 0; 44static char show_textrel = 0;
65static char show_rpath = 0; 45static char show_rpath = 0;
66static char show_needed = 0; 46static char show_needed = 0;
67static char show_interp = 0; 47static char show_interp = 0;
68static char show_bind = 0; 48static char show_bind = 0;
69static char show_soname = 0; 49static char show_soname = 0;
70static char show_textrels = 0; 50static char show_textrels = 0;
71static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
72static char be_quiet = 0; 53static char be_quiet = 0;
73static char be_verbose = 0; 54static char be_verbose = 0;
74static char be_wewy_wewy_quiet = 0; 55static char be_wewy_wewy_quiet = 0;
75static char be_semi_verbose = 0; 56static char be_semi_verbose = 0;
76static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL; 58static char *find_lib = NULL;
78static char *find_section = NULL; 59static char *find_section = NULL;
79static char *out_format = NULL; 60static char *out_format = NULL;
80static char *search_path = NULL; 61static char *search_path = NULL;
81static char fix_elf = 0; 62static char fix_elf = 0;
82static char gmatch = 0; 63static char g_match = 0;
83static char use_ldcache = 0; 64static char use_ldcache = 0;
84 65
85static char **qa_textrels = NULL; 66static char **qa_textrels = NULL;
86static char **qa_execstack = NULL; 67static char **qa_execstack = NULL;
68static char **qa_wx_load = NULL;
87 69
88int match_bits = 0; 70int match_bits = 0;
71unsigned int match_perms = 0;
89caddr_t ldcache = 0; 72caddr_t ldcache = 0;
90size_t ldcache_size = 0; 73size_t ldcache_size = 0;
91unsigned long setpax = 0UL; 74unsigned long setpax = 0UL;
92 75
93/* utility funcs */ 76int has_objdump = 0;
77
78static char *getstr_perms(const char *fname);
94static char *xstrdup(const char *s) 79static char *getstr_perms(const char *fname)
95{ 80{
96 char *ret = strdup(s); 81 struct stat st;
97 if (!ret) err("Could not strdup(): %s", strerror(errno)); 82 static char buf[8];
83
84 if ((stat(fname, &st)) == (-1))
85 return (char *) "";
86
87 snprintf(buf, sizeof(buf), "%o", st.st_mode);
88
89 return (char *) buf + 2;
90}
91
92/* find the path to a file by name */
93static char *which(const char *fname)
94{
95 static char fullpath[BUFSIZ];
96 char *path, *p;
97
98 path = getenv("PATH");
99 if (!path)
100 return NULL;
101
102 path = xstrdup(path);
103 while ((p = strrchr(path, ':')) != NULL) {
104 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
105 *p = 0;
106 if (access(fullpath, R_OK) != (-1)) {
107 free(path);
108 return (char *) fullpath;
109 }
110 }
111 free(path);
112 return NULL;
113}
114
115/* 1 on failure. 0 otherwise */
116static int rematch(const char *regex, const char *match, int cflags)
117{
118 regex_t preg;
119 int ret;
120
121 if ((match == NULL) || (regex == NULL))
122 return EXIT_FAILURE;
123
124
125 if ((ret = regcomp(&preg, regex, cflags))) {
126 char err[256];
127
128 if (regerror(ret, &preg, err, sizeof(err)))
129 fprintf(stderr, "regcomp failed: %s", err);
130 else
131 fprintf(stderr, "regcomp failed");
132
133 return EXIT_FAILURE;
134 }
135 ret = regexec(&preg, match, 0, NULL, 0);
136 regfree(&preg);
137
98 return ret; 138 return ret;
99}
100static void *xmalloc(size_t size)
101{
102 void *ret = malloc(size);
103 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
104 return ret;
105}
106static void *xrealloc(void *ptr, size_t size)
107{
108 void *ret = realloc(ptr, size);
109 if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
110 return ret;
111}
112static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
113{
114 size_t new_len;
115
116 new_len = strlen(*dst) + strlen(src);
117 if (*curr_len <= new_len) {
118 *curr_len = new_len + (*curr_len / 2);
119 *dst = realloc(*dst, *curr_len);
120 if (!*dst)
121 err("could not realloc() %li bytes", (unsigned long)*curr_len);
122 }
123
124 if (n)
125 strncat(*dst, src, n);
126 else
127 strcat(*dst, src);
128}
129static inline void xchrcat(char **dst, const char append, size_t *curr_len)
130{
131 static char my_app[2];
132 my_app[0] = append;
133 my_app[1] = '\0';
134 xstrcat(dst, my_app, curr_len);
135}
136
137/* Match filename against entries in matchlist, return TRUE
138 * if the file is listed */
139static int file_matches_list(const char *filename, char **matchlist) {
140 char **file;
141 char *match;
142 char buf[__PAX_UTILS_PATH_MAX];
143
144 if (matchlist == NULL)
145 return 0;
146
147 for (file = matchlist; *file != NULL; file++) {
148 if (search_path) {
149 snprintf(buf,__PAX_UTILS_PATH_MAX, "%s%s", search_path, *file);
150 match=buf;
151 } else {
152 match=*file;
153 }
154 if (fnmatch(match, filename, 0) == 0)
155 return 1; /* TRUE */
156 }
157 return 0; /* FALSE */
158} 139}
159 140
160/* sub-funcs for scanelf_file() */ 141/* sub-funcs for scanelf_file() */
161static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 142static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
162{ 143{
271 uint32_t flags, check_flags; \ 252 uint32_t flags, check_flags; \
272 if (elf->phdr != NULL) { \ 253 if (elf->phdr != NULL) { \
273 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 254 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
274 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 255 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
275 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 256 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
257 if (multi_stack++) \
276 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 258 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
277 if (!file_matches_list(elf->filename, qa_execstack)) {\ 259 if (file_matches_list(elf->filename, qa_execstack)) \
260 continue; \
278 found = found_phdr; \ 261 found = found_phdr; \
279 offset = 0; \ 262 offset = 0; \
280 check_flags = PF_X; \ 263 check_flags = PF_X; \
281 } else continue; \
282 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 264 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
265 if (multi_relro++) \
283 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 266 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
284 found = found_relro; \ 267 found = found_relro; \
285 offset = 4; \ 268 offset = 4; \
286 check_flags = PF_X; \ 269 check_flags = PF_X; \
287 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 270 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
288 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \ 271 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
272 if (multi_load++ > max_pt_load) \
289 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \ 273 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
274 if (file_matches_list(elf->filename, qa_wx_load)) \
275 continue; \
290 found = found_load; \ 276 found = found_load; \
291 offset = 8; \ 277 offset = 8; \
292 check_flags = PF_W|PF_X; \ 278 check_flags = PF_W|PF_X; \
293 } else \ 279 } else \
294 continue; \ 280 continue; \
331 break; \ 317 break; \
332 } \ 318 } \
333 } \ 319 } \
334 skip_this_shdr##B: \ 320 skip_this_shdr##B: \
335 if (!multi_stack) { \ 321 if (!multi_stack) { \
322 if (file_matches_list(elf->filename, qa_execstack)) \
323 return NULL; \
336 *found_phdr = 1; \ 324 *found_phdr = 1; \
337 shown = 1; \ 325 shown = 1; \
338 memcpy(ret, "!WX", 3); \ 326 memcpy(ret, "!WX", 3); \
339 } \ 327 } \
340 } \ 328 } \
346 return NULL; 334 return NULL;
347 else 335 else
348 return ret; 336 return ret;
349} 337}
350 338
339/*
340 * See if this ELF contains a DT_TEXTREL tag in any of its
341 * PT_DYNAMIC sections.
342 */
351static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 343static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
352{ 344{
353 static const char *ret = "TEXTREL"; 345 static const char *ret = "TEXTREL";
354 unsigned long i; 346 unsigned long i;
355 347
363 Elf ## B ## _Dyn *dyn; \ 355 Elf ## B ## _Dyn *dyn; \
364 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 356 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
365 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 357 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
366 Elf ## B ## _Off offset; \ 358 Elf ## B ## _Off offset; \
367 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 359 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
368 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 360 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
369 offset = EGET(phdr[i].p_offset); \ 361 offset = EGET(phdr[i].p_offset); \
370 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 362 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
371 dyn = DYN ## B (elf->data + offset); \ 363 dyn = DYN ## B (elf->data + offset); \
372 while (EGET(dyn->d_tag) != DT_NULL) { \ 364 while (EGET(dyn->d_tag) != DT_NULL) { \
373 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 365 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
385 if (be_quiet || be_wewy_wewy_quiet) 377 if (be_quiet || be_wewy_wewy_quiet)
386 return NULL; 378 return NULL;
387 else 379 else
388 return " - "; 380 return " - ";
389} 381}
382
383/*
384 * Scan the .text section to see if there are any relocations in it.
385 * Should rewrite this to check PT_LOAD sections that are marked
386 * Executable rather than the section named '.text'.
387 */
390static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 388static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
391{ 389{
392 unsigned long s, r, rmax; 390 unsigned long s, r, rmax;
393 void *symtab_void, *strtab_void, *text_void; 391 void *symtab_void, *strtab_void, *text_void;
394 392
461 /* show the raw details about this reloc */ \ 459 /* show the raw details about this reloc */ \
462 printf(" %s: ", elf->base_filename); \ 460 printf(" %s: ", elf->base_filename); \
463 if (sym && sym->st_name) \ 461 if (sym && sym->st_name) \
464 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 462 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
465 else \ 463 else \
466 printf("(memory/fake?)"); \ 464 printf("(memory/data?)"); \
467 printf(" [0x%lX]", (unsigned long)r_offset); \ 465 printf(" [0x%lX]", (unsigned long)r_offset); \
468 /* now try to find the closest symbol that this rel is probably in */ \ 466 /* now try to find the closest symbol that this rel is probably in */ \
469 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 467 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
470 func = NULL; \ 468 func = NULL; \
471 offset_tmp = 0; \ 469 offset_tmp = 0; \
475 offset_tmp = EGET(sym->st_value); \ 473 offset_tmp = EGET(sym->st_value); \
476 } \ 474 } \
477 ++sym; \ 475 ++sym; \
478 } \ 476 } \
479 printf(" in "); \ 477 printf(" in "); \
480 if (func && func->st_name) \ 478 if (func && func->st_name) { \
481 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ 479 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
480 if (r_offset > EGET(func->st_size)) \
481 printf("(optimized out: previous %s)", func_name); \
482 else \ 482 else \
483 printf("(NULL: fake?)"); \ 483 printf("%s", func_name); \
484 } else \
485 printf("(optimized out)"); \
484 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 486 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
487 if (be_verbose && has_objdump) { \
488 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
489 char *sysbuf; \
490 size_t syslen; \
491 const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
492 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
493 sysbuf = xmalloc(syslen); \
494 if (end_addr < r_offset) \
495 /* not uncommon when things are optimized out */ \
496 end_addr = r_offset + 0x100; \
497 snprintf(sysbuf, syslen, sysfmt, \
498 (unsigned long)offset_tmp, \
499 (unsigned long)end_addr, \
500 elf->filename, \
501 (unsigned long)r_offset); \
502 fflush(stdout); \
503 system(sysbuf); \
504 fflush(stdout); \
505 free(sysbuf); \
506 } \
485 } \ 507 } \
486 } } 508 } }
487 SHOW_TEXTRELS(32) 509 SHOW_TEXTRELS(32)
488 SHOW_TEXTRELS(64) 510 SHOW_TEXTRELS(64)
489 } 511 }
507 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 529 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
508 break; 530 break;
509 case '$': 531 case '$':
510 if (fstat(elf->fd, &st) != -1) 532 if (fstat(elf->fd, &st) != -1)
511 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 533 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
512 warnf("Security problem with %s='%s' in %s with mode set of %o", 534 warnf("Security problem with %s='%s' in %s with mode set of %o",
513 dt_type, item, elf->filename, st.st_mode & 07777); 535 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
514 break; 536 break;
515 default: 537 default:
516 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename); 538 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
517 break; 539 break;
518 } 540 }
538 Elf ## B ## _Off offset; \ 560 Elf ## B ## _Off offset; \
539 Elf ## B ## _Xword word; \ 561 Elf ## B ## _Xword word; \
540 /* Scan all the program headers */ \ 562 /* Scan all the program headers */ \
541 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 563 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
542 /* Just scan dynamic headers */ \ 564 /* Just scan dynamic headers */ \
543 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 565 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
544 offset = EGET(phdr[i].p_offset); \ 566 offset = EGET(phdr[i].p_offset); \
545 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 567 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
546 /* Just scan dynamic RPATH/RUNPATH headers */ \ 568 /* Just scan dynamic RPATH/RUNPATH headers */ \
547 dyn = DYN ## B (elf->data + offset); \ 569 dyn = DYN ## B (elf->data + offset); \
548 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 570 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
677#define FLAG_POWERPC_LIB64 0x0500 699#define FLAG_POWERPC_LIB64 0x0500
678#define FLAG_MIPS64_LIBN32 0x0600 700#define FLAG_MIPS64_LIBN32 0x0600
679#define FLAG_MIPS64_LIBN64 0x0700 701#define FLAG_MIPS64_LIBN64 0x0700
680 702
681static char *lookup_cache_lib(elfobj *, char *); 703static char *lookup_cache_lib(elfobj *, char *);
704
682#if defined(__GLIBC__) || defined(__UCLIBC__) 705#if defined(__GLIBC__) || defined(__UCLIBC__)
706
683static char *lookup_cache_lib(elfobj *elf, char *fname) 707static char *lookup_cache_lib(elfobj *elf, char *fname)
684{ 708{
685 int fd = 0; 709 int fd = 0;
686 char *strs; 710 char *strs;
687 static char buf[__PAX_UTILS_PATH_MAX] = ""; 711 static char buf[__PAX_UTILS_PATH_MAX] = "";
743 continue; 767 continue;
744 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 768 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
745 } 769 }
746 return buf; 770 return buf;
747} 771}
772#elif defined(__NetBSD__)
773static char *lookup_cache_lib(elfobj *elf, char *fname)
774{
775 static char buf[__PAX_UTILS_PATH_MAX] = "";
776 static struct stat st;
777
778 char **ldpath;
779 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
780 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
781 continue; /* if the pathname is too long, or something went wrong, ignore */
782
783 if (stat(buf, &st) != 0)
784 continue; /* if the lib doesn't exist in *ldpath, look further */
785
786 /* NetBSD doesn't actually do sanity checks, it just loads the file
787 * and if that doesn't work, continues looking in other directories.
788 * This cannot easily be safely emulated, unfortunately. For now,
789 * just assume that if it exists, it's a valid library. */
790
791 return buf;
792 }
793
794 /* not found in any path */
795 return NULL;
796}
748#else 797#else
749#warning Cache support not implemented for your current target. 798#warning Cache support not implemented for your target
750static char *lookup_cache_lib(elfobj *elf, char *fname) 799static char *lookup_cache_lib(elfobj *elf, char *fname)
751{ 800{
752 return NULL; 801 return NULL;
753} 802}
754#endif 803#endif
771 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 820 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
772 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 821 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
773 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 822 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
774 Elf ## B ## _Off offset; \ 823 Elf ## B ## _Off offset; \
775 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 824 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
776 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 825 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
777 offset = EGET(phdr[i].p_offset); \ 826 offset = EGET(phdr[i].p_offset); \
778 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 827 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
779 dyn = DYN ## B (elf->data + offset); \ 828 dyn = DYN ## B (elf->data + offset); \
780 while (EGET(dyn->d_tag) != DT_NULL) { \ 829 while (EGET(dyn->d_tag) != DT_NULL) { \
781 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 830 if (EGET(dyn->d_tag) == DT_NEEDED) { \
793 needed = p; \ 842 needed = p; \
794 xstrcat(ret, needed, ret_len); \ 843 xstrcat(ret, needed, ret_len); \
795 } \ 844 } \
796 *found_needed = 1; \ 845 *found_needed = 1; \
797 } else { \ 846 } else { \
798 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 847 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
799 *found_lib = 1; \ 848 *found_lib = 1; \
800 return (be_wewy_wewy_quiet ? NULL : needed); \ 849 return (be_wewy_wewy_quiet ? NULL : needed); \
801 } \ 850 } \
802 } \ 851 } \
803 } \ 852 } \
846 Elf ## B ## _Dyn *dyn; \ 895 Elf ## B ## _Dyn *dyn; \
847 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 896 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
848 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 897 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
849 Elf ## B ## _Off offset; \ 898 Elf ## B ## _Off offset; \
850 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 899 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
851 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 900 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
852 dynamic = 1; \ 901 dynamic = 1; \
853 offset = EGET(phdr[i].p_offset); \ 902 offset = EGET(phdr[i].p_offset); \
854 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 903 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
855 dyn = DYN ## B (elf->data + offset); \ 904 dyn = DYN ## B (elf->data + offset); \
856 while (EGET(dyn->d_tag) != DT_NULL) { \ 905 while (EGET(dyn->d_tag) != DT_NULL) { \
868 SHOW_BIND(32) 917 SHOW_BIND(32)
869 SHOW_BIND(64) 918 SHOW_BIND(64)
870 919
871 if (be_wewy_wewy_quiet) return NULL; 920 if (be_wewy_wewy_quiet) return NULL;
872 921
922 /* don't output anything if quiet mode and the ELF is static or not setuid */
873 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 923 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
874 return NULL; 924 return NULL;
875 } else { 925 } else {
876 *found_bind = 1; 926 *found_bind = 1;
877 return (char *) (dynamic ? "LAZY" : "STATIC"); 927 return (char *) (dynamic ? "LAZY" : "STATIC");
878 } 928 }
894 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 944 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
895 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 945 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
896 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 946 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
897 Elf ## B ## _Off offset; \ 947 Elf ## B ## _Off offset; \
898 /* only look for soname in shared objects */ \ 948 /* only look for soname in shared objects */ \
899 if (ehdr->e_type != ET_DYN) \ 949 if (EGET(ehdr->e_type) != ET_DYN) \
900 return NULL; \ 950 return NULL; \
901 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 951 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
902 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 952 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
903 offset = EGET(phdr[i].p_offset); \ 953 offset = EGET(phdr[i].p_offset); \
904 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 954 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
905 dyn = DYN ## B (elf->data + offset); \ 955 dyn = DYN ## B (elf->data + offset); \
906 while (EGET(dyn->d_tag) != DT_NULL) { \ 956 while (EGET(dyn->d_tag) != DT_NULL) { \
907 if (EGET(dyn->d_tag) == DT_SONAME) { \ 957 if (EGET(dyn->d_tag) == DT_SONAME) { \
921 SHOW_SONAME(64) 971 SHOW_SONAME(64)
922 } 972 }
923 973
924 return NULL; 974 return NULL;
925} 975}
976
926static char *scanelf_file_sym(elfobj *elf, char *found_sym) 977static char *scanelf_file_sym(elfobj *elf, char *found_sym)
927{ 978{
928 unsigned long i; 979 unsigned long i;
929 char *ret; 980 char *ret;
930 void *symtab_void, *strtab_void; 981 void *symtab_void, *strtab_void;
952 warnf("%s: corrupt ELF symbols", elf->filename); \ 1003 warnf("%s: corrupt ELF symbols", elf->filename); \
953 ++sym; \ 1004 ++sym; \
954 continue; \ 1005 continue; \
955 } \ 1006 } \
956 /* debug display ... show all symbols and some extra info */ \ 1007 /* debug display ... show all symbols and some extra info */ \
957 if (*ret == '*') { \ 1008 if (g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
958 printf("%s(%s) %5lX %15s %s\n", \ 1009 printf("%s(%s) %5lX %15s %s %s\n", \
959 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1010 ((*found_sym == 0) ? "\n\t" : "\t"), \
960 elf->base_filename, \ 1011 elf->base_filename, \
961 (unsigned long)sym->st_size, \ 1012 (unsigned long)sym->st_size, \
962 get_elfstttype(sym->st_info), \ 1013 get_elfstttype(sym->st_info), \
963 symname); \ 1014 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
964 *found_sym = 1; \ 1015 *found_sym = 1; \
965 } else { \ 1016 } else { \
966 /* allow the user to specify a comma delimited list of symbols to search for */ \ 1017 /* allow the user to specify a comma delimited list of symbols to search for */ \
967 char *this_sym, *next_sym; \ 1018 char *this_sym, *this_sym_ver, *next_sym; \
968 this_sym = ret; \ 1019 this_sym = ret; \
1020 this_sym_ver = versioned_symname; \
969 do { \ 1021 do { \
970 next_sym = strchr(this_sym, ','); \ 1022 next_sym = strchr(this_sym, ','); \
971 if (next_sym == NULL) \ 1023 if (next_sym == NULL) \
972 next_sym = this_sym + strlen(this_sym); \ 1024 next_sym = this_sym + strlen(this_sym); \
973 /* do we want a defined symbol ? */ \ 1025 /* do we want a defined symbol ? */ \
974 if (*this_sym == '+') { \ 1026 if (*this_sym == '+') { \
975 if (sym->st_shndx == SHN_UNDEF) \ 1027 if (sym->st_shndx == SHN_UNDEF) \
976 goto skip_this_sym##B; \ 1028 goto skip_this_sym##B; \
977 ++this_sym; \ 1029 ++this_sym; \
1030 ++this_sym_ver; \
978 /* do we want an undefined symbol ? */ \ 1031 /* do we want an undefined symbol ? */ \
979 } else if (*this_sym == '-') { \ 1032 } else if (*this_sym == '-') { \
980 if (sym->st_shndx != SHN_UNDEF) \ 1033 if (sym->st_shndx != SHN_UNDEF) \
981 goto skip_this_sym##B; \ 1034 goto skip_this_sym##B; \
982 ++this_sym; \ 1035 ++this_sym; \
1036 ++this_sym_ver; \
983 } \ 1037 } \
984 /* ok, lets compare the name now */ \ 1038 /* ok, lets compare the name now */ \
985 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \ 1039 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
986 (strcmp(symname, versioned_symname) == 0)) { \ 1040 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
987 if (be_semi_verbose) { \ 1041 if (be_semi_verbose) { \
988 char buf[126]; \ 1042 char buf[126]; \
989 snprintf(buf, sizeof(buf), "%lX %s %s", \ 1043 snprintf(buf, sizeof(buf), "%lX %s %s", \
990 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \ 1044 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
991 ret = buf; \ 1045 ret = buf; \
1048/* scan an elf file and show all the fun stuff */ 1102/* scan an elf file and show all the fun stuff */
1049#define prints(str) write(fileno(stdout), str, strlen(str)) 1103#define prints(str) write(fileno(stdout), str, strlen(str))
1050static int scanelf_elfobj(elfobj *elf) 1104static int scanelf_elfobj(elfobj *elf)
1051{ 1105{
1052 unsigned long i; 1106 unsigned long i;
1053 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1107 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1054 found_rpath, found_needed, found_interp, found_bind, found_soname, 1108 found_rpath, found_needed, found_interp, found_bind, found_soname,
1055 found_sym, found_lib, found_file, found_textrels, found_section; 1109 found_sym, found_lib, found_file, found_textrels, found_section;
1056 static char *out_buffer = NULL; 1110 static char *out_buffer = NULL;
1057 static size_t out_len; 1111 static size_t out_len;
1058 1112
1059 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1113 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1068 printf("%s: scanning file\n", elf->filename); 1122 printf("%s: scanning file\n", elf->filename);
1069 1123
1070 /* init output buffer */ 1124 /* init output buffer */
1071 if (!out_buffer) { 1125 if (!out_buffer) {
1072 out_len = sizeof(char) * 80; 1126 out_len = sizeof(char) * 80;
1073 out_buffer = (char*)xmalloc(out_len); 1127 out_buffer = xmalloc(out_len);
1074 } 1128 }
1075 *out_buffer = '\0'; 1129 *out_buffer = '\0';
1076 1130
1077 /* show the header */ 1131 /* show the header */
1078 if (!be_quiet && show_banner) { 1132 if (!be_quiet && show_banner) {
1089 case 'o': prints(" TYPE "); break; 1143 case 'o': prints(" TYPE "); break;
1090 case 'x': prints(" PAX "); break; 1144 case 'x': prints(" PAX "); break;
1091 case 'e': prints("STK/REL/PTL "); break; 1145 case 'e': prints("STK/REL/PTL "); break;
1092 case 't': prints("TEXTREL "); break; 1146 case 't': prints("TEXTREL "); break;
1093 case 'r': prints("RPATH "); break; 1147 case 'r': prints("RPATH "); break;
1148 case 'M': prints("CLASS "); break;
1094 case 'n': prints("NEEDED "); break; 1149 case 'n': prints("NEEDED "); break;
1095 case 'i': prints("INTERP "); break; 1150 case 'i': prints("INTERP "); break;
1096 case 'b': prints("BIND "); break; 1151 case 'b': prints("BIND "); break;
1097 case 'S': prints("SONAME "); break; 1152 case 'S': prints("SONAME "); break;
1098 case 's': prints("SYM "); break; 1153 case 's': prints("SYM "); break;
1099 case 'N': prints("LIB "); break; 1154 case 'N': prints("LIB "); break;
1100 case 'T': prints("TEXTRELS "); break; 1155 case 'T': prints("TEXTRELS "); break;
1101 case 'k': prints("SECTION "); break; 1156 case 'k': prints("SECTION "); break;
1157 case 'a': prints("ARCH "); break;
1158 case 'O': prints("PERM "); break;
1159 case 'D': prints("ENDIAN "); break;
1102 default: warnf("'%c' has no title ?", out_format[i]); 1160 default: warnf("'%c' has no title ?", out_format[i]);
1103 } 1161 }
1104 } 1162 }
1105 if (!found_file) prints("FILE "); 1163 if (!found_file) prints("FILE ");
1106 prints("\n"); 1164 prints("\n");
1156 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1214 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1157 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1215 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1158 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1216 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1159 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; 1217 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1160 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1218 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1219 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1220 case 'D': out = get_endian(elf); break;
1221 case 'O': out = getstr_perms(elf->filename); break;
1161 case 'n': 1222 case 'n':
1162 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1223 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1163 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1224 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1164 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1225 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1165 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1226 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1166 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1227 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1167 case 'k': out = scanelf_file_sections(elf, &found_section); break; 1228 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1229 case 'a': out = get_elfemtype(elf); break;
1168 default: warnf("'%c' has no scan code?", out_format[i]); 1230 default: warnf("'%c' has no scan code?", out_format[i]);
1169 } 1231 }
1170 if (out) { 1232 if (out) {
1171 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1233 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1172 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1234 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1218 if (strlen(match_etypes)) { 1280 if (strlen(match_etypes)) {
1219 char sbuf[126]; 1281 char sbuf[126];
1220 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1282 strncpy(sbuf, match_etypes, sizeof(sbuf));
1221 if (strchr(match_etypes, ',') != NULL) { 1283 if (strchr(match_etypes, ',') != NULL) {
1222 char *p; 1284 char *p;
1223 while((p = strrchr(sbuf, ',')) != NULL) { 1285 while ((p = strrchr(sbuf, ',')) != NULL) {
1224 *p = 0; 1286 *p = 0;
1225 if (etype_lookup(p+1) == get_etype(elf)) 1287 if (etype_lookup(p+1) == get_etype(elf))
1226 goto label_ret; 1288 goto label_ret;
1227 } 1289 }
1228 } 1290 }
1261 munmap(ar_buffer, len); 1323 munmap(ar_buffer, len);
1262 1324
1263 return 0; 1325 return 0;
1264} 1326}
1265/* scan a file which may be an elf or an archive or some other magical beast */ 1327/* scan a file which may be an elf or an archive or some other magical beast */
1266static void scanelf_file(const char *filename) 1328static int scanelf_file(const char *filename, const struct stat *st_cache)
1267{ 1329{
1330 const struct stat *st = st_cache;
1268 struct stat st; 1331 struct stat symlink_st;
1269 int fd; 1332 int fd;
1270 1333
1271 /* make sure 'filename' exists */
1272 if (lstat(filename, &st) == -1) {
1273 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1274 return;
1275 }
1276
1277 /* always handle regular files and handle symlinked files if no -y */ 1334 /* always handle regular files and handle symlinked files if no -y */
1278 if (S_ISLNK(st.st_mode)) { 1335 if (S_ISLNK(st->st_mode)) {
1279 if (!scan_symlink) return; 1336 if (!scan_symlink) return 1;
1280 stat(filename, &st); 1337 stat(filename, &symlink_st);
1338 st = &symlink_st;
1281 } 1339 }
1340
1282 if (!S_ISREG(st.st_mode)) { 1341 if (!S_ISREG(st->st_mode)) {
1283 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1342 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1284 return; 1343 return 1;
1285 } 1344 }
1286 1345
1346 if (match_perms) {
1347 if ((st->st_mode | match_perms) != st->st_mode)
1348 return 1;
1349 }
1287 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1350 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1288 return; 1351 return 1;
1289 1352
1290 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1353 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1291 /* if it isn't an ELF, maybe it's an .a archive */ 1354 /* if it isn't an ELF, maybe it's an .a archive */
1292 scanelf_archive(filename, fd, st.st_size); 1355 scanelf_archive(filename, fd, st->st_size);
1293 1356
1294 close(fd); 1357 close(fd);
1358 return 0;
1295} 1359}
1296 1360
1297/* scan a directory for ET_EXEC files and print when we find one */ 1361/* scan a directory for ET_EXEC files and print when we find one */
1298static void scanelf_dir(const char *path) 1362static int scanelf_dir(const char *path)
1299{ 1363{
1300 register DIR *dir; 1364 register DIR *dir;
1301 register struct dirent *dentry; 1365 register struct dirent *dentry;
1302 struct stat st_top, st; 1366 struct stat st_top, st;
1303 char buf[__PAX_UTILS_PATH_MAX]; 1367 char buf[__PAX_UTILS_PATH_MAX];
1304 size_t pathlen = 0, len = 0; 1368 size_t pathlen = 0, len = 0;
1369 int ret = 0;
1305 1370
1306 /* make sure path exists */ 1371 /* make sure path exists */
1307 if (lstat(path, &st_top) == -1) { 1372 if (lstat(path, &st_top) == -1) {
1308 if (be_verbose > 2) printf("%s: does not exist\n", path); 1373 if (be_verbose > 2) printf("%s: does not exist\n", path);
1309 return; 1374 return 1;
1310 } 1375 }
1311 1376
1312 /* ok, if it isn't a directory, assume we can open it */ 1377 /* ok, if it isn't a directory, assume we can open it */
1313 if (!S_ISDIR(st_top.st_mode)) { 1378 if (!S_ISDIR(st_top.st_mode)) {
1314 scanelf_file(path); 1379 return scanelf_file(path, &st_top);
1315 return;
1316 } 1380 }
1317 1381
1318 /* now scan the dir looking for fun stuff */ 1382 /* now scan the dir looking for fun stuff */
1319 if ((dir = opendir(path)) == NULL) { 1383 if ((dir = opendir(path)) == NULL) {
1320 warnf("could not opendir %s: %s", path, strerror(errno)); 1384 warnf("could not opendir %s: %s", path, strerror(errno));
1321 return; 1385 return 1;
1322 } 1386 }
1323 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1387 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1324 1388
1325 pathlen = strlen(path); 1389 pathlen = strlen(path);
1326 while ((dentry = readdir(dir))) { 1390 while ((dentry = readdir(dir))) {
1333 continue; 1397 continue;
1334 } 1398 }
1335 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name); 1399 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1336 if (lstat(buf, &st) != -1) { 1400 if (lstat(buf, &st) != -1) {
1337 if (S_ISREG(st.st_mode)) 1401 if (S_ISREG(st.st_mode))
1338 scanelf_file(buf); 1402 ret = scanelf_file(buf, &st);
1339 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1403 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1340 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1404 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1341 scanelf_dir(buf); 1405 ret = scanelf_dir(buf);
1342 } 1406 }
1343 } 1407 }
1344 } 1408 }
1345 closedir(dir); 1409 closedir(dir);
1410 return ret;
1346} 1411}
1347 1412
1348static int scanelf_from_file(const char *filename) 1413static int scanelf_from_file(const char *filename)
1349{ 1414{
1350 FILE *fp = NULL; 1415 FILE *fp = NULL;
1351 char *p; 1416 char *p;
1352 char path[__PAX_UTILS_PATH_MAX]; 1417 char path[__PAX_UTILS_PATH_MAX];
1418 int ret = 0;
1353 1419
1354 if (strcmp(filename, "-") == 0) 1420 if (strcmp(filename, "-") == 0)
1355 fp = stdin; 1421 fp = stdin;
1356 else if ((fp = fopen(filename, "r")) == NULL) 1422 else if ((fp = fopen(filename, "r")) == NULL)
1357 return 1; 1423 return 1;
1358 1424
1359 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1425 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1360 if ((p = strchr(path, '\n')) != NULL) 1426 if ((p = strchr(path, '\n')) != NULL)
1361 *p = 0; 1427 *p = 0;
1362 search_path = path; 1428 search_path = path;
1363 scanelf_dir(path); 1429 ret = scanelf_dir(path);
1364 } 1430 }
1365 if (fp != stdin) 1431 if (fp != stdin)
1366 fclose(fp); 1432 fclose(fp);
1367 return 0; 1433 return ret;
1368} 1434}
1369 1435
1370#if defined(__GLIBC__) || defined(__UCLIBC__) 1436#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1437
1371static int load_ld_so_conf(int i, const char *fname) 1438static int load_ld_cache_config(int i, const char *fname)
1372{ 1439{
1373 FILE *fp = NULL; 1440 FILE *fp = NULL;
1374 char *p; 1441 char *p;
1375 char path[__PAX_UTILS_PATH_MAX]; 1442 char path[__PAX_UTILS_PATH_MAX];
1376 1443
1377 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1444 if (i + 1 == ARRAY_SIZE(ldpaths))
1378 return i; 1445 return i;
1379 1446
1380 if ((fp = fopen(fname, "r")) == NULL) 1447 if ((fp = fopen(fname, "r")) == NULL)
1381 return i; 1448 return i;
1382 1449
1383 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1450 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1384 if ((p = strrchr(path, '\r')) != NULL) 1451 if ((p = strrchr(path, '\r')) != NULL)
1385 *p = 0; 1452 *p = 0;
1386 if ((p = strchr(path, '\n')) != NULL) 1453 if ((p = strchr(path, '\n')) != NULL)
1387 *p = 0; 1454 *p = 0;
1455#ifdef __linux__
1388 // recursive includes of the same file will make this segfault. 1456 /* recursive includes of the same file will make this segfault. */
1389 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { 1457 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1390 glob64_t gl; 1458 glob64_t gl;
1391 size_t x; 1459 size_t x;
1392 char gpath[__PAX_UTILS_PATH_MAX]; 1460 char gpath[__PAX_UTILS_PATH_MAX];
1393 1461
1401 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1469 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1402 for (x = 0; x < gl.gl_pathc; ++x) { 1470 for (x = 0; x < gl.gl_pathc; ++x) {
1403 /* try to avoid direct loops */ 1471 /* try to avoid direct loops */
1404 if (strcmp(gl.gl_pathv[x], fname) == 0) 1472 if (strcmp(gl.gl_pathv[x], fname) == 0)
1405 continue; 1473 continue;
1406 i = load_ld_so_conf(i, gl.gl_pathv[x]); 1474 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1407 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) { 1475 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1408 globfree64(&gl); 1476 globfree64(&gl);
1409 return i; 1477 return i;
1410 } 1478 }
1411 } 1479 }
1412 globfree64 (&gl); 1480 globfree64 (&gl);
1413 continue; 1481 continue;
1414 } else
1415 abort();
1416 } 1482 }
1483 }
1484#endif
1417 if (*path != '/') 1485 if (*path != '/')
1418 continue; 1486 continue;
1419 1487
1420 ldpaths[i++] = xstrdup(path); 1488 ldpaths[i++] = xstrdup(path);
1421 1489
1422 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1490 if (i + 1 == ARRAY_SIZE(ldpaths))
1423 break; 1491 break;
1424 } 1492 }
1425 ldpaths[i] = NULL; 1493 ldpaths[i] = NULL;
1426 1494
1427 fclose(fp); 1495 fclose(fp);
1428 return i; 1496 return i;
1429} 1497}
1430#endif
1431 1498
1432#if defined(__FreeBSD__) || (__DragonFly__) 1499#elif defined(__FreeBSD__) || (__DragonFly__)
1500
1433static int load_ld_so_hints(int i, const char *fname) 1501static int load_ld_cache_config(int i, const char *fname)
1434{ 1502{
1435 FILE *fp = NULL; 1503 FILE *fp = NULL;
1436 char *b = NULL, *p; 1504 char *b = NULL, *p;
1437 struct elfhints_hdr hdr; 1505 struct elfhints_hdr hdr;
1438 1506
1439 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1507 if (i + 1 == ARRAY_SIZE(ldpaths))
1440 return i; 1508 return i;
1441 1509
1442 if ((fp = fopen(fname, "r")) == NULL) 1510 if ((fp = fopen(fname, "r")) == NULL)
1443 return i; 1511 return i;
1444 1512
1445 if ( fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) || 1513 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1446 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 || 1514 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1447 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 1515 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1448 ) { 1516 {
1449 fclose(fp); 1517 fclose(fp);
1450 return i; 1518 return i;
1451 } 1519 }
1452 1520
1453 b = (char*)malloc(hdr.dirlistlen+1); 1521 b = xmalloc(hdr.dirlistlen + 1);
1454 if ( fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1 ) { 1522 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1455 fclose(fp); 1523 fclose(fp);
1456 free(b); 1524 free(b);
1457 return i; 1525 return i;
1458 } 1526 }
1459 1527
1460 while ( (p = strsep(&b, ":")) ) { 1528 while ((p = strsep(&b, ":"))) {
1461 if ( *p == '\0' ) continue; 1529 if (*p == '\0') continue;
1462 ldpaths[i++] = xstrdup(p); 1530 ldpaths[i++] = xstrdup(p);
1463 1531
1464 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1532 if (i + 1 == ARRAY_SIZE(ldpaths))
1465 break; 1533 break;
1466 } 1534 }
1467 ldpaths[i] = NULL; 1535 ldpaths[i] = NULL;
1468 1536
1469 free(b); 1537 free(b);
1470 fclose(fp); 1538 fclose(fp);
1471 return i; 1539 return i;
1472} 1540}
1541
1542#else
1543
1544#warning Cache config support not implemented for your target
1545static int load_ld_cache_config(int i, const char *fname)
1546{
1547 memset(ldpaths, 0x00, sizeof(ldpaths));
1548}
1549
1473#endif 1550#endif
1474 1551
1475/* scan /etc/ld.so.conf for paths */ 1552/* scan /etc/ld.so.conf for paths */
1476static void scanelf_ldpath() 1553static void scanelf_ldpath(void)
1477{ 1554{
1478 char scan_l, scan_ul, scan_ull; 1555 char scan_l, scan_ul, scan_ull;
1479 int i = 0; 1556 int i = 0;
1480 1557
1481 if (!ldpaths[0]) 1558 if (!ldpaths[0])
1495 if (!scan_ul) scanelf_dir("/usr/lib"); 1572 if (!scan_ul) scanelf_dir("/usr/lib");
1496 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1573 if (!scan_ull) scanelf_dir("/usr/local/lib");
1497} 1574}
1498 1575
1499/* scan env PATH for paths */ 1576/* scan env PATH for paths */
1500static void scanelf_envpath() 1577static void scanelf_envpath(void)
1501{ 1578{
1502 char *path, *p; 1579 char *path, *p;
1503 1580
1504 path = getenv("PATH"); 1581 path = getenv("PATH");
1505 if (!path) 1582 if (!path)
1512 } 1589 }
1513 1590
1514 free(path); 1591 free(path);
1515} 1592}
1516 1593
1517/* usage / invocation handling functions */ 1594
1595/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H I J K P Q U W Y Z */
1518#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV" 1596#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DO:BhV"
1519#define a_argument required_argument 1597#define a_argument required_argument
1520static struct option const long_opts[] = { 1598static struct option const long_opts[] = {
1521 {"path", no_argument, NULL, 'p'}, 1599 {"path", no_argument, NULL, 'p'},
1522 {"ldpath", no_argument, NULL, 'l'}, 1600 {"ldpath", no_argument, NULL, 'l'},
1523 {"recursive", no_argument, NULL, 'R'}, 1601 {"recursive", no_argument, NULL, 'R'},
1540 {"lib", a_argument, NULL, 'N'}, 1618 {"lib", a_argument, NULL, 'N'},
1541 {"gmatch", no_argument, NULL, 'g'}, 1619 {"gmatch", no_argument, NULL, 'g'},
1542 {"textrels", no_argument, NULL, 'T'}, 1620 {"textrels", no_argument, NULL, 'T'},
1543 {"etype", a_argument, NULL, 'E'}, 1621 {"etype", a_argument, NULL, 'E'},
1544 {"bits", a_argument, NULL, 'M'}, 1622 {"bits", a_argument, NULL, 'M'},
1623 {"endian", no_argument, NULL, 'D'},
1624 {"perms", a_argument, NULL, 'O'},
1545 {"all", no_argument, NULL, 'a'}, 1625 {"all", no_argument, NULL, 'a'},
1546 {"quiet", no_argument, NULL, 'q'}, 1626 {"quiet", no_argument, NULL, 'q'},
1547 {"verbose", no_argument, NULL, 'v'}, 1627 {"verbose", no_argument, NULL, 'v'},
1548 {"format", a_argument, NULL, 'F'}, 1628 {"format", a_argument, NULL, 'F'},
1549 {"from", a_argument, NULL, 'f'}, 1629 {"from", a_argument, NULL, 'f'},
1577 "Find a specified library", 1657 "Find a specified library",
1578 "Use strncmp to match libraries. (use with -N)", 1658 "Use strncmp to match libraries. (use with -N)",
1579 "Locate cause of TEXTREL", 1659 "Locate cause of TEXTREL",
1580 "Print only ELF files matching etype ET_DYN,ET_EXEC ...", 1660 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1581 "Print only ELF files matching numeric bits", 1661 "Print only ELF files matching numeric bits",
1662 "Print Endianness",
1663 "Print only ELF files matching octal permissions",
1582 "Print all scanned info (-x -e -t -r -b)\n", 1664 "Print all scanned info (-x -e -t -r -b)\n",
1583 "Only output 'bad' things", 1665 "Only output 'bad' things",
1584 "Be verbose (can be specified more than once)", 1666 "Be verbose (can be specified more than once)",
1585 "Use specified format for output", 1667 "Use specified format for output",
1586 "Read input stream from a filename", 1668 "Read input stream from a filename",
1598 printf("* Scan ELF binaries for stuff\n\n" 1680 printf("* Scan ELF binaries for stuff\n\n"
1599 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 1681 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1600 printf("Options: -[%s]\n", PARSE_FLAGS); 1682 printf("Options: -[%s]\n", PARSE_FLAGS);
1601 for (i = 0; long_opts[i].name; ++i) 1683 for (i = 0; long_opts[i].name; ++i)
1602 if (long_opts[i].has_arg == no_argument) 1684 if (long_opts[i].has_arg == no_argument)
1603 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 1685 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1604 long_opts[i].name, opts_help[i]); 1686 long_opts[i].name, opts_help[i]);
1605 else 1687 else
1606 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 1688 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1607 long_opts[i].name, opts_help[i]); 1689 long_opts[i].name, opts_help[i]);
1608 1690
1609 if (status != EXIT_SUCCESS) 1691 puts("\nFor more information, see the scanelf(1) manpage");
1610 exit(status);
1611
1612 puts("\nThe format modifiers for the -F option are:");
1613 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1614 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1615 puts(" i INTERP \tb BIND \ts symbol");
1616 puts(" N library \to Type \tT TEXTRELs");
1617 puts(" S SONAME \tk section");
1618 puts(" p filename (with search path removed)");
1619 puts(" f filename (short name/basename)");
1620 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1621
1622 puts("\nELF Etypes:");
1623 print_etypes(stdout);
1624
1625 exit(status); 1692 exit(status);
1626} 1693}
1627 1694
1628/* parse command line arguments and preform needed actions */ 1695/* parse command line arguments and preform needed actions */
1696#define do_pax_state(option, flag) \
1697 if (islower(option)) { \
1698 flags &= ~PF_##flag; \
1699 flags |= PF_NO##flag; \
1700 } else { \
1701 flags &= ~PF_NO##flag; \
1702 flags |= PF_##flag; \
1703 }
1629static void parseargs(int argc, char *argv[]) 1704static int parseargs(int argc, char *argv[])
1630{ 1705{
1631 int i; 1706 int i;
1632 const char *from_file = NULL; 1707 const char *from_file = NULL;
1708 int ret = 0;
1633 1709
1634 opterr = 0; 1710 opterr = 0;
1635 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1711 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1636 switch (i) { 1712 switch (i) {
1637 1713
1649 case 'E': 1725 case 'E':
1650 strncpy(match_etypes, optarg, sizeof(match_etypes)); 1726 strncpy(match_etypes, optarg, sizeof(match_etypes));
1651 break; 1727 break;
1652 case 'M': 1728 case 'M':
1653 match_bits = atoi(optarg); 1729 match_bits = atoi(optarg);
1730 if (match_bits == 0) {
1731 if (strcmp(optarg, "ELFCLASS32") == 0)
1732 match_bits = 32;
1733 if (strcmp(optarg, "ELFCLASS64") == 0)
1734 match_bits = 64;
1735 }
1736 break;
1737 case 'O':
1738 if (sscanf(optarg, "%o", &match_perms) == (-1))
1739 match_bits = 0;
1654 break; 1740 break;
1655 case 'o': { 1741 case 'o': {
1656 FILE *fp = NULL;
1657 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1742 if (freopen(optarg, "w", stdout) == NULL)
1658 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1743 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1659 SET_STDOUT(fp);
1660 break; 1744 break;
1661 } 1745 }
1662 case 'k': 1746 case 'k':
1663 if (find_section) warn("You prob don't want to specify -k twice"); 1747 if (find_section) warn("You prob don't want to specify -k twice");
1664 find_section = optarg; 1748 find_section = optarg;
1665 break; 1749 break;
1666 case 's': { 1750 case 's': {
1667 if (find_sym) warn("You prob don't want to specify -s twice"); 1751 if (find_sym) warn("You prob don't want to specify -s twice");
1668 find_sym = optarg; 1752 find_sym = optarg;
1669 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1753 versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1670 sprintf(versioned_symname, "%s@", find_sym); 1754 sprintf(versioned_symname, "%s@", find_sym);
1671 break; 1755 break;
1672 } 1756 }
1673 case 'N': { 1757 case 'N': {
1674 if (find_lib) warn("You prob don't want to specify -N twice"); 1758 if (find_lib) warn("You prob don't want to specify -N twice");
1683 } 1767 }
1684 case 'z': { 1768 case 'z': {
1685 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC); 1769 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1686 size_t x; 1770 size_t x;
1687 1771
1688 for (x = 0 ; x < strlen(optarg); x++) { 1772 for (x = 0; x < strlen(optarg); x++) {
1689 switch(optarg[x]) { 1773 switch (optarg[x]) {
1690 case 'p': 1774 case 'p':
1691 case 'P': 1775 case 'P':
1692 do_state(optarg[x], PAGEEXEC); 1776 do_pax_state(optarg[x], PAGEEXEC);
1693 break; 1777 break;
1694 case 's': 1778 case 's':
1695 case 'S': 1779 case 'S':
1696 do_state(optarg[x], SEGMEXEC); 1780 do_pax_state(optarg[x], SEGMEXEC);
1697 break; 1781 break;
1698 case 'm': 1782 case 'm':
1699 case 'M': 1783 case 'M':
1700 do_state(optarg[x], MPROTECT); 1784 do_pax_state(optarg[x], MPROTECT);
1701 break; 1785 break;
1702 case 'e': 1786 case 'e':
1703 case 'E': 1787 case 'E':
1704 do_state(optarg[x], EMUTRAMP); 1788 do_pax_state(optarg[x], EMUTRAMP);
1705 break; 1789 break;
1706 case 'r': 1790 case 'r':
1707 case 'R': 1791 case 'R':
1708 do_state(optarg[x], RANDMMAP); 1792 do_pax_state(optarg[x], RANDMMAP);
1709 break; 1793 break;
1710 case 'x': 1794 case 'x':
1711 case 'X': 1795 case 'X':
1712 do_state(optarg[x], RANDEXEC); 1796 do_pax_state(optarg[x], RANDEXEC);
1713 break; 1797 break;
1714 default: 1798 default:
1715 break; 1799 break;
1716 } 1800 }
1717 } 1801 }
1722 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) || 1806 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1723 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)))) 1807 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1724 setpax = flags; 1808 setpax = flags;
1725 break; 1809 break;
1726 } 1810 }
1727 case 'g': gmatch = 1; break; 1811 case 'g': g_match = 1; break;
1728 case 'L': use_ldcache = 1; break; 1812 case 'L': use_ldcache = 1; break;
1729 case 'y': scan_symlink = 0; break; 1813 case 'y': scan_symlink = 0; break;
1730 case 'A': scan_archives = 1; break; 1814 case 'A': scan_archives = 1; break;
1731 case 'B': show_banner = 0; break; 1815 case 'B': show_banner = 0; break;
1732 case 'l': scan_ldpath = 1; break; 1816 case 'l': scan_ldpath = 1; break;
1743 case 'b': show_bind = 1; break; 1827 case 'b': show_bind = 1; break;
1744 case 'S': show_soname = 1; break; 1828 case 'S': show_soname = 1; break;
1745 case 'T': show_textrels = 1; break; 1829 case 'T': show_textrels = 1; break;
1746 case 'q': be_quiet = 1; break; 1830 case 'q': be_quiet = 1; break;
1747 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1831 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1748 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1832 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1749 1833 case 'D': show_endian = 1; break;
1750 case ':': 1834 case ':':
1751 err("Option '%c' is missing parameter", optopt); 1835 err("Option '%c' is missing parameter", optopt);
1752 case '?': 1836 case '?':
1753 err("Unknown option '%c' or argument missing", optopt); 1837 err("Unknown option '%c' or argument missing", optopt);
1754 default: 1838 default:
1755 err("Unhandled option '%c'; please report this", i); 1839 err("Unhandled option '%c'; please report this", i);
1756 } 1840 }
1757 } 1841 }
1758 1842 if (show_textrels && be_verbose) {
1843 if (which("objdump") != NULL)
1844 has_objdump = 1;
1845 }
1759 /* let the format option override all other options */ 1846 /* let the format option override all other options */
1760 if (out_format) { 1847 if (out_format) {
1761 show_pax = show_phdr = show_textrel = show_rpath = \ 1848 show_pax = show_phdr = show_textrel = show_rpath = \
1762 show_needed = show_interp = show_bind = show_soname = \ 1849 show_needed = show_interp = show_bind = show_soname = \
1763 show_textrels = 0; 1850 show_textrels = show_perms = show_endian = 0;
1764 for (i = 0; out_format[i]; ++i) { 1851 for (i = 0; out_format[i]; ++i) {
1765 if (!IS_MODIFIER(out_format[i])) continue; 1852 if (!IS_MODIFIER(out_format[i])) continue;
1766 1853
1767 switch (out_format[++i]) { 1854 switch (out_format[++i]) {
1768 case '+': break; 1855 case '+': break;
1773 case 'f': break; 1860 case 'f': break;
1774 case 'k': break; 1861 case 'k': break;
1775 case 's': break; 1862 case 's': break;
1776 case 'N': break; 1863 case 'N': break;
1777 case 'o': break; 1864 case 'o': break;
1865 case 'a': break;
1866 case 'M': break;
1867 case 'D': show_endian = 1; break;
1868 case 'O': show_perms = 1; break;
1778 case 'x': show_pax = 1; break; 1869 case 'x': show_pax = 1; break;
1779 case 'e': show_phdr = 1; break; 1870 case 'e': show_phdr = 1; break;
1780 case 't': show_textrel = 1; break; 1871 case 't': show_textrel = 1; break;
1781 case 'r': show_rpath = 1; break; 1872 case 'r': show_rpath = 1; break;
1782 case 'n': show_needed = 1; break; 1873 case 'n': show_needed = 1; break;
1783 case 'i': show_interp = 1; break; 1874 case 'i': show_interp = 1; break;
1784 case 'b': show_bind = 1; break; 1875 case 'b': show_bind = 1; break;
1785 case 'S': show_soname = 1; break; 1876 case 'S': show_soname = 1; break;
1786 case 'T': show_textrels = 1; break; 1877 case 'T': show_textrels = 1; break;
1787 default: 1878 default:
1788 err("Invalid format specifier '%c' (byte %i)", 1879 err("Invalid format specifier '%c' (byte %i)",
1789 out_format[i], i+1); 1880 out_format[i], i+1);
1790 } 1881 }
1791 } 1882 }
1792 1883
1793 /* construct our default format */ 1884 /* construct our default format */
1794 } else { 1885 } else {
1795 size_t fmt_len = 30; 1886 size_t fmt_len = 30;
1796 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1887 out_format = xmalloc(sizeof(char) * fmt_len);
1797 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1888 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1798 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1889 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1890 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1891 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1799 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1892 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1800 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1893 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1801 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1894 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1802 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1895 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1803 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1896 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1811 } 1904 }
1812 if (be_verbose > 2) printf("Format: %s\n", out_format); 1905 if (be_verbose > 2) printf("Format: %s\n", out_format);
1813 1906
1814 /* now lets actually do the scanning */ 1907 /* now lets actually do the scanning */
1815 if (scan_ldpath || use_ldcache) 1908 if (scan_ldpath || use_ldcache)
1816#if defined(__GLIBC__) || defined(__UCLIBC__) 1909 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1817 load_ld_so_conf(0, "/etc/ld.so.conf");
1818#elif defined(__FreeBSD__) || defined(__DragonFly__)
1819 load_ld_so_hints(0, _PATH_ELF_HINTS);
1820#endif
1821 if (scan_ldpath) scanelf_ldpath(); 1910 if (scan_ldpath) scanelf_ldpath();
1822 if (scan_envpath) scanelf_envpath(); 1911 if (scan_envpath) scanelf_envpath();
1823 if (!from_file && optind == argc && ttyname(0) == NULL) 1912 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1824 from_file = "-"; 1913 from_file = "-";
1825 if (from_file) { 1914 if (from_file) {
1826 scanelf_from_file(from_file); 1915 scanelf_from_file(from_file);
1827 from_file = *argv; 1916 from_file = *argv;
1828 } 1917 }
1829 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1918 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1830 err("Nothing to scan !?"); 1919 err("Nothing to scan !?");
1831 while (optind < argc) { 1920 while (optind < argc) {
1832 search_path = argv[optind++]; 1921 search_path = argv[optind++];
1833 scanelf_dir(search_path); 1922 ret = scanelf_dir(search_path);
1834 } 1923 }
1835 1924
1836 /* clean up */ 1925 /* clean up */
1837 if (versioned_symname) free(versioned_symname); 1926 free(versioned_symname);
1838 for (i = 0; ldpaths[i]; ++i) 1927 for (i = 0; ldpaths[i]; ++i)
1839 free(ldpaths[i]); 1928 free(ldpaths[i]);
1840 1929
1841 if (ldcache != 0) 1930 if (ldcache != 0)
1842 munmap(ldcache, ldcache_size); 1931 munmap(ldcache, ldcache_size);
1932 return ret;
1843} 1933}
1844 1934
1845static char **get_split_env(const char *envvar) { 1935static char **get_split_env(const char *envvar)
1936{
1937 const char *delims = " \t\n";
1846 char **envvals = NULL; 1938 char **envvals = NULL;
1847 char *saveptr = NULL;
1848 char *env; 1939 char *env, *s;
1849 char *s;
1850 int nentry; 1940 int nentry;
1851 1941
1852 if ((env = getenv(envvar)) == NULL) 1942 if ((env = getenv(envvar)) == NULL)
1853 return NULL; 1943 return NULL;
1854 1944
1855 env = xstrdup(env); 1945 env = xstrdup(env);
1856 if (env == NULL) 1946 if (env == NULL)
1857 return NULL; 1947 return NULL;
1858 1948
1949 s = strtok(env, delims);
1950 if (s == NULL) {
1951 free(env);
1952 return NULL;
1953 }
1954
1859 nentry = 0; 1955 nentry = 0;
1860 for (s = strtok_r(env, " \t\n", &saveptr); s != NULL; s = strtok_r(NULL, " \t\n", &saveptr)) { 1956 while (s != NULL) {
1957 ++nentry;
1861 if ((envvals = xrealloc(envvals, sizeof(char *)*(nentry+1))) == NULL) 1958 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1862 return NULL;
1863 envvals[nentry++] = s; 1959 envvals[nentry-1] = s;
1960 s = strtok(NULL, delims);
1864 } 1961 }
1865 envvals[nentry] = NULL; 1962 envvals[nentry] = NULL;
1866 1963
1964 /* don't want to free(env) as it contains the memory that backs
1965 * the envvals array of strings */
1867 return envvals; 1966 return envvals;
1868} 1967}
1869 1968
1870static void parseenv() { 1969static void parseenv(void)
1970{
1871 qa_textrels=get_split_env("QA_TEXTRELS"); 1971 qa_textrels = get_split_env("QA_TEXTRELS");
1872 qa_execstack=get_split_env("QA_EXECSTACK"); 1972 qa_execstack = get_split_env("QA_EXECSTACK");
1973 qa_wx_load = get_split_env("QA_WX_LOAD");
1873} 1974}
1874 1975
1976#ifdef __PAX_UTILS_CLEANUP
1977static void cleanup(void)
1978{
1979 free(out_format);
1980 free(qa_textrels);
1981 free(qa_execstack);
1982 free(qa_wx_load);
1983}
1984#endif
1875 1985
1876 1986
1877int main(int argc, char *argv[]) 1987int main(int argc, char *argv[])
1878{ 1988{
1989 int ret;
1879 if (argc < 2) 1990 if (argc < 2)
1880 usage(EXIT_FAILURE); 1991 usage(EXIT_FAILURE);
1881 parseenv(); 1992 parseenv();
1882 parseargs(argc, argv); 1993 ret = parseargs(argc, argv);
1883 fclose(stdout); 1994 fclose(stdout);
1884#ifdef __BOUNDS_CHECKING_ON 1995#ifdef __PAX_UTILS_CLEANUP
1885 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 1996 cleanup();
1997 warn("The calls to add/delete heap should be off:\n"
1998 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1999 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1886#endif 2000#endif
1887 return EXIT_SUCCESS; 2001 return ret;
1888} 2002}
2003
2004
2005/* Match filename against entries in matchlist, return TRUE
2006 * if the file is listed */
2007static int file_matches_list(const char *filename, char **matchlist)
2008{
2009 char **file;
2010 char *match;
2011 char buf[__PAX_UTILS_PATH_MAX];
2012
2013 if (matchlist == NULL)
2014 return 0;
2015
2016 for (file = matchlist; *file != NULL; file++) {
2017 if (search_path) {
2018 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2019 match = buf;
2020 } else {
2021 match = *file;
2022 }
2023 if (fnmatch(match, filename, 0) == 0)
2024 return 1;
2025 }
2026 return 0;
2027}

Legend:
Removed from v.1.143  
changed lines
  Added in v.1.188

  ViewVC Help
Powered by ViewVC 1.1.20