/[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.132 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.132 2006/03/07 17:48:17 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 14
12static const char *rcsid = "$Id: scanelf.c,v 1.132 2006/03/07 17:48:17 solar Exp $";
13#define argv0 "scanelf"
14
15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16 16
17
18#define do_state(option, flag) \
19 if (islower(option)) { \
20 flags &= ~PF_##flag; \
21 flags |= PF_NO##flag; \
22 } else { \
23 flags &= ~PF_NO##flag; \
24 flags |= PF_##flag; \
25 }
26
27
28/* prototypes */ 17/* prototypes */
18static int file_matches_list(const char *filename, char **matchlist);
29static int scanelf_elfobj(elfobj *elf); 19static int scanelf_elfobj(elfobj *elf);
30static int scanelf_elf(const char *filename, int fd, size_t len); 20static int scanelf_elf(const char *filename, int fd, size_t len);
31static int scanelf_archive(const char *filename, int fd, size_t len); 21static int scanelf_archive(const char *filename, int fd, size_t len);
32static void scanelf_file(const char *filename); 22static int scanelf_file(const char *filename, const struct stat *st_cache);
33static void scanelf_dir(const char *path); 23static int scanelf_dir(const char *path);
34static void scanelf_ldpath(void); 24static void scanelf_ldpath(void);
35static void scanelf_envpath(void); 25static void scanelf_envpath(void);
36static void usage(int status); 26static void usage(int status);
27static char **get_split_env(const char *envvar);
28static void parseenv(void);
37static void parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
38static char *xstrdup(const char *s); 30static int rematch(const char *regex, const char *match, int cflags);
39static void *xmalloc(size_t size);
40static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
41#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
42static inline void xchrcat(char **dst, const char append, size_t *curr_len);
43 31
44/* variables to control behavior */ 32/* variables to control behavior */
45static char match_etypes[126] = ""; 33static char match_etypes[126] = "";
46static char *ldpaths[256]; 34static char *ldpaths[256];
47static char scan_ldpath = 0; 35static char scan_ldpath = 0;
49static char scan_symlink = 1; 37static char scan_symlink = 1;
50static char scan_archives = 0; 38static char scan_archives = 0;
51static char dir_recurse = 0; 39static char dir_recurse = 0;
52static char dir_crossmount = 1; 40static char dir_crossmount = 1;
53static char show_pax = 0; 41static char show_pax = 0;
42static char show_perms = 0;
54static char show_phdr = 0; 43static char show_phdr = 0;
55static char show_textrel = 0; 44static char show_textrel = 0;
56static char show_rpath = 0; 45static char show_rpath = 0;
57static char show_needed = 0; 46static char show_needed = 0;
58static char show_interp = 0; 47static char show_interp = 0;
59static char show_bind = 0; 48static char show_bind = 0;
60static char show_soname = 0; 49static char show_soname = 0;
61static char show_textrels = 0; 50static char show_textrels = 0;
62static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
63static char be_quiet = 0; 53static char be_quiet = 0;
64static char be_verbose = 0; 54static char be_verbose = 0;
65static char be_wewy_wewy_quiet = 0; 55static char be_wewy_wewy_quiet = 0;
66static char be_semi_verbose = 0; 56static char be_semi_verbose = 0;
67static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
68static char *find_lib = NULL; 58static char *find_lib = NULL;
69static char *find_section = NULL; 59static char *find_section = NULL;
70static char *out_format = NULL; 60static char *out_format = NULL;
71static char *search_path = NULL; 61static char *search_path = NULL;
72static char fix_elf = 0; 62static char fix_elf = 0;
73static char gmatch = 0; 63static char g_match = 0;
74static char use_ldcache = 0; 64static char use_ldcache = 0;
75 65
66static char **qa_textrels = NULL;
67static char **qa_execstack = NULL;
68static char **qa_wx_load = NULL;
69
76int match_bits = 0; 70int match_bits = 0;
71unsigned int match_perms = 0;
77caddr_t ldcache = 0; 72caddr_t ldcache = 0;
78size_t ldcache_size = 0; 73size_t ldcache_size = 0;
79unsigned long setpax = 0UL; 74unsigned long setpax = 0UL;
75
76int has_objdump = 0;
77
78static char *getstr_perms(const char *fname);
79static char *getstr_perms(const char *fname)
80{
81 struct stat st;
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
138 return ret;
139}
80 140
81/* sub-funcs for scanelf_file() */ 141/* sub-funcs for scanelf_file() */
82static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 142static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
83{ 143{
84 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 144 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
192 uint32_t flags, check_flags; \ 252 uint32_t flags, check_flags; \
193 if (elf->phdr != NULL) { \ 253 if (elf->phdr != NULL) { \
194 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 254 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
195 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 255 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
196 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 256 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
257 if (multi_stack++) \
197 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 258 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
259 if (file_matches_list(elf->filename, qa_execstack)) \
260 continue; \
198 found = found_phdr; \ 261 found = found_phdr; \
199 offset = 0; \ 262 offset = 0; \
200 check_flags = PF_X; \ 263 check_flags = PF_X; \
201 } 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++) \
202 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 266 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
203 found = found_relro; \ 267 found = found_relro; \
204 offset = 4; \ 268 offset = 4; \
205 check_flags = PF_X; \ 269 check_flags = PF_X; \
206 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 270 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
207 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) \
208 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; \
209 found = found_load; \ 276 found = found_load; \
210 offset = 8; \ 277 offset = 8; \
211 check_flags = PF_W|PF_X; \ 278 check_flags = PF_W|PF_X; \
212 } else \ 279 } else \
213 continue; \ 280 continue; \
250 break; \ 317 break; \
251 } \ 318 } \
252 } \ 319 } \
253 skip_this_shdr##B: \ 320 skip_this_shdr##B: \
254 if (!multi_stack) { \ 321 if (!multi_stack) { \
322 if (file_matches_list(elf->filename, qa_execstack)) \
323 return NULL; \
255 *found_phdr = 1; \ 324 *found_phdr = 1; \
256 shown = 1; \ 325 shown = 1; \
257 memcpy(ret, "!WX", 3); \ 326 memcpy(ret, "!WX", 3); \
258 } \ 327 } \
259 } \ 328 } \
264 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 333 if (be_wewy_wewy_quiet || (be_quiet && !shown))
265 return NULL; 334 return NULL;
266 else 335 else
267 return ret; 336 return ret;
268} 337}
338
339/*
340 * See if this ELF contains a DT_TEXTREL tag in any of its
341 * PT_DYNAMIC sections.
342 */
269static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 343static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
270{ 344{
271 static const char *ret = "TEXTREL"; 345 static const char *ret = "TEXTREL";
272 unsigned long i; 346 unsigned long i;
273 347
274 if (!show_textrel && !show_textrels) return NULL; 348 if (!show_textrel && !show_textrels) return NULL;
349
350 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
275 351
276 if (elf->phdr) { 352 if (elf->phdr) {
277#define SHOW_TEXTREL(B) \ 353#define SHOW_TEXTREL(B) \
278 if (elf->elf_class == ELFCLASS ## B) { \ 354 if (elf->elf_class == ELFCLASS ## B) { \
279 Elf ## B ## _Dyn *dyn; \ 355 Elf ## B ## _Dyn *dyn; \
280 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 356 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
281 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 357 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
282 Elf ## B ## _Off offset; \ 358 Elf ## B ## _Off offset; \
283 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 359 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
284 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; \
285 offset = EGET(phdr[i].p_offset); \ 361 offset = EGET(phdr[i].p_offset); \
286 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 362 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
287 dyn = DYN ## B (elf->data + offset); \ 363 dyn = DYN ## B (elf->data + offset); \
288 while (EGET(dyn->d_tag) != DT_NULL) { \ 364 while (EGET(dyn->d_tag) != DT_NULL) { \
289 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)*/ \
301 if (be_quiet || be_wewy_wewy_quiet) 377 if (be_quiet || be_wewy_wewy_quiet)
302 return NULL; 378 return NULL;
303 else 379 else
304 return " - "; 380 return " - ";
305} 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 */
306static 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)
307{ 389{
308 unsigned long s, r, rmax; 390 unsigned long s, r, rmax;
309 void *symtab_void, *strtab_void, *text_void; 391 void *symtab_void, *strtab_void, *text_void;
310 392
377 /* show the raw details about this reloc */ \ 459 /* show the raw details about this reloc */ \
378 printf(" %s: ", elf->base_filename); \ 460 printf(" %s: ", elf->base_filename); \
379 if (sym && sym->st_name) \ 461 if (sym && sym->st_name) \
380 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))); \
381 else \ 463 else \
382 printf("(memory/fake?)"); \ 464 printf("(memory/data?)"); \
383 printf(" [0x%lX]", (unsigned long)r_offset); \ 465 printf(" [0x%lX]", (unsigned long)r_offset); \
384 /* 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 */ \
385 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 467 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
386 func = NULL; \ 468 func = NULL; \
387 offset_tmp = 0; \ 469 offset_tmp = 0; \
391 offset_tmp = EGET(sym->st_value); \ 473 offset_tmp = EGET(sym->st_value); \
392 } \ 474 } \
393 ++sym; \ 475 ++sym; \
394 } \ 476 } \
395 printf(" in "); \ 477 printf(" in "); \
396 if (func && func->st_name) \ 478 if (func && func->st_name) { \
397 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); \
398 else \ 482 else \
399 printf("(NULL: fake?)"); \ 483 printf("%s", func_name); \
484 } else \
485 printf("(optimized out)"); \
400 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 } \
401 } \ 507 } \
402 } } 508 } }
403 SHOW_TEXTRELS(32) 509 SHOW_TEXTRELS(32)
404 SHOW_TEXTRELS(64) 510 SHOW_TEXTRELS(64)
405 } 511 }
423 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 529 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
424 break; 530 break;
425 case '$': 531 case '$':
426 if (fstat(elf->fd, &st) != -1) 532 if (fstat(elf->fd, &st) != -1)
427 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 533 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
428 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",
429 dt_type, item, elf->filename, st.st_mode & 07777); 535 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
430 break; 536 break;
431 default: 537 default:
432 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);
433 break; 539 break;
434 } 540 }
454 Elf ## B ## _Off offset; \ 560 Elf ## B ## _Off offset; \
455 Elf ## B ## _Xword word; \ 561 Elf ## B ## _Xword word; \
456 /* Scan all the program headers */ \ 562 /* Scan all the program headers */ \
457 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 563 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
458 /* Just scan dynamic headers */ \ 564 /* Just scan dynamic headers */ \
459 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; \
460 offset = EGET(phdr[i].p_offset); \ 566 offset = EGET(phdr[i].p_offset); \
461 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 567 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
462 /* Just scan dynamic RPATH/RUNPATH headers */ \ 568 /* Just scan dynamic RPATH/RUNPATH headers */ \
463 dyn = DYN ## B (elf->data + offset); \ 569 dyn = DYN ## B (elf->data + offset); \
464 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 570 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
593#define FLAG_POWERPC_LIB64 0x0500 699#define FLAG_POWERPC_LIB64 0x0500
594#define FLAG_MIPS64_LIBN32 0x0600 700#define FLAG_MIPS64_LIBN32 0x0600
595#define FLAG_MIPS64_LIBN64 0x0700 701#define FLAG_MIPS64_LIBN64 0x0700
596 702
597static char *lookup_cache_lib(elfobj *, char *); 703static char *lookup_cache_lib(elfobj *, char *);
704
705#if defined(__GLIBC__) || defined(__UCLIBC__)
706
598static char *lookup_cache_lib(elfobj *elf, char *fname) 707static char *lookup_cache_lib(elfobj *elf, char *fname)
599{ 708{
600 int fd = 0; 709 int fd = 0;
601 char *strs; 710 char *strs;
602 static char buf[__PAX_UTILS_PATH_MAX] = ""; 711 static char buf[__PAX_UTILS_PATH_MAX] = "";
658 continue; 767 continue;
659 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 768 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
660 } 769 }
661 return buf; 770 return buf;
662} 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;
663 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}
797#else
798#warning Cache support not implemented for your target
799static char *lookup_cache_lib(elfobj *elf, char *fname)
800{
801 return NULL;
802}
803#endif
664 804
665static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 805static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
666{ 806{
667 unsigned long i; 807 unsigned long i;
668 char *needed; 808 char *needed;
680 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 820 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
681 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 821 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
682 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 822 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
683 Elf ## B ## _Off offset; \ 823 Elf ## B ## _Off offset; \
684 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 824 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
685 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; \
686 offset = EGET(phdr[i].p_offset); \ 826 offset = EGET(phdr[i].p_offset); \
687 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 827 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
688 dyn = DYN ## B (elf->data + offset); \ 828 dyn = DYN ## B (elf->data + offset); \
689 while (EGET(dyn->d_tag) != DT_NULL) { \ 829 while (EGET(dyn->d_tag) != DT_NULL) { \
690 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 830 if (EGET(dyn->d_tag) == DT_NEEDED) { \
702 needed = p; \ 842 needed = p; \
703 xstrcat(ret, needed, ret_len); \ 843 xstrcat(ret, needed, ret_len); \
704 } \ 844 } \
705 *found_needed = 1; \ 845 *found_needed = 1; \
706 } else { \ 846 } else { \
707 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 847 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
708 *found_lib = 1; \ 848 *found_lib = 1; \
709 return (be_wewy_wewy_quiet ? NULL : needed); \ 849 return (be_wewy_wewy_quiet ? NULL : needed); \
710 } \ 850 } \
711 } \ 851 } \
712 } \ 852 } \
755 Elf ## B ## _Dyn *dyn; \ 895 Elf ## B ## _Dyn *dyn; \
756 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 896 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
757 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 897 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
758 Elf ## B ## _Off offset; \ 898 Elf ## B ## _Off offset; \
759 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 899 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
760 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; \
761 dynamic = 1; \ 901 dynamic = 1; \
762 offset = EGET(phdr[i].p_offset); \ 902 offset = EGET(phdr[i].p_offset); \
763 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 903 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
764 dyn = DYN ## B (elf->data + offset); \ 904 dyn = DYN ## B (elf->data + offset); \
765 while (EGET(dyn->d_tag) != DT_NULL) { \ 905 while (EGET(dyn->d_tag) != DT_NULL) { \
777 SHOW_BIND(32) 917 SHOW_BIND(32)
778 SHOW_BIND(64) 918 SHOW_BIND(64)
779 919
780 if (be_wewy_wewy_quiet) return NULL; 920 if (be_wewy_wewy_quiet) return NULL;
781 921
922 /* don't output anything if quiet mode and the ELF is static or not setuid */
782 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))))) {
783 return NULL; 924 return NULL;
784 } else { 925 } else {
785 *found_bind = 1; 926 *found_bind = 1;
786 return (char *) (dynamic ? "LAZY" : "STATIC"); 927 return (char *) (dynamic ? "LAZY" : "STATIC");
787 } 928 }
803 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 944 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
804 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 945 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
805 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 946 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
806 Elf ## B ## _Off offset; \ 947 Elf ## B ## _Off offset; \
807 /* only look for soname in shared objects */ \ 948 /* only look for soname in shared objects */ \
808 if (ehdr->e_type != ET_DYN) \ 949 if (EGET(ehdr->e_type) != ET_DYN) \
809 return NULL; \ 950 return NULL; \
810 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 951 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
811 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; \
812 offset = EGET(phdr[i].p_offset); \ 953 offset = EGET(phdr[i].p_offset); \
813 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 954 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
814 dyn = DYN ## B (elf->data + offset); \ 955 dyn = DYN ## B (elf->data + offset); \
815 while (EGET(dyn->d_tag) != DT_NULL) { \ 956 while (EGET(dyn->d_tag) != DT_NULL) { \
816 if (EGET(dyn->d_tag) == DT_SONAME) { \ 957 if (EGET(dyn->d_tag) == DT_SONAME) { \
830 SHOW_SONAME(64) 971 SHOW_SONAME(64)
831 } 972 }
832 973
833 return NULL; 974 return NULL;
834} 975}
976
835static char *scanelf_file_sym(elfobj *elf, char *found_sym) 977static char *scanelf_file_sym(elfobj *elf, char *found_sym)
836{ 978{
837 unsigned long i; 979 unsigned long i;
838 char *ret; 980 char *ret;
839 void *symtab_void, *strtab_void; 981 void *symtab_void, *strtab_void;
853 char *symname; \ 995 char *symname; \
854 if (cnt) \ 996 if (cnt) \
855 cnt = EGET(symtab->sh_size) / cnt; \ 997 cnt = EGET(symtab->sh_size) / cnt; \
856 for (i = 0; i < cnt; ++i) { \ 998 for (i = 0; i < cnt; ++i) { \
857 if (sym->st_name) { \ 999 if (sym->st_name) { \
1000 /* make sure the symbol name is in acceptable memory range */ \
858 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1001 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
859 if ((void*)symname > (void*)elf->data_end) { \ 1002 if ((void*)symname > (void*)elf->data_end) { \
860 warnf("%s: corrupt ELF symbols", elf->filename); \ 1003 warnf("%s: corrupt ELF symbols", elf->filename); \
1004 ++sym; \
861 continue; \ 1005 continue; \
862 } \ 1006 } \
863 if (*find_sym == '*') { \ 1007 /* debug display ... show all symbols and some extra info */ \
1008 if (g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
864 printf("%s(%s) %5lX %15s %s\n", \ 1009 printf("%s(%s) %5lX %15s %s %s\n", \
865 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1010 ((*found_sym == 0) ? "\n\t" : "\t"), \
866 elf->base_filename, \ 1011 elf->base_filename, \
867 (unsigned long)sym->st_size, \ 1012 (unsigned long)sym->st_size, \
868 get_elfstttype(sym->st_info), \ 1013 get_elfstttype(sym->st_info), \
869 symname); \ 1014 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
870 *found_sym = 1; \ 1015 *found_sym = 1; \
871 } else { \ 1016 } else { \
1017 /* allow the user to specify a comma delimited list of symbols to search for */ \
872 char *this_sym, *next_sym; \ 1018 char *this_sym, *this_sym_ver, *next_sym; \
1019 this_sym = ret; \
873 this_sym = find_sym; \ 1020 this_sym_ver = versioned_symname; \
874 do { \ 1021 do { \
875 next_sym = strchr(this_sym, ','); \ 1022 next_sym = strchr(this_sym, ','); \
876 if (next_sym == NULL) \ 1023 if (next_sym == NULL) \
877 next_sym = this_sym + strlen(this_sym); \ 1024 next_sym = this_sym + strlen(this_sym); \
1025 /* do we want a defined symbol ? */ \
1026 if (*this_sym == '+') { \
1027 if (sym->st_shndx == SHN_UNDEF) \
1028 goto skip_this_sym##B; \
1029 ++this_sym; \
1030 ++this_sym_ver; \
1031 /* do we want an undefined symbol ? */ \
1032 } else if (*this_sym == '-') { \
1033 if (sym->st_shndx != SHN_UNDEF) \
1034 goto skip_this_sym##B; \
1035 ++this_sym; \
1036 ++this_sym_ver; \
1037 } \
1038 /* ok, lets compare the name now */ \
878 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') || \
879 (strcmp(symname, versioned_symname) == 0)) { \ 1040 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
880 if (be_semi_verbose) { \ 1041 if (be_semi_verbose) { \
881 char buf[126]; \ 1042 char buf[126]; \
882 snprintf(buf, sizeof(buf), "%lX %s %s", \ 1043 snprintf(buf, sizeof(buf), "%lX %s %s", \
883 (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); \
884 ret = buf; \ 1045 ret = buf; \
885 } else \ 1046 } else \
886 ret = this_sym; \ 1047 ret = this_sym; \
887 (*found_sym)++; \ 1048 (*found_sym)++; \
888 goto break_out; \ 1049 goto break_out; \
889 } \ 1050 } \
890 this_sym = next_sym + 1; \ 1051 skip_this_sym##B: this_sym = next_sym + 1; \
891 } while (*next_sym != '\0'); \ 1052 } while (*next_sym != '\0'); \
892 } \ 1053 } \
893 } \ 1054 } \
894 ++sym; \ 1055 ++sym; \
895 } } 1056 } }
914 if (!find_section) 1075 if (!find_section)
915 return NULL; 1076 return NULL;
916 1077
917#define FIND_SECTION(B) \ 1078#define FIND_SECTION(B) \
918 if (elf->elf_class == ELFCLASS ## B) { \ 1079 if (elf->elf_class == ELFCLASS ## B) { \
1080 int invert; \
919 Elf ## B ## _Shdr *section; \ 1081 Elf ## B ## _Shdr *section; \
1082 invert = (*find_section == '!' ? 1 : 0); \
920 section = SHDR ## B (elf_findsecbyname(elf, find_section)); \ 1083 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
921 if (section != NULL) \ 1084 if ((section == NULL && invert) || (section != NULL && !invert)) \
922 *found_section = 1; \ 1085 *found_section = 1; \
923 } 1086 }
924 FIND_SECTION(32) 1087 FIND_SECTION(32)
925 FIND_SECTION(64) 1088 FIND_SECTION(64)
926 1089
927
928 if (be_wewy_wewy_quiet) return NULL; 1090 if (be_wewy_wewy_quiet)
1091 return NULL;
929 1092
930 if (*found_section) 1093 if (*found_section)
931 return find_section; 1094 return find_section;
932 1095
933 if (be_quiet) 1096 if (be_quiet)
939/* scan an elf file and show all the fun stuff */ 1102/* scan an elf file and show all the fun stuff */
940#define prints(str) write(fileno(stdout), str, strlen(str)) 1103#define prints(str) write(fileno(stdout), str, strlen(str))
941static int scanelf_elfobj(elfobj *elf) 1104static int scanelf_elfobj(elfobj *elf)
942{ 1105{
943 unsigned long i; 1106 unsigned long i;
944 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1107 char found_pax, found_phdr, found_relro, found_load, found_textrel,
945 found_rpath, found_needed, found_interp, found_bind, found_soname, 1108 found_rpath, found_needed, found_interp, found_bind, found_soname,
946 found_sym, found_lib, found_file, found_textrels, found_section; 1109 found_sym, found_lib, found_file, found_textrels, found_section;
947 static char *out_buffer = NULL; 1110 static char *out_buffer = NULL;
948 static size_t out_len; 1111 static size_t out_len;
949 1112
950 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1113 found_pax = found_phdr = found_relro = found_load = found_textrel = \
959 printf("%s: scanning file\n", elf->filename); 1122 printf("%s: scanning file\n", elf->filename);
960 1123
961 /* init output buffer */ 1124 /* init output buffer */
962 if (!out_buffer) { 1125 if (!out_buffer) {
963 out_len = sizeof(char) * 80; 1126 out_len = sizeof(char) * 80;
964 out_buffer = (char*)xmalloc(out_len); 1127 out_buffer = xmalloc(out_len);
965 } 1128 }
966 *out_buffer = '\0'; 1129 *out_buffer = '\0';
967 1130
968 /* show the header */ 1131 /* show the header */
969 if (!be_quiet && show_banner) { 1132 if (!be_quiet && show_banner) {
980 case 'o': prints(" TYPE "); break; 1143 case 'o': prints(" TYPE "); break;
981 case 'x': prints(" PAX "); break; 1144 case 'x': prints(" PAX "); break;
982 case 'e': prints("STK/REL/PTL "); break; 1145 case 'e': prints("STK/REL/PTL "); break;
983 case 't': prints("TEXTREL "); break; 1146 case 't': prints("TEXTREL "); break;
984 case 'r': prints("RPATH "); break; 1147 case 'r': prints("RPATH "); break;
1148 case 'M': prints("CLASS "); break;
985 case 'n': prints("NEEDED "); break; 1149 case 'n': prints("NEEDED "); break;
986 case 'i': prints("INTERP "); break; 1150 case 'i': prints("INTERP "); break;
987 case 'b': prints("BIND "); break; 1151 case 'b': prints("BIND "); break;
988 case 'S': prints("SONAME "); break; 1152 case 'S': prints("SONAME "); break;
989 case 's': prints("SYM "); break; 1153 case 's': prints("SYM "); break;
990 case 'N': prints("LIB "); break; 1154 case 'N': prints("LIB "); break;
991 case 'T': prints("TEXTRELS "); break; 1155 case 'T': prints("TEXTRELS "); break;
992 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;
993 default: warnf("'%c' has no title ?", out_format[i]); 1160 default: warnf("'%c' has no title ?", out_format[i]);
994 } 1161 }
995 } 1162 }
996 if (!found_file) prints("FILE "); 1163 if (!found_file) prints("FILE ");
997 prints("\n"); 1164 prints("\n");
1047 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1214 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1048 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;
1049 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1216 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1050 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;
1051 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;
1052 case 'n': 1222 case 'n':
1053 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;
1054 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1224 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1055 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1225 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1056 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1226 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1057 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1227 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1058 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;
1059 default: warnf("'%c' has no scan code?", out_format[i]); 1230 default: warnf("'%c' has no scan code?", out_format[i]);
1060 } 1231 }
1061 if (out) { 1232 if (out) {
1062 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1233 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1063 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1234 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1109 if (strlen(match_etypes)) { 1280 if (strlen(match_etypes)) {
1110 char sbuf[126]; 1281 char sbuf[126];
1111 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1282 strncpy(sbuf, match_etypes, sizeof(sbuf));
1112 if (strchr(match_etypes, ',') != NULL) { 1283 if (strchr(match_etypes, ',') != NULL) {
1113 char *p; 1284 char *p;
1114 while((p = strrchr(sbuf, ',')) != NULL) { 1285 while ((p = strrchr(sbuf, ',')) != NULL) {
1115 *p = 0; 1286 *p = 0;
1116 if (etype_lookup(p+1) == get_etype(elf)) 1287 if (etype_lookup(p+1) == get_etype(elf))
1117 goto label_ret; 1288 goto label_ret;
1118 } 1289 }
1119 } 1290 }
1152 munmap(ar_buffer, len); 1323 munmap(ar_buffer, len);
1153 1324
1154 return 0; 1325 return 0;
1155} 1326}
1156/* 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 */
1157static void scanelf_file(const char *filename) 1328static int scanelf_file(const char *filename, const struct stat *st_cache)
1158{ 1329{
1330 const struct stat *st = st_cache;
1159 struct stat st; 1331 struct stat symlink_st;
1160 int fd; 1332 int fd;
1161 1333
1162 /* make sure 'filename' exists */
1163 if (lstat(filename, &st) == -1) {
1164 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1165 return;
1166 }
1167
1168 /* always handle regular files and handle symlinked files if no -y */ 1334 /* always handle regular files and handle symlinked files if no -y */
1169 if (S_ISLNK(st.st_mode)) { 1335 if (S_ISLNK(st->st_mode)) {
1170 if (!scan_symlink) return; 1336 if (!scan_symlink) return 1;
1171 stat(filename, &st); 1337 stat(filename, &symlink_st);
1338 st = &symlink_st;
1172 } 1339 }
1340
1173 if (!S_ISREG(st.st_mode)) { 1341 if (!S_ISREG(st->st_mode)) {
1174 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1342 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1175 return; 1343 return 1;
1176 } 1344 }
1177 1345
1346 if (match_perms) {
1347 if ((st->st_mode | match_perms) != st->st_mode)
1348 return 1;
1349 }
1178 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1350 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1179 return; 1351 return 1;
1180 1352
1181 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1353 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1182 /* 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 */
1183 scanelf_archive(filename, fd, st.st_size); 1355 scanelf_archive(filename, fd, st->st_size);
1184 1356
1185 close(fd); 1357 close(fd);
1358 return 0;
1186} 1359}
1187 1360
1188/* 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 */
1189static void scanelf_dir(const char *path) 1362static int scanelf_dir(const char *path)
1190{ 1363{
1191 register DIR *dir; 1364 register DIR *dir;
1192 register struct dirent *dentry; 1365 register struct dirent *dentry;
1193 struct stat st_top, st; 1366 struct stat st_top, st;
1194 char buf[__PAX_UTILS_PATH_MAX]; 1367 char buf[__PAX_UTILS_PATH_MAX];
1195 size_t pathlen = 0, len = 0; 1368 size_t pathlen = 0, len = 0;
1369 int ret = 0;
1196 1370
1197 /* make sure path exists */ 1371 /* make sure path exists */
1198 if (lstat(path, &st_top) == -1) { 1372 if (lstat(path, &st_top) == -1) {
1199 if (be_verbose > 2) printf("%s: does not exist\n", path); 1373 if (be_verbose > 2) printf("%s: does not exist\n", path);
1200 return; 1374 return 1;
1201 } 1375 }
1202 1376
1203 /* 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 */
1204 if (!S_ISDIR(st_top.st_mode)) { 1378 if (!S_ISDIR(st_top.st_mode)) {
1205 scanelf_file(path); 1379 return scanelf_file(path, &st_top);
1206 return;
1207 } 1380 }
1208 1381
1209 /* now scan the dir looking for fun stuff */ 1382 /* now scan the dir looking for fun stuff */
1210 if ((dir = opendir(path)) == NULL) { 1383 if ((dir = opendir(path)) == NULL) {
1211 warnf("could not opendir %s: %s", path, strerror(errno)); 1384 warnf("could not opendir %s: %s", path, strerror(errno));
1212 return; 1385 return 1;
1213 } 1386 }
1214 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1387 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1215 1388
1216 pathlen = strlen(path); 1389 pathlen = strlen(path);
1217 while ((dentry = readdir(dir))) { 1390 while ((dentry = readdir(dir))) {
1221 if (len >= sizeof(buf)) { 1394 if (len >= sizeof(buf)) {
1222 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1395 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1223 (unsigned long)len, (unsigned long)sizeof(buf)); 1396 (unsigned long)len, (unsigned long)sizeof(buf));
1224 continue; 1397 continue;
1225 } 1398 }
1226 sprintf(buf, "%s/%s", path, dentry->d_name); 1399 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1227 if (lstat(buf, &st) != -1) { 1400 if (lstat(buf, &st) != -1) {
1228 if (S_ISREG(st.st_mode)) 1401 if (S_ISREG(st.st_mode))
1229 scanelf_file(buf); 1402 ret = scanelf_file(buf, &st);
1230 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1403 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1231 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1404 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1232 scanelf_dir(buf); 1405 ret = scanelf_dir(buf);
1233 } 1406 }
1234 } 1407 }
1235 } 1408 }
1236 closedir(dir); 1409 closedir(dir);
1410 return ret;
1237} 1411}
1238 1412
1239static int scanelf_from_file(char *filename) 1413static int scanelf_from_file(const char *filename)
1240{ 1414{
1241 FILE *fp = NULL; 1415 FILE *fp = NULL;
1242 char *p; 1416 char *p;
1243 char path[__PAX_UTILS_PATH_MAX]; 1417 char path[__PAX_UTILS_PATH_MAX];
1418 int ret = 0;
1244 1419
1245 if (strcmp(filename, "-") == 0) 1420 if (strcmp(filename, "-") == 0)
1246 fp = stdin; 1421 fp = stdin;
1247 else if ((fp = fopen(filename, "r")) == NULL) 1422 else if ((fp = fopen(filename, "r")) == NULL)
1248 return 1; 1423 return 1;
1249 1424
1250 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1425 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1251 if ((p = strchr(path, '\n')) != NULL) 1426 if ((p = strchr(path, '\n')) != NULL)
1252 *p = 0; 1427 *p = 0;
1253 search_path = path; 1428 search_path = path;
1254 scanelf_dir(path); 1429 ret = scanelf_dir(path);
1255 } 1430 }
1256 if (fp != stdin) 1431 if (fp != stdin)
1257 fclose(fp); 1432 fclose(fp);
1258 return 0; 1433 return ret;
1259} 1434}
1260 1435
1436#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1437
1261static int load_ld_so_conf(int i, const char *fname) 1438static int load_ld_cache_config(int i, const char *fname)
1262{ 1439{
1263 FILE *fp = NULL; 1440 FILE *fp = NULL;
1264 char *p; 1441 char *p;
1265 char path[__PAX_UTILS_PATH_MAX]; 1442 char path[__PAX_UTILS_PATH_MAX];
1266 1443
1267 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1444 if (i + 1 == ARRAY_SIZE(ldpaths))
1268 return i; 1445 return i;
1269 1446
1270 if ((fp = fopen(fname, "r")) == NULL) 1447 if ((fp = fopen(fname, "r")) == NULL)
1271 return i; 1448 return i;
1272 1449
1273 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1450 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1274 if ((p = strrchr(path, '\r')) != NULL) 1451 if ((p = strrchr(path, '\r')) != NULL)
1275 *p = 0; 1452 *p = 0;
1276 if ((p = strchr(path, '\n')) != NULL) 1453 if ((p = strchr(path, '\n')) != NULL)
1277 *p = 0; 1454 *p = 0;
1278#ifdef HAVE_GLOB 1455#ifdef __linux__
1279 // recursive includes of the same file will make this segfault. 1456 /* recursive includes of the same file will make this segfault. */
1280 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { 1457 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1281 glob64_t gl; 1458 glob64_t gl;
1282 size_t x; 1459 size_t x;
1283 char gpath[__PAX_UTILS_PATH_MAX]; 1460 char gpath[__PAX_UTILS_PATH_MAX];
1284 1461
1292 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1469 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1293 for (x = 0; x < gl.gl_pathc; ++x) { 1470 for (x = 0; x < gl.gl_pathc; ++x) {
1294 /* try to avoid direct loops */ 1471 /* try to avoid direct loops */
1295 if (strcmp(gl.gl_pathv[x], fname) == 0) 1472 if (strcmp(gl.gl_pathv[x], fname) == 0)
1296 continue; 1473 continue;
1297 i = load_ld_so_conf(i, gl.gl_pathv[x]); 1474 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1298 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) { 1475 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1299 globfree64(&gl); 1476 globfree64(&gl);
1300 return i; 1477 return i;
1301 } 1478 }
1302 } 1479 }
1303 globfree64 (&gl); 1480 globfree64 (&gl);
1304 continue; 1481 continue;
1305 } else 1482 }
1306 abort();
1307 } 1483 }
1308#endif 1484#endif
1309 if (*path != '/') 1485 if (*path != '/')
1310 continue; 1486 continue;
1311 1487
1312 ldpaths[i++] = xstrdup(path); 1488 ldpaths[i++] = xstrdup(path);
1313 1489
1314 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1490 if (i + 1 == ARRAY_SIZE(ldpaths))
1315 break; 1491 break;
1316 } 1492 }
1317 ldpaths[i] = NULL; 1493 ldpaths[i] = NULL;
1318 1494
1319 fclose(fp); 1495 fclose(fp);
1320 return i; 1496 return i;
1321} 1497}
1322 1498
1499#elif defined(__FreeBSD__) || (__DragonFly__)
1500
1501static int load_ld_cache_config(int i, const char *fname)
1502{
1503 FILE *fp = NULL;
1504 char *b = NULL, *p;
1505 struct elfhints_hdr hdr;
1506
1507 if (i + 1 == ARRAY_SIZE(ldpaths))
1508 return i;
1509
1510 if ((fp = fopen(fname, "r")) == NULL)
1511 return i;
1512
1513 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1514 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1515 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1516 {
1517 fclose(fp);
1518 return i;
1519 }
1520
1521 b = xmalloc(hdr.dirlistlen + 1);
1522 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1523 fclose(fp);
1524 free(b);
1525 return i;
1526 }
1527
1528 while ((p = strsep(&b, ":"))) {
1529 if (*p == '\0') continue;
1530 ldpaths[i++] = xstrdup(p);
1531
1532 if (i + 1 == ARRAY_SIZE(ldpaths))
1533 break;
1534 }
1535 ldpaths[i] = NULL;
1536
1537 free(b);
1538 fclose(fp);
1539 return i;
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
1550#endif
1551
1323/* scan /etc/ld.so.conf for paths */ 1552/* scan /etc/ld.so.conf for paths */
1324static void scanelf_ldpath() 1553static void scanelf_ldpath(void)
1325{ 1554{
1326 char scan_l, scan_ul, scan_ull; 1555 char scan_l, scan_ul, scan_ull;
1327 int i = 0; 1556 int i = 0;
1328 1557
1329 if (!ldpaths[0]) 1558 if (!ldpaths[0])
1343 if (!scan_ul) scanelf_dir("/usr/lib"); 1572 if (!scan_ul) scanelf_dir("/usr/lib");
1344 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1573 if (!scan_ull) scanelf_dir("/usr/local/lib");
1345} 1574}
1346 1575
1347/* scan env PATH for paths */ 1576/* scan env PATH for paths */
1348static void scanelf_envpath() 1577static void scanelf_envpath(void)
1349{ 1578{
1350 char *path, *p; 1579 char *path, *p;
1351 1580
1352 path = getenv("PATH"); 1581 path = getenv("PATH");
1353 if (!path) 1582 if (!path)
1360 } 1589 }
1361 1590
1362 free(path); 1591 free(path);
1363} 1592}
1364 1593
1365/* 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 */
1366#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"
1367#define a_argument required_argument 1597#define a_argument required_argument
1368static struct option const long_opts[] = { 1598static struct option const long_opts[] = {
1369 {"path", no_argument, NULL, 'p'}, 1599 {"path", no_argument, NULL, 'p'},
1370 {"ldpath", no_argument, NULL, 'l'}, 1600 {"ldpath", no_argument, NULL, 'l'},
1371 {"recursive", no_argument, NULL, 'R'}, 1601 {"recursive", no_argument, NULL, 'R'},
1388 {"lib", a_argument, NULL, 'N'}, 1618 {"lib", a_argument, NULL, 'N'},
1389 {"gmatch", no_argument, NULL, 'g'}, 1619 {"gmatch", no_argument, NULL, 'g'},
1390 {"textrels", no_argument, NULL, 'T'}, 1620 {"textrels", no_argument, NULL, 'T'},
1391 {"etype", a_argument, NULL, 'E'}, 1621 {"etype", a_argument, NULL, 'E'},
1392 {"bits", a_argument, NULL, 'M'}, 1622 {"bits", a_argument, NULL, 'M'},
1623 {"endian", no_argument, NULL, 'D'},
1624 {"perms", a_argument, NULL, 'O'},
1393 {"all", no_argument, NULL, 'a'}, 1625 {"all", no_argument, NULL, 'a'},
1394 {"quiet", no_argument, NULL, 'q'}, 1626 {"quiet", no_argument, NULL, 'q'},
1395 {"verbose", no_argument, NULL, 'v'}, 1627 {"verbose", no_argument, NULL, 'v'},
1396 {"format", a_argument, NULL, 'F'}, 1628 {"format", a_argument, NULL, 'F'},
1397 {"from", a_argument, NULL, 'f'}, 1629 {"from", a_argument, NULL, 'f'},
1425 "Find a specified library", 1657 "Find a specified library",
1426 "Use strncmp to match libraries. (use with -N)", 1658 "Use strncmp to match libraries. (use with -N)",
1427 "Locate cause of TEXTREL", 1659 "Locate cause of TEXTREL",
1428 "Print only ELF files matching etype ET_DYN,ET_EXEC ...", 1660 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1429 "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",
1430 "Print all scanned info (-x -e -t -r -b)\n", 1664 "Print all scanned info (-x -e -t -r -b)\n",
1431 "Only output 'bad' things", 1665 "Only output 'bad' things",
1432 "Be verbose (can be specified more than once)", 1666 "Be verbose (can be specified more than once)",
1433 "Use specified format for output", 1667 "Use specified format for output",
1434 "Read input stream from a filename", 1668 "Read input stream from a filename",
1446 printf("* Scan ELF binaries for stuff\n\n" 1680 printf("* Scan ELF binaries for stuff\n\n"
1447 "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);
1448 printf("Options: -[%s]\n", PARSE_FLAGS); 1682 printf("Options: -[%s]\n", PARSE_FLAGS);
1449 for (i = 0; long_opts[i].name; ++i) 1683 for (i = 0; long_opts[i].name; ++i)
1450 if (long_opts[i].has_arg == no_argument) 1684 if (long_opts[i].has_arg == no_argument)
1451 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 1685 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1452 long_opts[i].name, opts_help[i]); 1686 long_opts[i].name, opts_help[i]);
1453 else 1687 else
1454 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 1688 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1455 long_opts[i].name, opts_help[i]); 1689 long_opts[i].name, opts_help[i]);
1456 1690
1457 if (status != EXIT_SUCCESS) 1691 puts("\nFor more information, see the scanelf(1) manpage");
1458 exit(status);
1459
1460 puts("\nThe format modifiers for the -F option are:");
1461 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1462 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1463 puts(" i INTERP \tb BIND \ts symbol");
1464 puts(" N library \to Type \tT TEXTRELs");
1465 puts(" S SONAME \tk section");
1466 puts(" p filename (with search path removed)");
1467 puts(" f filename (short name/basename)");
1468 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1469
1470 puts("\nELF Etypes:");
1471 print_etypes(stdout);
1472
1473 exit(status); 1692 exit(status);
1474} 1693}
1475 1694
1476/* 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 }
1477static void parseargs(int argc, char *argv[]) 1704static int parseargs(int argc, char *argv[])
1478{ 1705{
1479 int i; 1706 int i;
1480 char *from_file = NULL; 1707 const char *from_file = NULL;
1708 int ret = 0;
1481 1709
1482 opterr = 0; 1710 opterr = 0;
1483 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) {
1484 switch (i) { 1712 switch (i) {
1485 1713
1497 case 'E': 1725 case 'E':
1498 strncpy(match_etypes, optarg, sizeof(match_etypes)); 1726 strncpy(match_etypes, optarg, sizeof(match_etypes));
1499 break; 1727 break;
1500 case 'M': 1728 case 'M':
1501 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;
1502 break; 1740 break;
1503 case 'o': { 1741 case 'o': {
1504 FILE *fp = NULL;
1505 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1742 if (freopen(optarg, "w", stdout) == NULL)
1506 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1743 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1507 SET_STDOUT(fp);
1508 break; 1744 break;
1509 } 1745 }
1510 case 'k': 1746 case 'k':
1511 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");
1512 find_section = optarg; 1748 find_section = optarg;
1513 break; 1749 break;
1514 case 's': { 1750 case 's': {
1515 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");
1516 find_sym = optarg; 1752 find_sym = optarg;
1517 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1753 versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1518 sprintf(versioned_symname, "%s@", find_sym); 1754 sprintf(versioned_symname, "%s@", find_sym);
1519 break; 1755 break;
1520 } 1756 }
1521 case 'N': { 1757 case 'N': {
1522 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");
1531 } 1767 }
1532 case 'z': { 1768 case 'z': {
1533 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC); 1769 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1534 size_t x; 1770 size_t x;
1535 1771
1536 for (x = 0 ; x < strlen(optarg); x++) { 1772 for (x = 0; x < strlen(optarg); x++) {
1537 switch(optarg[x]) { 1773 switch (optarg[x]) {
1538 case 'p': 1774 case 'p':
1539 case 'P': 1775 case 'P':
1540 do_state(optarg[x], PAGEEXEC); 1776 do_pax_state(optarg[x], PAGEEXEC);
1541 break; 1777 break;
1542 case 's': 1778 case 's':
1543 case 'S': 1779 case 'S':
1544 do_state(optarg[x], SEGMEXEC); 1780 do_pax_state(optarg[x], SEGMEXEC);
1545 break; 1781 break;
1546 case 'm': 1782 case 'm':
1547 case 'M': 1783 case 'M':
1548 do_state(optarg[x], MPROTECT); 1784 do_pax_state(optarg[x], MPROTECT);
1549 break; 1785 break;
1550 case 'e': 1786 case 'e':
1551 case 'E': 1787 case 'E':
1552 do_state(optarg[x], EMUTRAMP); 1788 do_pax_state(optarg[x], EMUTRAMP);
1553 break; 1789 break;
1554 case 'r': 1790 case 'r':
1555 case 'R': 1791 case 'R':
1556 do_state(optarg[x], RANDMMAP); 1792 do_pax_state(optarg[x], RANDMMAP);
1557 break; 1793 break;
1558 case 'x': 1794 case 'x':
1559 case 'X': 1795 case 'X':
1560 do_state(optarg[x], RANDEXEC); 1796 do_pax_state(optarg[x], RANDEXEC);
1561 break; 1797 break;
1562 default: 1798 default:
1563 break; 1799 break;
1564 } 1800 }
1565 } 1801 }
1570 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) || 1806 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1571 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)))) 1807 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1572 setpax = flags; 1808 setpax = flags;
1573 break; 1809 break;
1574 } 1810 }
1575 case 'g': gmatch = 1; break; 1811 case 'g': g_match = 1; break;
1576 case 'L': use_ldcache = 1; break; 1812 case 'L': use_ldcache = 1; break;
1577 case 'y': scan_symlink = 0; break; 1813 case 'y': scan_symlink = 0; break;
1578 case 'A': scan_archives = 1; break; 1814 case 'A': scan_archives = 1; break;
1579 case 'B': show_banner = 0; break; 1815 case 'B': show_banner = 0; break;
1580 case 'l': scan_ldpath = 1; break; 1816 case 'l': scan_ldpath = 1; break;
1591 case 'b': show_bind = 1; break; 1827 case 'b': show_bind = 1; break;
1592 case 'S': show_soname = 1; break; 1828 case 'S': show_soname = 1; break;
1593 case 'T': show_textrels = 1; break; 1829 case 'T': show_textrels = 1; break;
1594 case 'q': be_quiet = 1; break; 1830 case 'q': be_quiet = 1; break;
1595 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1831 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1596 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;
1597 1833 case 'D': show_endian = 1; break;
1598 case ':': 1834 case ':':
1599 err("Option '%c' is missing parameter", optopt); 1835 err("Option '%c' is missing parameter", optopt);
1600 case '?': 1836 case '?':
1601 err("Unknown option '%c' or argument missing", optopt); 1837 err("Unknown option '%c' or argument missing", optopt);
1602 default: 1838 default:
1603 err("Unhandled option '%c'; please report this", i); 1839 err("Unhandled option '%c'; please report this", i);
1604 } 1840 }
1605 } 1841 }
1606 1842 if (show_textrels && be_verbose) {
1843 if (which("objdump") != NULL)
1844 has_objdump = 1;
1845 }
1607 /* let the format option override all other options */ 1846 /* let the format option override all other options */
1608 if (out_format) { 1847 if (out_format) {
1609 show_pax = show_phdr = show_textrel = show_rpath = \ 1848 show_pax = show_phdr = show_textrel = show_rpath = \
1610 show_needed = show_interp = show_bind = show_soname = \ 1849 show_needed = show_interp = show_bind = show_soname = \
1611 show_textrels = 0; 1850 show_textrels = show_perms = show_endian = 0;
1612 for (i = 0; out_format[i]; ++i) { 1851 for (i = 0; out_format[i]; ++i) {
1613 if (!IS_MODIFIER(out_format[i])) continue; 1852 if (!IS_MODIFIER(out_format[i])) continue;
1614 1853
1615 switch (out_format[++i]) { 1854 switch (out_format[++i]) {
1616 case '+': break; 1855 case '+': break;
1621 case 'f': break; 1860 case 'f': break;
1622 case 'k': break; 1861 case 'k': break;
1623 case 's': break; 1862 case 's': break;
1624 case 'N': break; 1863 case 'N': break;
1625 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;
1626 case 'x': show_pax = 1; break; 1869 case 'x': show_pax = 1; break;
1627 case 'e': show_phdr = 1; break; 1870 case 'e': show_phdr = 1; break;
1628 case 't': show_textrel = 1; break; 1871 case 't': show_textrel = 1; break;
1629 case 'r': show_rpath = 1; break; 1872 case 'r': show_rpath = 1; break;
1630 case 'n': show_needed = 1; break; 1873 case 'n': show_needed = 1; break;
1631 case 'i': show_interp = 1; break; 1874 case 'i': show_interp = 1; break;
1632 case 'b': show_bind = 1; break; 1875 case 'b': show_bind = 1; break;
1633 case 'S': show_soname = 1; break; 1876 case 'S': show_soname = 1; break;
1634 case 'T': show_textrels = 1; break; 1877 case 'T': show_textrels = 1; break;
1635 default: 1878 default:
1636 err("Invalid format specifier '%c' (byte %i)", 1879 err("Invalid format specifier '%c' (byte %i)",
1637 out_format[i], i+1); 1880 out_format[i], i+1);
1638 } 1881 }
1639 } 1882 }
1640 1883
1641 /* construct our default format */ 1884 /* construct our default format */
1642 } else { 1885 } else {
1643 size_t fmt_len = 30; 1886 size_t fmt_len = 30;
1644 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1887 out_format = xmalloc(sizeof(char) * fmt_len);
1645 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1888 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1646 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);
1647 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1892 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1648 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1893 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1649 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1894 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1650 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1895 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1651 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1896 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1659 } 1904 }
1660 if (be_verbose > 2) printf("Format: %s\n", out_format); 1905 if (be_verbose > 2) printf("Format: %s\n", out_format);
1661 1906
1662 /* now lets actually do the scanning */ 1907 /* now lets actually do the scanning */
1663 if (scan_ldpath || use_ldcache) 1908 if (scan_ldpath || use_ldcache)
1664 load_ld_so_conf(0, "/etc/ld.so.conf"); 1909 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1665 if (scan_ldpath) scanelf_ldpath(); 1910 if (scan_ldpath) scanelf_ldpath();
1666 if (scan_envpath) scanelf_envpath(); 1911 if (scan_envpath) scanelf_envpath();
1667 if (!from_file && ttyname(0) == NULL) 1912 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1668 from_file = (char *) "-"; 1913 from_file = "-";
1669 if (from_file) { 1914 if (from_file) {
1670 scanelf_from_file(from_file); 1915 scanelf_from_file(from_file);
1671 from_file = *argv; 1916 from_file = *argv;
1672 } 1917 }
1673 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1918 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1674 err("Nothing to scan !?"); 1919 err("Nothing to scan !?");
1675 while (optind < argc) { 1920 while (optind < argc) {
1676 search_path = argv[optind++]; 1921 search_path = argv[optind++];
1677 scanelf_dir(search_path); 1922 ret = scanelf_dir(search_path);
1678 } 1923 }
1679 1924
1680 /* clean up */ 1925 /* clean up */
1681 if (versioned_symname) free(versioned_symname); 1926 free(versioned_symname);
1682 for (i = 0; ldpaths[i]; ++i) 1927 for (i = 0; ldpaths[i]; ++i)
1683 free(ldpaths[i]); 1928 free(ldpaths[i]);
1684 1929
1685 if (ldcache != 0) 1930 if (ldcache != 0)
1686 munmap(ldcache, ldcache_size); 1931 munmap(ldcache, ldcache_size);
1687}
1688
1689
1690
1691/* utility funcs */
1692static char *xstrdup(const char *s)
1693{
1694 char *ret = strdup(s);
1695 if (!ret) err("Could not strdup(): %s", strerror(errno));
1696 return ret; 1932 return ret;
1697} 1933}
1698static void *xmalloc(size_t size)
1699{
1700 void *ret = malloc(size);
1701 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1702 return ret;
1703}
1704static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1705{
1706 size_t new_len;
1707 1934
1708 new_len = strlen(*dst) + strlen(src); 1935static char **get_split_env(const char *envvar)
1709 if (*curr_len <= new_len) {
1710 *curr_len = new_len + (*curr_len / 2);
1711 *dst = realloc(*dst, *curr_len);
1712 if (!*dst)
1713 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1714 }
1715
1716 if (n)
1717 strncat(*dst, src, n);
1718 else
1719 strcat(*dst, src);
1720}
1721static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1722{ 1936{
1723 static char my_app[2]; 1937 const char *delims = " \t\n";
1724 my_app[0] = append; 1938 char **envvals = NULL;
1725 my_app[1] = '\0'; 1939 char *env, *s;
1726 xstrcat(dst, my_app, curr_len); 1940 int nentry;
1727}
1728 1941
1942 if ((env = getenv(envvar)) == NULL)
1943 return NULL;
1944
1945 env = xstrdup(env);
1946 if (env == NULL)
1947 return NULL;
1948
1949 s = strtok(env, delims);
1950 if (s == NULL) {
1951 free(env);
1952 return NULL;
1953 }
1954
1955 nentry = 0;
1956 while (s != NULL) {
1957 ++nentry;
1958 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1959 envvals[nentry-1] = s;
1960 s = strtok(NULL, delims);
1961 }
1962 envvals[nentry] = NULL;
1963
1964 /* don't want to free(env) as it contains the memory that backs
1965 * the envvals array of strings */
1966 return envvals;
1967}
1968
1969static void parseenv(void)
1970{
1971 qa_textrels = get_split_env("QA_TEXTRELS");
1972 qa_execstack = get_split_env("QA_EXECSTACK");
1973 qa_wx_load = get_split_env("QA_WX_LOAD");
1974}
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
1729 1985
1730 1986
1731int main(int argc, char *argv[]) 1987int main(int argc, char *argv[])
1732{ 1988{
1989 int ret;
1733 if (argc < 2) 1990 if (argc < 2)
1734 usage(EXIT_FAILURE); 1991 usage(EXIT_FAILURE);
1992 parseenv();
1735 parseargs(argc, argv); 1993 ret = parseargs(argc, argv);
1736 fclose(stdout); 1994 fclose(stdout);
1737#ifdef __BOUNDS_CHECKING_ON 1995#ifdef __PAX_UTILS_CLEANUP
1738 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");
1739#endif 2000#endif
1740 return EXIT_SUCCESS; 2001 return ret;
1741} 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.132  
changed lines
  Added in v.1.188

  ViewVC Help
Powered by ViewVC 1.1.20