/[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.91 Revision 1.119
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2006 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.91 2005/12/07 01:04:52 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.119 2006/02/05 02:25:58 solar Exp $
5 * 5 *
6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10#include <stdio.h>
11#include <stdlib.h>
12#include <sys/types.h>
13#include <libgen.h>
14#include <limits.h>
15#define __USE_GNU
16#include <string.h>
17#include <errno.h>
18#include <unistd.h>
19#include <sys/stat.h>
20#include <dirent.h>
21#include <getopt.h>
22#include <assert.h>
23#include "paxinc.h" 10#include "paxinc.h"
24 11
25static const char *rcsid = "$Id: scanelf.c,v 1.91 2005/12/07 01:04:52 vapier Exp $"; 12static const char *rcsid = "$Id: scanelf.c,v 1.119 2006/02/05 02:25:58 solar Exp $";
26#define argv0 "scanelf" 13#define argv0 "scanelf"
27 14
28#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#')
29 16
30 17
31 18
32/* prototypes */ 19/* prototypes */
20static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len);
33static void scanelf_file(const char *filename); 23static void scanelf_file(const char *filename);
34static void scanelf_dir(const char *path); 24static void scanelf_dir(const char *path);
35static void scanelf_ldpath(); 25static void scanelf_ldpath(void);
36static void scanelf_envpath(); 26static void scanelf_envpath(void);
37static void usage(int status); 27static void usage(int status);
38static void parseargs(int argc, char *argv[]); 28static void parseargs(int argc, char *argv[]);
39static char *xstrdup(const char *s); 29static char *xstrdup(const char *s);
40static void *xmalloc(size_t size); 30static void *xmalloc(size_t size);
41static void xstrcat(char **dst, const char *src, size_t *curr_len); 31static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32#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); 33static inline void xchrcat(char **dst, const char append, size_t *curr_len);
43 34
44/* variables to control behavior */ 35/* variables to control behavior */
36static char match_etypes[126] = "";
45static char *ldpaths[256]; 37static char *ldpaths[256];
46static char scan_ldpath = 0; 38static char scan_ldpath = 0;
47static char scan_envpath = 0; 39static char scan_envpath = 0;
48static char scan_symlink = 1; 40static char scan_symlink = 1;
41static char scan_archives = 0;
49static char dir_recurse = 0; 42static char dir_recurse = 0;
50static char dir_crossmount = 1; 43static char dir_crossmount = 1;
51static char show_pax = 0; 44static char show_pax = 0;
52static char show_phdr = 0; 45static char show_phdr = 0;
53static char show_textrel = 0; 46static char show_textrel = 0;
63static char be_wewy_wewy_quiet = 0; 56static char be_wewy_wewy_quiet = 0;
64static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
65static char *find_lib = NULL; 58static char *find_lib = NULL;
66static char *out_format = NULL; 59static char *out_format = NULL;
67static char *search_path = NULL; 60static char *search_path = NULL;
61static char fix_elf = 0;
68static char gmatch = 0; 62static char gmatch = 0;
63static char use_ldcache = 0;
69 64
65
66caddr_t ldcache = 0;
67size_t ldcache_size = 0;
70 68
71/* sub-funcs for scanelf_file() */ 69/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 70static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{ 71{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 72 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
144 142
145static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 143static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
146{ 144{
147 static char ret[12]; 145 static char ret[12];
148 char *found; 146 char *found;
149 unsigned long i, shown;
150 unsigned char multi_stack, multi_relro, multi_load; 147 unsigned long i, shown, multi_stack, multi_relro, multi_load;
148 int max_pt_load;
151 149
152 if (!show_phdr) return NULL; 150 if (!show_phdr) return NULL;
153 151
154 memcpy(ret, "--- --- ---\0", 12); 152 memcpy(ret, "--- --- ---\0", 12);
155 153
156 shown = 0; 154 shown = 0;
157 multi_stack = multi_relro = multi_load = 0; 155 multi_stack = multi_relro = multi_load = 0;
156 max_pt_load = elf_max_pt_load(elf);
158 157
158#define NOTE_GNU_STACK ".note.GNU-stack"
159#define SHOW_PHDR(B) \ 159#define SHOW_PHDR(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \ 160 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 161 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
162 Elf ## B ## _Off offset; \ 162 Elf ## B ## _Off offset; \
163 uint32_t flags, check_flags; \ 163 uint32_t flags, check_flags; \
173 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 173 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
174 found = found_relro; \ 174 found = found_relro; \
175 offset = 4; \ 175 offset = 4; \
176 check_flags = PF_X; \ 176 check_flags = PF_X; \
177 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 177 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
178 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
178 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 179 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
179 found = found_load; \ 180 found = found_load; \
180 offset = 8; \ 181 offset = 8; \
181 check_flags = PF_W|PF_X; \ 182 check_flags = PF_W|PF_X; \
182 } else \ 183 } else \
183 continue; \ 184 continue; \
184 flags = EGET(phdr[i].p_flags); \ 185 flags = EGET(phdr[i].p_flags); \
185 if (be_quiet && ((flags & check_flags) != check_flags)) \ 186 if (be_quiet && ((flags & check_flags) != check_flags)) \
186 continue; \ 187 continue; \
188 if (fix_elf && ((flags & PF_X) != flags)) { \
189 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
190 ret[3] = ret[7] = '!'; \
191 flags = EGET(phdr[i].p_flags); \
192 } \
187 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 193 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
188 *found = 1; \ 194 *found = 1; \
189 ++shown; \ 195 ++shown; \
190 } \ 196 } \
191 } else if (elf->shdr != NULL) { \ 197 } else if (elf->shdr != NULL) { \
192 /* no program headers which means this is prob an object file */ \ 198 /* no program headers which means this is prob an object file */ \
193 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 199 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
194 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 200 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
201 char *str; \
202 if ((void*)strtbl > (void*)elf->data_end) \
203 goto skip_this_shdr##B; \
195 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 204 check_flags = SHF_WRITE|SHF_EXECINSTR; \
196 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 205 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
197 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 206 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
198 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 207 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
199 if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \ 208 str = elf->data + offset; \
209 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
210 if (!strcmp(str, NOTE_GNU_STACK)) { \
200 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \ 211 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
201 flags = EGET(shdr[i].sh_flags); \ 212 flags = EGET(shdr[i].sh_flags); \
202 if (be_quiet && ((flags & check_flags) != check_flags)) \ 213 if (be_quiet && ((flags & check_flags) != check_flags)) \
203 continue; \ 214 continue; \
204 ++*found_phdr; \ 215 ++*found_phdr; \
208 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \ 219 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
209 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \ 220 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
210 break; \ 221 break; \
211 } \ 222 } \
212 } \ 223 } \
224 skip_this_shdr##B: \
213 if (!multi_stack) { \ 225 if (!multi_stack) { \
214 *found_phdr = 1; \ 226 *found_phdr = 1; \
215 shown = 1; \ 227 shown = 1; \
216 memcpy(ret, "!WX", 3); \ 228 memcpy(ret, "!WX", 3); \
217 } \ 229 } \
321 if (be_verbose <= 2) continue; \ 333 if (be_verbose <= 2) continue; \
322 } else \ 334 } else \
323 *found_textrels = 1; \ 335 *found_textrels = 1; \
324 /* locate this relocation symbol name */ \ 336 /* locate this relocation symbol name */ \
325 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 337 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
338 if ((void*)sym > (void*)elf->data_end) { \
339 warn("%s: corrupt ELF symbol", elf->filename); \
340 continue; \
341 } \
326 sym_max = ELF ## B ## _R_SYM(r_info); \ 342 sym_max = ELF ## B ## _R_SYM(r_info); \
327 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 343 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
328 sym += sym_max; \ 344 sym += sym_max; \
329 else \ 345 else \
330 sym = NULL; \ 346 sym = NULL; \
362 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename); 378 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
363 379
364 return NULL; 380 return NULL;
365} 381}
366 382
367static void rpath_security_checks(elfobj *, char *); 383static void rpath_security_checks(elfobj *, char *, const char *);
368static void rpath_security_checks(elfobj *elf, char *item) { 384static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
385{
369 struct stat st; 386 struct stat st;
370 switch (*item) { 387 switch (*item) {
371 case '/': break; 388 case '/': break;
372 case '.': 389 case '.':
373 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename); 390 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
374 break; 391 break;
392 case ':':
375 case '\0': 393 case '\0':
376 warnf("Security problem NULL RPATH in %s", elf->filename); 394 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
377 break; 395 break;
378 case '$': 396 case '$':
379 if (fstat(elf->fd, &st) != -1) 397 if (fstat(elf->fd, &st) != -1)
380 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 398 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
381 warnf("Security problem with RPATH='%s' in %s with mode set of %o", 399 warnf("Security problem with %s='%s' in %s with mode set of %o",
382 item, elf->filename, st.st_mode & 07777); 400 dt_type, item, elf->filename, st.st_mode & 07777);
383 break; 401 break;
384 default: 402 default:
385 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename); 403 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
386 break; 404 break;
387 } 405 }
388} 406}
389static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 407static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
390{ 408{
426 /* Verify the memory is somewhat sane */ \ 444 /* Verify the memory is somewhat sane */ \
427 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 445 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
428 if (offset < (Elf ## B ## _Off)elf->len) { \ 446 if (offset < (Elf ## B ## _Off)elf->len) { \
429 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 447 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
430 *r = (char*)(elf->data + offset); \ 448 *r = (char*)(elf->data + offset); \
449 /* cache the length in case we need to nuke this section later on */ \
450 if (fix_elf) \
451 offset = strlen(*r); \
431 /* If quiet, don't output paths in ld.so.conf */ \ 452 /* If quiet, don't output paths in ld.so.conf */ \
432 if (be_quiet) { \ 453 if (be_quiet) { \
433 size_t len; \ 454 size_t len; \
434 char *start, *end; \ 455 char *start, *end; \
435 /* note that we only 'chop' off leading known paths. */ \ 456 /* note that we only 'chop' off leading known paths. */ \
436 /* since *r is read-only memory, we can only move the ptr forward. */ \ 457 /* since *r is read-only memory, we can only move the ptr forward. */ \
437 start = *r; \ 458 start = *r; \
438 /* scan each path in : delimited list */ \ 459 /* scan each path in : delimited list */ \
439 while (start) { \ 460 while (start) { \
440 rpath_security_checks(elf, start); \ 461 rpath_security_checks(elf, start, get_elfdtype(word)); \
441 end = strchr(start, ':'); \ 462 end = strchr(start, ':'); \
442 len = (end ? abs(end - start) : strlen(start)); \ 463 len = (end ? abs(end - start) : strlen(start)); \
464 if (use_ldcache) \
443 for (s = 0; ldpaths[s]; ++s) { \ 465 for (s = 0; ldpaths[s]; ++s) \
444 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 466 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
445 *r = (end ? end + 1 : NULL); \ 467 *r = end; \
468 /* corner case ... if RPATH reads "/usr/lib:", we want \
469 * to show ':' rather than '' */ \
470 if (end && end[1] != '\0') \
471 (*r)++; \
446 break; \ 472 break; \
447 } \ 473 } \
448 } \
449 if (!*r || !ldpaths[s] || !end) \ 474 if (!*r || !end) \
450 start = NULL; \ 475 break; \
451 else \ 476 else \
452 start = start + len + 1; \ 477 start = start + len + 1; \
453 } \ 478 } \
454 } \ 479 } \
480 if (*r) { \
481 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
482 /* just nuke it */ \
483 nuke_it##B: \
484 memset(*r, 0x00, offset); \
485 *r = NULL; \
486 ESET(dyn->d_tag, DT_DEBUG); \
487 ESET(dyn->d_un.d_ptr, 0); \
488 } else if (fix_elf) { \
489 /* try to clean "bad" paths */ \
490 size_t len, tmpdir_len; \
491 char *start, *end; \
492 const char *tmpdir; \
493 start = *r; \
494 tmpdir = (getenv("TMPDIR") ? : "."); \
495 tmpdir_len = strlen(tmpdir); \
496 while (1) { \
497 end = strchr(start, ':'); \
498 if (start == end) { \
499 eat_this_path##B: \
500 len = strlen(end); \
501 memmove(start, end+1, len); \
502 start[len-1] = '\0'; \
503 end = start - 1; \
504 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
505 if (!end) { \
506 if (start == *r) \
507 goto nuke_it##B; \
508 *--start = '\0'; \
509 } else \
510 goto eat_this_path##B; \
511 } \
512 if (!end) \
513 break; \
514 start = end + 1; \
515 } \
516 if (**r == '\0') \
517 goto nuke_it##B; \
518 } \
519 if (*r) \
455 if (*r) *found_rpath = 1; \ 520 *found_rpath = 1; \
521 } \
456 } \ 522 } \
457 ++dyn; \ 523 ++dyn; \
458 } \ 524 } \
459 } } 525 } }
460 SHOW_RPATH(32) 526 SHOW_RPATH(32)
477 } else if (rpath || runpath) 543 } else if (rpath || runpath)
478 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 544 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
479 else if (!be_quiet) 545 else if (!be_quiet)
480 xstrcat(ret, " - ", ret_len); 546 xstrcat(ret, " - ", ret_len);
481} 547}
548
549#define LDSO_CACHE_MAGIC "ld.so-"
550#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
551#define LDSO_CACHE_VER "1.7.0"
552#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
553#define FLAG_ANY -1
554#define FLAG_TYPE_MASK 0x00ff
555#define FLAG_LIBC4 0x0000
556#define FLAG_ELF 0x0001
557#define FLAG_ELF_LIBC5 0x0002
558#define FLAG_ELF_LIBC6 0x0003
559#define FLAG_REQUIRED_MASK 0xff00
560#define FLAG_SPARC_LIB64 0x0100
561#define FLAG_IA64_LIB64 0x0200
562#define FLAG_X8664_LIB64 0x0300
563#define FLAG_S390_LIB64 0x0400
564#define FLAG_POWERPC_LIB64 0x0500
565#define FLAG_MIPS64_LIBN32 0x0600
566#define FLAG_MIPS64_LIBN64 0x0700
567
568static char *lookup_cache_lib(elfobj *, char *);
569static char *lookup_cache_lib(elfobj *elf, char *fname)
570{
571 int fd = 0;
572 char *strs;
573 static char buf[__PAX_UTILS_PATH_MAX] = "";
574 const char *cachefile = "/etc/ld.so.cache";
575 struct stat st;
576
577 typedef struct {
578 char magic[LDSO_CACHE_MAGIC_LEN];
579 char version[LDSO_CACHE_VER_LEN];
580 int nlibs;
581 } header_t;
582 header_t *header;
583
584 typedef struct {
585 int flags;
586 int sooffset;
587 int liboffset;
588 } libentry_t;
589 libentry_t *libent;
590
591 if (fname == NULL)
592 return NULL;
593
594 if (ldcache == 0) {
595 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
596 return NULL;
597
598 /* cache these values so we only map/unmap the cache file once */
599 ldcache_size = st.st_size;
600 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
601
602 close(fd);
603
604 if (ldcache == (caddr_t)-1) {
605 ldcache = 0;
606 return NULL;
607 }
608
609 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
610 return NULL;
611 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
612 return NULL;
613 }
614
615 header = (header_t *) ldcache;
616 libent = (libentry_t *) (ldcache + sizeof(header_t));
617 strs = (char *) &libent[header->nlibs];
618
619 for (fd = 0; fd < header->nlibs; fd++) {
620 /* this should be more fine grained, but for now we assume that
621 * diff arches will not be cached together. and we ignore the
622 * the different multilib mips cases. */
623 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
624 continue;
625 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
626 continue;
627
628 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
629 continue;
630 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
631 }
632 return buf;
633}
634
635
482static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 636static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
483{ 637{
484 unsigned long i; 638 unsigned long i;
485 char *needed; 639 char *needed;
486 void *strtbl_void; 640 void *strtbl_void;
641 char *p;
487 642
488 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 643 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
489 644
490 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 645 strtbl_void = elf_findsecbyname(elf, ".dynstr");
491 646
511 } \ 666 } \
512 needed = (char*)(elf->data + offset); \ 667 needed = (char*)(elf->data + offset); \
513 if (op == 0) { \ 668 if (op == 0) { \
514 if (!be_wewy_wewy_quiet) { \ 669 if (!be_wewy_wewy_quiet) { \
515 if (*found_needed) xchrcat(ret, ',', ret_len); \ 670 if (*found_needed) xchrcat(ret, ',', ret_len); \
671 if (use_ldcache) \
672 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
673 needed = p; \
516 xstrcat(ret, needed, ret_len); \ 674 xstrcat(ret, needed, ret_len); \
517 } \ 675 } \
518 *found_needed = 1; \ 676 *found_needed = 1; \
519 } else { \ 677 } else { \
520 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 678 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
644 return NULL; 802 return NULL;
645} 803}
646static char *scanelf_file_sym(elfobj *elf, char *found_sym) 804static char *scanelf_file_sym(elfobj *elf, char *found_sym)
647{ 805{
648 unsigned long i; 806 unsigned long i;
807 char *ret;
649 void *symtab_void, *strtab_void; 808 void *symtab_void, *strtab_void;
650 809
651 if (!find_sym) return NULL; 810 if (!find_sym) return NULL;
811 ret = find_sym;
652 812
653 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 813 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
654 814
655 if (symtab_void && strtab_void) { 815 if (symtab_void && strtab_void) {
656#define FIND_SYM(B) \ 816#define FIND_SYM(B) \
657 if (elf->elf_class == ELFCLASS ## B) { \ 817 if (elf->elf_class == ELFCLASS ## B) { \
658 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 818 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
659 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 819 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
660 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 820 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
661 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 821 unsigned long cnt = EGET(symtab->sh_entsize); \
662 char *symname; \ 822 char *symname; \
823 if (cnt) \
824 cnt = EGET(symtab->sh_size) / cnt; \
663 for (i = 0; i < cnt; ++i) { \ 825 for (i = 0; i < cnt; ++i) { \
664 if (sym->st_name) { \ 826 if (sym->st_name) { \
665 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 827 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
828 if ((void*)symname > (void*)elf->data_end) { \
829 warnf("%s: corrupt ELF symbols", elf->filename); \
830 continue; \
831 } \
666 if (*find_sym == '*') { \ 832 if (*find_sym == '*') { \
667 printf("%s(%s) %5lX %15s %s\n", \ 833 printf("%s(%s) %5lX %15s %s\n", \
668 ((*found_sym == 0) ? "\n\t" : "\t"), \ 834 ((*found_sym == 0) ? "\n\t" : "\t"), \
669 elf->base_filename, \ 835 elf->base_filename, \
670 (long)sym->st_size, \ 836 (unsigned long)sym->st_size, \
671 (char *)get_elfstttype(sym->st_info), \ 837 get_elfstttype(sym->st_info), \
672 symname); \ 838 symname); \
673 *found_sym = 1; \ 839 *found_sym = 1; \
674 } else if ((strcmp(find_sym, symname) == 0) || \ 840 } else { \
841 char *this_sym, *next_sym; \
842 this_sym = find_sym; \
843 do { \
844 next_sym = strchr(this_sym, ','); \
845 if (next_sym == NULL) \
846 next_sym = this_sym + strlen(this_sym); \
847 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
675 (strcmp(symname, versioned_symname) == 0)) \ 848 (strcmp(symname, versioned_symname) == 0)) { \
849 ret = this_sym; \
676 (*found_sym)++; \ 850 (*found_sym)++; \
851 goto break_out; \
852 } \
853 this_sym = next_sym + 1; \
854 } while (*next_sym != '\0'); \
855 } \
677 } \ 856 } \
678 ++sym; \ 857 ++sym; \
679 } } 858 } }
680 FIND_SYM(32) 859 FIND_SYM(32)
681 FIND_SYM(64) 860 FIND_SYM(64)
682 } 861 }
683 862
863break_out:
684 if (be_wewy_wewy_quiet) return NULL; 864 if (be_wewy_wewy_quiet) return NULL;
685 865
686 if (*find_sym != '*' && *found_sym) 866 if (*find_sym != '*' && *found_sym)
687 return find_sym; 867 return ret;
688 if (be_quiet) 868 if (be_quiet)
689 return NULL; 869 return NULL;
690 else 870 else
691 return (char *)" - "; 871 return (char *)" - ";
692} 872}
873
874
693/* scan an elf file and show all the fun stuff */ 875/* scan an elf file and show all the fun stuff */
694#define prints(str) write(fileno(stdout), str, strlen(str)) 876#define prints(str) write(fileno(stdout), str, strlen(str))
695static void scanelf_file(const char *filename) 877static int scanelf_elfobj(elfobj *elf)
696{ 878{
697 unsigned long i; 879 unsigned long i;
698 char found_pax, found_phdr, found_relro, found_load, found_textrel, 880 char found_pax, found_phdr, found_relro, found_load, found_textrel,
699 found_rpath, found_needed, found_interp, found_bind, found_soname, 881 found_rpath, found_needed, found_interp, found_bind, found_soname,
700 found_sym, found_lib, found_file, found_textrels; 882 found_sym, found_lib, found_file, found_textrels;
701 elfobj *elf;
702 struct stat st;
703 static char *out_buffer = NULL; 883 static char *out_buffer = NULL;
704 static size_t out_len; 884 static size_t out_len;
705
706 /* make sure 'filename' exists */
707 if (lstat(filename, &st) == -1) {
708 if (be_verbose > 2) printf("%s: does not exist\n", filename);
709 return;
710 }
711 /* always handle regular files and handle symlinked files if no -y */
712 if (S_ISLNK(st.st_mode)) {
713 if (!scan_symlink) return;
714 stat(filename, &st);
715 }
716 if (!S_ISREG(st.st_mode)) {
717 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
718 return;
719 }
720 885
721 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 886 found_pax = found_phdr = found_relro = found_load = found_textrel = \
722 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 887 found_rpath = found_needed = found_interp = found_bind = found_soname = \
723 found_sym = found_lib = found_file = found_textrels = 0; 888 found_sym = found_lib = found_file = found_textrels = 0;
724 889
725 /* verify this is real ELF */
726 if ((elf = readelf(filename)) == NULL) {
727 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
728 return;
729 }
730
731 if (be_verbose > 1) 890 if (be_verbose > 2)
732 printf("%s: scanning file {%s,%s}\n", filename, 891 printf("%s: scanning file {%s,%s}\n", elf->filename,
733 get_elfeitype(EI_CLASS, elf->elf_class), 892 get_elfeitype(EI_CLASS, elf->elf_class),
734 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 893 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
735 else if (be_verbose) 894 else if (be_verbose > 1)
736 printf("%s: scanning file\n", filename); 895 printf("%s: scanning file\n", elf->filename);
737 896
738 /* init output buffer */ 897 /* init output buffer */
739 if (!out_buffer) { 898 if (!out_buffer) {
740 out_len = sizeof(char) * 80; 899 out_len = sizeof(char) * 80;
741 out_buffer = (char*)xmalloc(out_len); 900 out_buffer = (char*)xmalloc(out_len);
795 case '#': 954 case '#':
796 xchrcat(&out_buffer, out_format[i], &out_len); break; 955 xchrcat(&out_buffer, out_format[i], &out_len); break;
797 case 'F': 956 case 'F':
798 found_file = 1; 957 found_file = 1;
799 if (be_wewy_wewy_quiet) break; 958 if (be_wewy_wewy_quiet) break;
800 xstrcat(&out_buffer, filename, &out_len); 959 xstrcat(&out_buffer, elf->filename, &out_len);
801 break; 960 break;
802 case 'p': 961 case 'p':
803 found_file = 1; 962 found_file = 1;
804 if (be_wewy_wewy_quiet) break; 963 if (be_wewy_wewy_quiet) break;
805 tmp = filename; 964 tmp = elf->filename;
806 if (search_path) { 965 if (search_path) {
807 ssize_t len_search = strlen(search_path); 966 ssize_t len_search = strlen(search_path);
808 ssize_t len_file = strlen(filename); 967 ssize_t len_file = strlen(elf->filename);
809 if (!strncmp(filename, search_path, len_search) && \ 968 if (!strncmp(elf->filename, search_path, len_search) && \
810 len_file > len_search) 969 len_file > len_search)
811 tmp += len_search; 970 tmp += len_search;
812 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 971 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
813 } 972 }
814 xstrcat(&out_buffer, tmp, &out_len); 973 xstrcat(&out_buffer, tmp, &out_len);
815 break; 974 break;
816 case 'f': 975 case 'f':
817 found_file = 1; 976 found_file = 1;
818 if (be_wewy_wewy_quiet) break; 977 if (be_wewy_wewy_quiet) break;
819 tmp = strrchr(filename, '/'); 978 tmp = strrchr(elf->filename, '/');
820 tmp = (tmp == NULL ? filename : tmp+1); 979 tmp = (tmp == NULL ? elf->filename : tmp+1);
821 xstrcat(&out_buffer, tmp, &out_len); 980 xstrcat(&out_buffer, tmp, &out_len);
822 break; 981 break;
823 case 'o': out = get_elfetype(elf); break; 982 case 'o': out = get_elfetype(elf); break;
824 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 983 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
825 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 984 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
832 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 991 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
833 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 992 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
834 case 's': out = scanelf_file_sym(elf, &found_sym); break; 993 case 's': out = scanelf_file_sym(elf, &found_sym); break;
835 default: warnf("'%c' has no scan code?", out_format[i]); 994 default: warnf("'%c' has no scan code?", out_format[i]);
836 } 995 }
996 if (out) {
997 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
998 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
999 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1000 else
837 if (out) xstrcat(&out_buffer, out, &out_len); 1001 xstrcat(&out_buffer, out, &out_len);
1002 }
838 } 1003 }
839 1004
840#define FOUND_SOMETHING() \ 1005#define FOUND_SOMETHING() \
841 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1006 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
842 found_rpath || found_needed || found_interp || found_bind || \ 1007 found_rpath || found_needed || found_interp || found_bind || \
843 found_soname || found_sym || found_lib || found_textrels) 1008 found_soname || found_sym || found_lib || found_textrels)
844 1009
845 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1010 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
846 xchrcat(&out_buffer, ' ', &out_len); 1011 xchrcat(&out_buffer, ' ', &out_len);
847 xstrcat(&out_buffer, filename, &out_len); 1012 xstrcat(&out_buffer, elf->filename, &out_len);
848 } 1013 }
849 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1014 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
850 puts(out_buffer); 1015 puts(out_buffer);
851 fflush(stdout); 1016 fflush(stdout);
852 } 1017 }
853 1018
1019 return 0;
1020}
1021
1022/* scan a single elf */
1023static int scanelf_elf(const char *filename, int fd, size_t len)
1024{
1025 int ret;
1026 elfobj *elf;
1027
1028 /* verify this is real ELF */
1029 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1030 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1031 return 1;
1032 }
1033
1034 if (strlen(match_etypes)) {
1035 char sbuf[126];
1036 strncpy(sbuf, match_etypes, sizeof(sbuf));
1037 if (strchr(match_etypes, ',') != NULL) {
1038 char *p;
1039 while((p = strrchr(sbuf, ',')) != NULL) {
1040 *p = 0;
1041 if (atoi(p+1) == get_etype(elf))
1042 goto label_ret;
1043 }
1044 }
1045 if (atoi(sbuf) != get_etype(elf)) {
1046 ret = 1;
1047 goto label_done;
1048 }
1049 }
1050
1051label_ret:
1052 ret = scanelf_elfobj(elf);
1053
1054label_done:
854 unreadelf(elf); 1055 unreadelf(elf);
1056 return ret;
1057}
1058
1059/* scan an archive of elfs */
1060static int scanelf_archive(const char *filename, int fd, size_t len)
1061{
1062 archive_handle *ar;
1063 archive_member *m;
1064 char *ar_buffer;
1065 elfobj *elf;
1066
1067 ar = ar_open_fd(filename, fd);
1068 if (ar == NULL)
1069 return 1;
1070
1071 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1072 while ((m=ar_next(ar)) != NULL) {
1073 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1074 if (elf) {
1075 scanelf_elfobj(elf);
1076 unreadelf(elf);
1077 }
1078 }
1079 munmap(ar_buffer, len);
1080
1081 return 0;
1082}
1083/* scan a file which may be an elf or an archive or some other magical beast */
1084static void scanelf_file(const char *filename)
1085{
1086 struct stat st;
1087 int fd;
1088
1089 /* make sure 'filename' exists */
1090 if (lstat(filename, &st) == -1) {
1091 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1092 return;
1093 }
1094
1095 /* always handle regular files and handle symlinked files if no -y */
1096 if (S_ISLNK(st.st_mode)) {
1097 if (!scan_symlink) return;
1098 stat(filename, &st);
1099 }
1100 if (!S_ISREG(st.st_mode)) {
1101 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1102 return;
1103 }
1104
1105 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1106 return;
1107
1108 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1109 /* if it isn't an ELF, maybe it's an .a archive */
1110 scanelf_archive(filename, fd, st.st_size);
1111
1112 close(fd);
855} 1113}
856 1114
857/* scan a directory for ET_EXEC files and print when we find one */ 1115/* scan a directory for ET_EXEC files and print when we find one */
858static void scanelf_dir(const char *path) 1116static void scanelf_dir(const char *path)
859{ 1117{
860 register DIR *dir; 1118 register DIR *dir;
861 register struct dirent *dentry; 1119 register struct dirent *dentry;
862 struct stat st_top, st; 1120 struct stat st_top, st;
863 char buf[_POSIX_PATH_MAX]; 1121 char buf[__PAX_UTILS_PATH_MAX];
864 size_t pathlen = 0, len = 0; 1122 size_t pathlen = 0, len = 0;
865 1123
866 /* make sure path exists */ 1124 /* make sure path exists */
867 if (lstat(path, &st_top) == -1) { 1125 if (lstat(path, &st_top) == -1) {
868 if (be_verbose > 2) printf("%s: does not exist\n", path); 1126 if (be_verbose > 2) printf("%s: does not exist\n", path);
878 /* now scan the dir looking for fun stuff */ 1136 /* now scan the dir looking for fun stuff */
879 if ((dir = opendir(path)) == NULL) { 1137 if ((dir = opendir(path)) == NULL) {
880 warnf("could not opendir %s: %s", path, strerror(errno)); 1138 warnf("could not opendir %s: %s", path, strerror(errno));
881 return; 1139 return;
882 } 1140 }
883 if (be_verbose) printf("%s: scanning dir\n", path); 1141 if (be_verbose > 1) printf("%s: scanning dir\n", path);
884 1142
885 pathlen = strlen(path); 1143 pathlen = strlen(path);
886 while ((dentry = readdir(dir))) { 1144 while ((dentry = readdir(dir))) {
887 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1145 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
888 continue; 1146 continue;
907 1165
908static int scanelf_from_file(char *filename) 1166static int scanelf_from_file(char *filename)
909{ 1167{
910 FILE *fp = NULL; 1168 FILE *fp = NULL;
911 char *p; 1169 char *p;
912 char path[_POSIX_PATH_MAX]; 1170 char path[__PAX_UTILS_PATH_MAX];
913 1171
914 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1172 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
915 fp = stdin; 1173 fp = stdin;
916 else if ((fp = fopen(filename, "r")) == NULL) 1174 else if ((fp = fopen(filename, "r")) == NULL)
917 return 1; 1175 return 1;
918 1176
919 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1177 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
920 if ((p = strchr(path, '\n')) != NULL) 1178 if ((p = strchr(path, '\n')) != NULL)
921 *p = 0; 1179 *p = 0;
922 search_path = path; 1180 search_path = path;
923 scanelf_dir(path); 1181 scanelf_dir(path);
924 } 1182 }
929 1187
930static void load_ld_so_conf() 1188static void load_ld_so_conf()
931{ 1189{
932 FILE *fp = NULL; 1190 FILE *fp = NULL;
933 char *p; 1191 char *p;
934 char path[_POSIX_PATH_MAX]; 1192 char path[__PAX_UTILS_PATH_MAX];
935 int i = 0; 1193 int i = 0;
936 1194
937 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1195 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
938 return; 1196 return;
939 1197
940 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1198 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
941 if (*path != '/') 1199 if (*path != '/')
942 continue; 1200 continue;
943 1201
944 if ((p = strrchr(path, '\r')) != NULL) 1202 if ((p = strrchr(path, '\r')) != NULL)
945 *p = 0; 1203 *p = 0;
997 1255
998 free(path); 1256 free(path);
999} 1257}
1000 1258
1001 1259
1002
1003/* usage / invocation handling functions */ 1260/* usage / invocation handling functions */
1004#define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV" 1261#define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:E:BhV"
1005#define a_argument required_argument 1262#define a_argument required_argument
1006static struct option const long_opts[] = { 1263static struct option const long_opts[] = {
1007 {"path", no_argument, NULL, 'p'}, 1264 {"path", no_argument, NULL, 'p'},
1008 {"ldpath", no_argument, NULL, 'l'}, 1265 {"ldpath", no_argument, NULL, 'l'},
1009 {"recursive", no_argument, NULL, 'R'}, 1266 {"recursive", no_argument, NULL, 'R'},
1010 {"mount", no_argument, NULL, 'm'}, 1267 {"mount", no_argument, NULL, 'm'},
1011 {"symlink", no_argument, NULL, 'y'}, 1268 {"symlink", no_argument, NULL, 'y'},
1269 {"archives", no_argument, NULL, 'A'},
1270 {"ldcache", no_argument, NULL, 'L'},
1271 {"fix", no_argument, NULL, 'X'},
1012 {"pax", no_argument, NULL, 'x'}, 1272 {"pax", no_argument, NULL, 'x'},
1013 {"header", no_argument, NULL, 'e'}, 1273 {"header", no_argument, NULL, 'e'},
1014 {"textrel", no_argument, NULL, 't'}, 1274 {"textrel", no_argument, NULL, 't'},
1015 {"rpath", no_argument, NULL, 'r'}, 1275 {"rpath", no_argument, NULL, 'r'},
1016 {"needed", no_argument, NULL, 'n'}, 1276 {"needed", no_argument, NULL, 'n'},
1019 {"soname", no_argument, NULL, 'S'}, 1279 {"soname", no_argument, NULL, 'S'},
1020 {"symbol", a_argument, NULL, 's'}, 1280 {"symbol", a_argument, NULL, 's'},
1021 {"lib", a_argument, NULL, 'N'}, 1281 {"lib", a_argument, NULL, 'N'},
1022 {"gmatch", no_argument, NULL, 'g'}, 1282 {"gmatch", no_argument, NULL, 'g'},
1023 {"textrels", no_argument, NULL, 'T'}, 1283 {"textrels", no_argument, NULL, 'T'},
1284 {"etype", a_argument, NULL, 'E'},
1024 {"all", no_argument, NULL, 'a'}, 1285 {"all", no_argument, NULL, 'a'},
1025 {"quiet", no_argument, NULL, 'q'}, 1286 {"quiet", no_argument, NULL, 'q'},
1026 {"verbose", no_argument, NULL, 'v'}, 1287 {"verbose", no_argument, NULL, 'v'},
1027 {"format", a_argument, NULL, 'F'}, 1288 {"format", a_argument, NULL, 'F'},
1028 {"from", a_argument, NULL, 'f'}, 1289 {"from", a_argument, NULL, 'f'},
1036static const char *opts_help[] = { 1297static const char *opts_help[] = {
1037 "Scan all directories in PATH environment", 1298 "Scan all directories in PATH environment",
1038 "Scan all directories in /etc/ld.so.conf", 1299 "Scan all directories in /etc/ld.so.conf",
1039 "Scan directories recursively", 1300 "Scan directories recursively",
1040 "Don't recursively cross mount points", 1301 "Don't recursively cross mount points",
1041 "Don't scan symlinks\n", 1302 "Don't scan symlinks",
1303 "Scan archives (.a files)",
1304 "Utilize ld.so.cache information (use with -r/-n)",
1305 "Try and 'fix' bad things (use with -r/-e)\n",
1042 "Print PaX markings", 1306 "Print PaX markings",
1043 "Print GNU_STACK/PT_LOAD markings", 1307 "Print GNU_STACK/PT_LOAD markings",
1044 "Print TEXTREL information", 1308 "Print TEXTREL information",
1045 "Print RPATH information", 1309 "Print RPATH information",
1046 "Print NEEDED information", 1310 "Print NEEDED information",
1049 "Print SONAME information", 1313 "Print SONAME information",
1050 "Find a specified symbol", 1314 "Find a specified symbol",
1051 "Find a specified library", 1315 "Find a specified library",
1052 "Use strncmp to match libraries. (use with -N)", 1316 "Use strncmp to match libraries. (use with -N)",
1053 "Locate cause of TEXTREL", 1317 "Locate cause of TEXTREL",
1318 "Print only ELF files matching numeric constant",
1054 "Print all scanned info (-x -e -t -r -b)\n", 1319 "Print all scanned info (-x -e -t -r -b)\n",
1055 "Only output 'bad' things", 1320 "Only output 'bad' things",
1056 "Be verbose (can be specified more than once)", 1321 "Be verbose (can be specified more than once)",
1057 "Use specified format for output", 1322 "Use specified format for output",
1058 "Read input stream from a filename", 1323 "Read input stream from a filename",
1066/* display usage and exit */ 1331/* display usage and exit */
1067static void usage(int status) 1332static void usage(int status)
1068{ 1333{
1069 unsigned long i; 1334 unsigned long i;
1070 printf("* Scan ELF binaries for stuff\n\n" 1335 printf("* Scan ELF binaries for stuff\n\n"
1071 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1336 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1072 printf("Options: -[%s]\n", PARSE_FLAGS); 1337 printf("Options: -[%s]\n", PARSE_FLAGS);
1073 for (i = 0; long_opts[i].name; ++i) 1338 for (i = 0; long_opts[i].name; ++i)
1074 if (long_opts[i].has_arg == no_argument) 1339 if (long_opts[i].has_arg == no_argument)
1075 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1340 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
1076 long_opts[i].name, opts_help[i]); 1341 long_opts[i].name, opts_help[i]);
1110 VERSION, __FILE__, __DATE__, rcsid, argv0); 1375 VERSION, __FILE__, __DATE__, rcsid, argv0);
1111 exit(EXIT_SUCCESS); 1376 exit(EXIT_SUCCESS);
1112 break; 1377 break;
1113 case 'h': usage(EXIT_SUCCESS); break; 1378 case 'h': usage(EXIT_SUCCESS); break;
1114 case 'f': 1379 case 'f':
1115 if (from_file) err("Don't specify -f twice"); 1380 if (from_file) warn("You prob don't want to specify -f twice");
1116 from_file = xstrdup(optarg); 1381 from_file = optarg;
1382 break;
1383 case 'E':
1384 strncpy(match_etypes, optarg, sizeof(match_etypes));
1117 break; 1385 break;
1118 case 'o': { 1386 case 'o': {
1119 FILE *fp = NULL; 1387 FILE *fp = NULL;
1120 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1388 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1121 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1389 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1122 SET_STDOUT(fp); 1390 SET_STDOUT(fp);
1123 break; 1391 break;
1124 } 1392 }
1125 1393
1126 case 's': { 1394 case 's': {
1127 size_t len;
1128 if (find_sym) err("Don't specify -s twice"); 1395 if (find_sym) warn("You prob don't want to specify -s twice");
1129 find_sym = xstrdup(optarg); 1396 find_sym = optarg;
1130 len = strlen(find_sym) + 1;
1131 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1397 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1132 sprintf(versioned_symname, "%s@", find_sym); 1398 sprintf(versioned_symname, "%s@", find_sym);
1133 break; 1399 break;
1134 } 1400 }
1135 case 'N': { 1401 case 'N': {
1136 if (find_lib) err("Don't specify -N twice"); 1402 if (find_lib) warn("You prob don't want to specify -N twice");
1137 find_lib = xstrdup(optarg); 1403 find_lib = optarg;
1138 break; 1404 break;
1139 } 1405 }
1140 1406
1141 case 'F': { 1407 case 'F': {
1142 if (out_format) err("Don't specify -F twice"); 1408 if (out_format) warn("You prob don't want to specify -F twice");
1143 out_format = xstrdup(optarg); 1409 out_format = optarg;
1144 break; 1410 break;
1145 } 1411 }
1146 1412
1147 case 'g': gmatch = 1; 1413 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */
1414 case 'L': use_ldcache = 1; break;
1148 case 'y': scan_symlink = 0; break; 1415 case 'y': scan_symlink = 0; break;
1416 case 'A': scan_archives = 1; break;
1149 case 'B': show_banner = 0; break; 1417 case 'B': show_banner = 0; break;
1150 case 'l': scan_ldpath = 1; break; 1418 case 'l': scan_ldpath = 1; break;
1151 case 'p': scan_envpath = 1; break; 1419 case 'p': scan_envpath = 1; break;
1152 case 'R': dir_recurse = 1; break; 1420 case 'R': dir_recurse = 1; break;
1153 case 'm': dir_crossmount = 0; break; 1421 case 'm': dir_crossmount = 0; break;
1422 case 'X': ++fix_elf; break;
1154 case 'x': show_pax = 1; break; 1423 case 'x': show_pax = 1; break;
1155 case 'e': show_phdr = 1; break; 1424 case 'e': show_phdr = 1; break;
1156 case 't': show_textrel = 1; break; 1425 case 't': show_textrel = 1; break;
1157 case 'r': show_rpath = 1; break; 1426 case 'r': show_rpath = 1; break;
1158 case 'n': show_needed = 1; break; 1427 case 'n': show_needed = 1; break;
1163 case 'q': be_quiet = 1; break; 1432 case 'q': be_quiet = 1; break;
1164 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1433 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1165 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1434 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1166 1435
1167 case ':': 1436 case ':':
1168 err("Option missing parameter\n"); 1437 err("Option '%c' is missing parameter", optopt);
1169 case '?': 1438 case '?':
1170 err("Unknown option\n"); 1439 err("Unknown option '%c' or argument missing", optopt);
1171 default: 1440 default:
1172 err("Unhandled option '%c'", i); 1441 err("Unhandled option '%c'; please report this", i);
1173 } 1442 }
1174 } 1443 }
1175 1444
1176 /* let the format option override all other options */ 1445 /* let the format option override all other options */
1177 if (out_format) { 1446 if (out_format) {
1224 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1493 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1225 } 1494 }
1226 if (be_verbose > 2) printf("Format: %s\n", out_format); 1495 if (be_verbose > 2) printf("Format: %s\n", out_format);
1227 1496
1228 /* now lets actually do the scanning */ 1497 /* now lets actually do the scanning */
1229 if (scan_ldpath || (show_rpath && be_quiet)) 1498 if (scan_ldpath || use_ldcache)
1230 load_ld_so_conf(); 1499 load_ld_so_conf();
1231 if (scan_ldpath) scanelf_ldpath(); 1500 if (scan_ldpath) scanelf_ldpath();
1232 if (scan_envpath) scanelf_envpath(); 1501 if (scan_envpath) scanelf_envpath();
1233 if (from_file) { 1502 if (from_file) {
1234 scanelf_from_file(from_file); 1503 scanelf_from_file(from_file);
1235 free(from_file);
1236 from_file = *argv; 1504 from_file = *argv;
1237 } 1505 }
1238 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1506 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1239 err("Nothing to scan !?"); 1507 err("Nothing to scan !?");
1240 while (optind < argc) { 1508 while (optind < argc) {
1241 search_path = argv[optind++]; 1509 search_path = argv[optind++];
1242 scanelf_dir(search_path); 1510 scanelf_dir(search_path);
1243 } 1511 }
1244 1512
1245 /* clean up */ 1513 /* clean up */
1246 if (find_sym) { 1514 if (versioned_symname) free(versioned_symname);
1247 free(find_sym);
1248 free(versioned_symname);
1249 }
1250 if (find_lib) free(find_lib);
1251 if (out_format) free(out_format);
1252 for (i = 0; ldpaths[i]; ++i) 1515 for (i = 0; ldpaths[i]; ++i)
1253 free(ldpaths[i]); 1516 free(ldpaths[i]);
1517
1518 if (ldcache != 0)
1519 munmap(ldcache, ldcache_size);
1254} 1520}
1255 1521
1256 1522
1257 1523
1258/* utility funcs */ 1524/* utility funcs */
1260{ 1526{
1261 char *ret = strdup(s); 1527 char *ret = strdup(s);
1262 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1528 if (!ret) err("Could not strdup(): %s", strerror(errno));
1263 return ret; 1529 return ret;
1264} 1530}
1265
1266static void *xmalloc(size_t size) 1531static void *xmalloc(size_t size)
1267{ 1532{
1268 void *ret = malloc(size); 1533 void *ret = malloc(size);
1269 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1534 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1270 return ret; 1535 return ret;
1271} 1536}
1272
1273static void xstrcat(char **dst, const char *src, size_t *curr_len) 1537static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1274{ 1538{
1275 size_t new_len; 1539 size_t new_len;
1276 1540
1277 new_len = strlen(*dst) + strlen(src); 1541 new_len = strlen(*dst) + strlen(src);
1278 if (*curr_len <= new_len) { 1542 if (*curr_len <= new_len) {
1279 *curr_len = new_len + (*curr_len / 2); 1543 *curr_len = new_len + (*curr_len / 2);
1280 *dst = realloc(*dst, *curr_len); 1544 *dst = realloc(*dst, *curr_len);
1281 if (!*dst) 1545 if (!*dst)
1282 err("could not realloc %li bytes", (unsigned long)*curr_len); 1546 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1283 } 1547 }
1284 1548
1549 if (n)
1550 strncat(*dst, src, n);
1551 else
1285 strcat(*dst, src); 1552 strcat(*dst, src);
1286} 1553}
1287
1288static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1554static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1289{ 1555{
1290 static char my_app[2]; 1556 static char my_app[2];
1291 my_app[0] = append; 1557 my_app[0] = append;
1292 my_app[1] = '\0'; 1558 my_app[1] = '\0';

Legend:
Removed from v.1.91  
changed lines
  Added in v.1.119

  ViewVC Help
Powered by ViewVC 1.1.20