/[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.127 Revision 1.203
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.127 2006/02/17 07:13:54 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.203 2008/12/30 12:39:53 vapier 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.203 2008/12/30 12:39:53 vapier 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.127 2006/02/17 07:13:54 solar Exp $";
13#define argv0 "scanelf"
14
15#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16
17
18 16
19/* prototypes */ 17/* prototypes */
18static int file_matches_list(const char *filename, char **matchlist);
20static int scanelf_elfobj(elfobj *elf); 19static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len); 20static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len); 21static int scanelf_archive(const char *filename, int fd, size_t len);
23static void scanelf_file(const char *filename); 22static int scanelf_file(const char *filename, const struct stat *st_cache);
24static void scanelf_dir(const char *path); 23static int scanelf_dir(const char *path);
25static void scanelf_ldpath(void); 24static void scanelf_ldpath(void);
26static void scanelf_envpath(void); 25static void scanelf_envpath(void);
27static void usage(int status); 26static void usage(int status);
27static char **get_split_env(const char *envvar);
28static void parseenv(void);
28static void parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
29static char *xstrdup(const char *s); 30static int rematch(const char *regex, const char *match, int cflags);
30static void *xmalloc(size_t size);
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)
33static inline void xchrcat(char **dst, const char append, size_t *curr_len);
34 31
35/* variables to control behavior */ 32/* variables to control behavior */
36static char match_etypes[126] = ""; 33static char match_etypes[126] = "";
37static char *ldpaths[256]; 34static char *ldpaths[256];
38static char scan_ldpath = 0; 35static char scan_ldpath = 0;
40static char scan_symlink = 1; 37static char scan_symlink = 1;
41static char scan_archives = 0; 38static char scan_archives = 0;
42static char dir_recurse = 0; 39static char dir_recurse = 0;
43static char dir_crossmount = 1; 40static char dir_crossmount = 1;
44static char show_pax = 0; 41static char show_pax = 0;
42static char show_perms = 0;
43static char show_size = 0;
45static char show_phdr = 0; 44static char show_phdr = 0;
46static char show_textrel = 0; 45static char show_textrel = 0;
47static char show_rpath = 0; 46static char show_rpath = 0;
48static char show_needed = 0; 47static char show_needed = 0;
49static char show_interp = 0; 48static char show_interp = 0;
50static char show_bind = 0; 49static char show_bind = 0;
51static char show_soname = 0; 50static char show_soname = 0;
52static char show_textrels = 0; 51static char show_textrels = 0;
53static char show_banner = 1; 52static char show_banner = 1;
53static char show_endian = 0;
54static char show_osabi = 0;
55static char show_eabi = 0;
54static char be_quiet = 0; 56static char be_quiet = 0;
55static char be_verbose = 0; 57static char be_verbose = 0;
56static char be_wewy_wewy_quiet = 0; 58static char be_wewy_wewy_quiet = 0;
57static char *find_sym = NULL, *versioned_symname = NULL; 59static char be_semi_verbose = 0;
60static char *find_sym = NULL;
58static char *find_lib = NULL; 61static char *find_lib = NULL;
59static char *find_section = NULL; 62static char *find_section = NULL;
60static char *out_format = NULL; 63static char *out_format = NULL;
61static char *search_path = NULL; 64static char *search_path = NULL;
62static char fix_elf = 0; 65static char fix_elf = 0;
63static char gmatch = 0; 66static char g_match = 0;
64static char use_ldcache = 0; 67static char use_ldcache = 0;
65 68
69static char **qa_textrels = NULL;
70static char **qa_execstack = NULL;
71static char **qa_wx_load = NULL;
72
66int match_bits = 0; 73static int match_bits = 0;
74static unsigned int match_perms = 0;
67caddr_t ldcache = 0; 75static caddr_t ldcache = 0;
68size_t ldcache_size = 0; 76static size_t ldcache_size = 0;
69unsigned long setpax = 0UL; 77static unsigned long setpax = 0UL;
78
79static int has_objdump = 0;
80
81static char *getstr_perms(const char *fname);
82static char *getstr_perms(const char *fname)
83{
84 struct stat st;
85 static char buf[8];
86
87 if ((stat(fname, &st)) == (-1))
88 return (char *) "";
89
90 snprintf(buf, sizeof(buf), "%o", st.st_mode);
91
92 return (char *) buf + 2;
93}
94
95/* find the path to a file by name */
96static char *which(const char *fname)
97{
98 static char fullpath[BUFSIZ];
99 char *path, *p;
100
101 path = getenv("PATH");
102 if (!path)
103 return NULL;
104
105 path = xstrdup(path);
106 while ((p = strrchr(path, ':')) != NULL) {
107 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
108 *p = 0;
109 if (access(fullpath, R_OK) != (-1)) {
110 free(path);
111 return (char *) fullpath;
112 }
113 }
114 free(path);
115 return NULL;
116}
117
118/* 1 on failure. 0 otherwise */
119static int rematch(const char *regex, const char *match, int cflags)
120{
121 regex_t preg;
122 int ret;
123
124 if ((match == NULL) || (regex == NULL))
125 return EXIT_FAILURE;
126
127 if ((ret = regcomp(&preg, regex, cflags))) {
128 char err[256];
129
130 if (regerror(ret, &preg, err, sizeof(err)))
131 fprintf(stderr, "regcomp failed: %s", err);
132 else
133 fprintf(stderr, "regcomp failed");
134
135 return EXIT_FAILURE;
136 }
137 ret = regexec(&preg, match, 0, NULL, 0);
138 regfree(&preg);
139
140 return ret;
141}
70 142
71/* sub-funcs for scanelf_file() */ 143/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 144static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{ 145{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 146 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
116 continue; \ 188 continue; \
117 if (fix_elf && setpax) { \ 189 if (fix_elf && setpax) { \
118 /* set the paxctl flags */ \ 190 /* set the paxctl flags */ \
119 ESET(phdr[i].p_flags, setpax); \ 191 ESET(phdr[i].p_flags, setpax); \
120 } \ 192 } \
121 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 193 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
122 continue; \ 194 continue; \
123 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 195 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
124 *found_pax = 1; \ 196 *found_pax = 1; \
125 ++shown; \ 197 ++shown; \
126 break; \ 198 break; \
128 } 200 }
129 SHOW_PAX(32) 201 SHOW_PAX(32)
130 SHOW_PAX(64) 202 SHOW_PAX(64)
131 } 203 }
132 204
205 if (fix_elf && setpax) {
206 /* set the chpax settings */
207 if (elf->elf_class == ELFCLASS32) {
208 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
209 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
210 } else {
211 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
212 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
213 }
214 }
215
133 /* fall back to EI_PAX if no PT_PAX was found */ 216 /* fall back to EI_PAX if no PT_PAX was found */
134 if (!*ret) { 217 if (!*ret) {
135 static char *paxflags; 218 static char *paxflags;
136
137 if (fix_elf && setpax) {
138 /* set the chpax settings */
139 // ESET(EHDR ## B (elf->ehdr)->e_ident[EI_PAX]), setpax);
140 }
141
142 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 219 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
143 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 220 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
144 *found_pax = 1; 221 *found_pax = 1;
145 return (be_wewy_wewy_quiet ? NULL : paxflags); 222 return (be_wewy_wewy_quiet ? NULL : paxflags);
146 } 223 }
176 uint32_t flags, check_flags; \ 253 uint32_t flags, check_flags; \
177 if (elf->phdr != NULL) { \ 254 if (elf->phdr != NULL) { \
178 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 255 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
179 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 256 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
180 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 257 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
258 if (multi_stack++) \
181 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 259 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
260 if (file_matches_list(elf->filename, qa_execstack)) \
261 continue; \
182 found = found_phdr; \ 262 found = found_phdr; \
183 offset = 0; \ 263 offset = 0; \
184 check_flags = PF_X; \ 264 check_flags = PF_X; \
185 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 265 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
266 if (multi_relro++) \
186 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 267 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
187 found = found_relro; \ 268 found = found_relro; \
188 offset = 4; \ 269 offset = 4; \
189 check_flags = PF_X; \ 270 check_flags = PF_X; \
190 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 271 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
191 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \ 272 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
273 if (multi_load++ > max_pt_load) \
192 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \ 274 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
275 if (file_matches_list(elf->filename, qa_wx_load)) \
276 continue; \
193 found = found_load; \ 277 found = found_load; \
194 offset = 8; \ 278 offset = 8; \
195 check_flags = PF_W|PF_X; \ 279 check_flags = PF_W|PF_X; \
196 } else \ 280 } else \
197 continue; \ 281 continue; \
198 flags = EGET(phdr[i].p_flags); \ 282 flags = EGET(phdr[i].p_flags); \
199 if (be_quiet && ((flags & check_flags) != check_flags)) \ 283 if (be_quiet && ((flags & check_flags) != check_flags)) \
200 continue; \ 284 continue; \
201 if (fix_elf && ((flags & PF_X) != flags)) { \ 285 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
202 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \ 286 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
203 ret[3] = ret[7] = '!'; \ 287 ret[3] = ret[7] = '!'; \
204 flags = EGET(phdr[i].p_flags); \ 288 flags = EGET(phdr[i].p_flags); \
205 } \ 289 } \
206 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 290 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
234 break; \ 318 break; \
235 } \ 319 } \
236 } \ 320 } \
237 skip_this_shdr##B: \ 321 skip_this_shdr##B: \
238 if (!multi_stack) { \ 322 if (!multi_stack) { \
323 if (file_matches_list(elf->filename, qa_execstack)) \
324 return NULL; \
239 *found_phdr = 1; \ 325 *found_phdr = 1; \
240 shown = 1; \ 326 shown = 1; \
241 memcpy(ret, "!WX", 3); \ 327 memcpy(ret, "!WX", 3); \
242 } \ 328 } \
243 } \ 329 } \
248 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 334 if (be_wewy_wewy_quiet || (be_quiet && !shown))
249 return NULL; 335 return NULL;
250 else 336 else
251 return ret; 337 return ret;
252} 338}
339
340/*
341 * See if this ELF contains a DT_TEXTREL tag in any of its
342 * PT_DYNAMIC sections.
343 */
253static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 344static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
254{ 345{
255 static const char *ret = "TEXTREL"; 346 static const char *ret = "TEXTREL";
256 unsigned long i; 347 unsigned long i;
257 348
258 if (!show_textrel && !show_textrels) return NULL; 349 if (!show_textrel && !show_textrels) return NULL;
350
351 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
259 352
260 if (elf->phdr) { 353 if (elf->phdr) {
261#define SHOW_TEXTREL(B) \ 354#define SHOW_TEXTREL(B) \
262 if (elf->elf_class == ELFCLASS ## B) { \ 355 if (elf->elf_class == ELFCLASS ## B) { \
263 Elf ## B ## _Dyn *dyn; \ 356 Elf ## B ## _Dyn *dyn; \
264 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 357 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
265 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 358 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
266 Elf ## B ## _Off offset; \ 359 Elf ## B ## _Off offset; \
267 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 360 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
268 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 361 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
269 offset = EGET(phdr[i].p_offset); \ 362 offset = EGET(phdr[i].p_offset); \
270 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 363 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
271 dyn = DYN ## B (elf->data + offset); \ 364 dyn = DYN ## B (elf->data + offset); \
272 while (EGET(dyn->d_tag) != DT_NULL) { \ 365 while (EGET(dyn->d_tag) != DT_NULL) { \
273 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 366 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
285 if (be_quiet || be_wewy_wewy_quiet) 378 if (be_quiet || be_wewy_wewy_quiet)
286 return NULL; 379 return NULL;
287 else 380 else
288 return " - "; 381 return " - ";
289} 382}
383
384/*
385 * Scan the .text section to see if there are any relocations in it.
386 * Should rewrite this to check PT_LOAD sections that are marked
387 * Executable rather than the section named '.text'.
388 */
290static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 389static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
291{ 390{
292 unsigned long s, r, rmax; 391 unsigned long s, r, rmax;
293 void *symtab_void, *strtab_void, *text_void; 392 void *symtab_void, *strtab_void, *text_void;
294 393
361 /* show the raw details about this reloc */ \ 460 /* show the raw details about this reloc */ \
362 printf(" %s: ", elf->base_filename); \ 461 printf(" %s: ", elf->base_filename); \
363 if (sym && sym->st_name) \ 462 if (sym && sym->st_name) \
364 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 463 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
365 else \ 464 else \
366 printf("(memory/fake?)"); \ 465 printf("(memory/data?)"); \
367 printf(" [0x%lX]", (unsigned long)r_offset); \ 466 printf(" [0x%lX]", (unsigned long)r_offset); \
368 /* now try to find the closest symbol that this rel is probably in */ \ 467 /* now try to find the closest symbol that this rel is probably in */ \
369 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 468 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
370 func = NULL; \ 469 func = NULL; \
371 offset_tmp = 0; \ 470 offset_tmp = 0; \
375 offset_tmp = EGET(sym->st_value); \ 474 offset_tmp = EGET(sym->st_value); \
376 } \ 475 } \
377 ++sym; \ 476 ++sym; \
378 } \ 477 } \
379 printf(" in "); \ 478 printf(" in "); \
380 if (func && func->st_name) \ 479 if (func && func->st_name) { \
381 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ 480 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
481 if (r_offset > EGET(func->st_size)) \
482 printf("(optimized out: previous %s)", func_name); \
382 else \ 483 else \
383 printf("(NULL: fake?)"); \ 484 printf("%s", func_name); \
485 } else \
486 printf("(optimized out)"); \
384 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 487 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
488 if (be_verbose && has_objdump) { \
489 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
490 char *sysbuf; \
491 size_t syslen; \
492 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"; \
493 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
494 sysbuf = xmalloc(syslen); \
495 if (end_addr < r_offset) \
496 /* not uncommon when things are optimized out */ \
497 end_addr = r_offset + 0x100; \
498 snprintf(sysbuf, syslen, sysfmt, \
499 (unsigned long)offset_tmp, \
500 (unsigned long)end_addr, \
501 elf->filename, \
502 (unsigned long)r_offset); \
503 fflush(stdout); \
504 system(sysbuf); \
505 fflush(stdout); \
506 free(sysbuf); \
507 } \
385 } \ 508 } \
386 } } 509 } }
387 SHOW_TEXTRELS(32) 510 SHOW_TEXTRELS(32)
388 SHOW_TEXTRELS(64) 511 SHOW_TEXTRELS(64)
389 } 512 }
407 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 530 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
408 break; 531 break;
409 case '$': 532 case '$':
410 if (fstat(elf->fd, &st) != -1) 533 if (fstat(elf->fd, &st) != -1)
411 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 534 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
412 warnf("Security problem with %s='%s' in %s with mode set of %o", 535 warnf("Security problem with %s='%s' in %s with mode set of %o",
413 dt_type, item, elf->filename, st.st_mode & 07777); 536 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
414 break; 537 break;
415 default: 538 default:
416 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename); 539 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
417 break; 540 break;
418 } 541 }
438 Elf ## B ## _Off offset; \ 561 Elf ## B ## _Off offset; \
439 Elf ## B ## _Xword word; \ 562 Elf ## B ## _Xword word; \
440 /* Scan all the program headers */ \ 563 /* Scan all the program headers */ \
441 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 564 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
442 /* Just scan dynamic headers */ \ 565 /* Just scan dynamic headers */ \
443 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 566 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
444 offset = EGET(phdr[i].p_offset); \ 567 offset = EGET(phdr[i].p_offset); \
445 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 568 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
446 /* Just scan dynamic RPATH/RUNPATH headers */ \ 569 /* Just scan dynamic RPATH/RUNPATH headers */ \
447 dyn = DYN ## B (elf->data + offset); \ 570 dyn = DYN ## B (elf->data + offset); \
448 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 571 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
577#define FLAG_POWERPC_LIB64 0x0500 700#define FLAG_POWERPC_LIB64 0x0500
578#define FLAG_MIPS64_LIBN32 0x0600 701#define FLAG_MIPS64_LIBN32 0x0600
579#define FLAG_MIPS64_LIBN64 0x0700 702#define FLAG_MIPS64_LIBN64 0x0700
580 703
581static char *lookup_cache_lib(elfobj *, char *); 704static char *lookup_cache_lib(elfobj *, char *);
705
706#if defined(__GLIBC__) || defined(__UCLIBC__)
707
582static char *lookup_cache_lib(elfobj *elf, char *fname) 708static char *lookup_cache_lib(elfobj *elf, char *fname)
583{ 709{
584 int fd = 0; 710 int fd = 0;
585 char *strs; 711 char *strs;
586 static char buf[__PAX_UTILS_PATH_MAX] = ""; 712 static char buf[__PAX_UTILS_PATH_MAX] = "";
612 ldcache_size = st.st_size; 738 ldcache_size = st.st_size;
613 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); 739 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
614 740
615 close(fd); 741 close(fd);
616 742
617 if (ldcache == (caddr_t)-1) { 743 if (ldcache == MAP_FAILED) {
618 ldcache = 0; 744 ldcache = 0;
619 return NULL; 745 return NULL;
620 } 746 }
621 747
622 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 748 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
642 continue; 768 continue;
643 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 769 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
644 } 770 }
645 return buf; 771 return buf;
646} 772}
773#elif defined(__NetBSD__)
774static char *lookup_cache_lib(elfobj *elf, char *fname)
775{
776 static char buf[__PAX_UTILS_PATH_MAX] = "";
777 static struct stat st;
647 778
779 char **ldpath;
780 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
781 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
782 continue; /* if the pathname is too long, or something went wrong, ignore */
783
784 if (stat(buf, &st) != 0)
785 continue; /* if the lib doesn't exist in *ldpath, look further */
786
787 /* NetBSD doesn't actually do sanity checks, it just loads the file
788 * and if that doesn't work, continues looking in other directories.
789 * This cannot easily be safely emulated, unfortunately. For now,
790 * just assume that if it exists, it's a valid library. */
791
792 return buf;
793 }
794
795 /* not found in any path */
796 return NULL;
797}
798#else
799#ifdef __ELF__
800#warning Cache support not implemented for your target
801#endif
802static char *lookup_cache_lib(elfobj *elf, char *fname)
803{
804 return NULL;
805}
806#endif
648 807
649static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 808static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
650{ 809{
651 unsigned long i; 810 unsigned long i;
652 char *needed; 811 char *needed;
664 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 823 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
665 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 824 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
666 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 825 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
667 Elf ## B ## _Off offset; \ 826 Elf ## B ## _Off offset; \
668 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 827 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
669 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 828 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
670 offset = EGET(phdr[i].p_offset); \ 829 offset = EGET(phdr[i].p_offset); \
671 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 830 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
672 dyn = DYN ## B (elf->data + offset); \ 831 dyn = DYN ## B (elf->data + offset); \
673 while (EGET(dyn->d_tag) != DT_NULL) { \ 832 while (EGET(dyn->d_tag) != DT_NULL) { \
674 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 833 if (EGET(dyn->d_tag) == DT_NEEDED) { \
686 needed = p; \ 845 needed = p; \
687 xstrcat(ret, needed, ret_len); \ 846 xstrcat(ret, needed, ret_len); \
688 } \ 847 } \
689 *found_needed = 1; \ 848 *found_needed = 1; \
690 } else { \ 849 } else { \
691 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 850 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
692 *found_lib = 1; \ 851 *found_lib = 1; \
693 return (be_wewy_wewy_quiet ? NULL : needed); \ 852 return (be_wewy_wewy_quiet ? NULL : needed); \
694 } \ 853 } \
695 } \ 854 } \
696 } \ 855 } \
727} 886}
728static char *scanelf_file_bind(elfobj *elf, char *found_bind) 887static char *scanelf_file_bind(elfobj *elf, char *found_bind)
729{ 888{
730 unsigned long i; 889 unsigned long i;
731 struct stat s; 890 struct stat s;
891 char dynamic = 0;
732 892
733 if (!show_bind) return NULL; 893 if (!show_bind) return NULL;
734 if (!elf->phdr) return NULL; 894 if (!elf->phdr) return NULL;
735 895
736#define SHOW_BIND(B) \ 896#define SHOW_BIND(B) \
738 Elf ## B ## _Dyn *dyn; \ 898 Elf ## B ## _Dyn *dyn; \
739 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 899 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
740 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 900 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
741 Elf ## B ## _Off offset; \ 901 Elf ## B ## _Off offset; \
742 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 902 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
743 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 903 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
904 dynamic = 1; \
744 offset = EGET(phdr[i].p_offset); \ 905 offset = EGET(phdr[i].p_offset); \
745 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 906 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
746 dyn = DYN ## B (elf->data + offset); \ 907 dyn = DYN ## B (elf->data + offset); \
747 while (EGET(dyn->d_tag) != DT_NULL) { \ 908 while (EGET(dyn->d_tag) != DT_NULL) { \
748 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 909 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
759 SHOW_BIND(32) 920 SHOW_BIND(32)
760 SHOW_BIND(64) 921 SHOW_BIND(64)
761 922
762 if (be_wewy_wewy_quiet) return NULL; 923 if (be_wewy_wewy_quiet) return NULL;
763 924
925 /* don't output anything if quiet mode and the ELF is static or not setuid */
764 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 926 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
765 return NULL; 927 return NULL;
766 } else { 928 } else {
767 *found_bind = 1; 929 *found_bind = 1;
768 return (char *) "LAZY"; 930 return (char *) (dynamic ? "LAZY" : "STATIC");
769 } 931 }
770} 932}
771static char *scanelf_file_soname(elfobj *elf, char *found_soname) 933static char *scanelf_file_soname(elfobj *elf, char *found_soname)
772{ 934{
773 unsigned long i; 935 unsigned long i;
785 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 947 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
786 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 948 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
787 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 949 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
788 Elf ## B ## _Off offset; \ 950 Elf ## B ## _Off offset; \
789 /* only look for soname in shared objects */ \ 951 /* only look for soname in shared objects */ \
790 if (ehdr->e_type != ET_DYN) \ 952 if (EGET(ehdr->e_type) != ET_DYN) \
791 return NULL; \ 953 return NULL; \
792 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 954 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
793 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 955 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
794 offset = EGET(phdr[i].p_offset); \ 956 offset = EGET(phdr[i].p_offset); \
795 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 957 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
796 dyn = DYN ## B (elf->data + offset); \ 958 dyn = DYN ## B (elf->data + offset); \
797 while (EGET(dyn->d_tag) != DT_NULL) { \ 959 while (EGET(dyn->d_tag) != DT_NULL) { \
798 if (EGET(dyn->d_tag) == DT_SONAME) { \ 960 if (EGET(dyn->d_tag) == DT_SONAME) { \
812 SHOW_SONAME(64) 974 SHOW_SONAME(64)
813 } 975 }
814 976
815 return NULL; 977 return NULL;
816} 978}
979
980static int scanelf_match_symname(const char *symname, const char *tomatch) {
981 /* We do things differently when checking with regexp */
982 if (g_match) {
983 return rematch(symname, tomatch, REG_EXTENDED) == 0;
984 } else {
985 const size_t symname_len = strlen(symname);
986 return (strncmp(symname, tomatch, symname_len) == 0 &&
987 /* Accept unversioned symbol names */
988 (tomatch[symname_len] == '\0' || tomatch[symname_len] == '@'));
989 }
990}
991
817static char *scanelf_file_sym(elfobj *elf, char *found_sym) 992static char *scanelf_file_sym(elfobj *elf, char *found_sym)
818{ 993{
819 unsigned long i; 994 unsigned long i;
820 char *ret; 995 char *ret;
821 void *symtab_void, *strtab_void; 996 void *symtab_void, *strtab_void;
834 unsigned long cnt = EGET(symtab->sh_entsize); \ 1009 unsigned long cnt = EGET(symtab->sh_entsize); \
835 char *symname; \ 1010 char *symname; \
836 if (cnt) \ 1011 if (cnt) \
837 cnt = EGET(symtab->sh_size) / cnt; \ 1012 cnt = EGET(symtab->sh_size) / cnt; \
838 for (i = 0; i < cnt; ++i) { \ 1013 for (i = 0; i < cnt; ++i) { \
1014 if ((void*)sym > (void*)elf->data_end) { \
1015 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1016 goto break_out; \
1017 } \
839 if (sym->st_name) { \ 1018 if (sym->st_name) { \
1019 /* make sure the symbol name is in acceptable memory range */ \
840 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1020 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
841 if ((void*)symname > (void*)elf->data_end) { \ 1021 if ((void*)symname > (void*)elf->data_end) { \
842 warnf("%s: corrupt ELF symbols", elf->filename); \ 1022 warnf("%s: corrupt ELF symbols", elf->filename); \
1023 ++sym; \
843 continue; \ 1024 continue; \
844 } \ 1025 } \
845 if (*find_sym == '*') { \ 1026 /* debug display ... show all symbols and some extra info */ \
1027 if (0 && g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
846 printf("%s(%s) %5lX %15s %s\n", \ 1028 printf("%s(%s) %5lX %15s %s %s\n", \
847 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1029 ((*found_sym == 0) ? "\n\t" : "\t"), \
848 elf->base_filename, \ 1030 elf->base_filename, \
849 (unsigned long)sym->st_size, \ 1031 (unsigned long)sym->st_size, \
850 get_elfstttype(sym->st_info), \ 1032 get_elfstttype(sym->st_info), \
851 symname); \ 1033 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
852 *found_sym = 1; \ 1034 *found_sym = 1; \
853 } else { \ 1035 } else { \
1036 /* allow the user to specify a comma delimited list of symbols to search for */ \
854 char *this_sym, *next_sym; \ 1037 char *this_sym, *next_sym; \
1038 next_sym = ret; \
1039 while (next_sym) { \
855 this_sym = find_sym; \ 1040 this_sym = next_sym; \
856 do { \
857 next_sym = strchr(this_sym, ','); \ 1041 if ((next_sym = strchr(this_sym, ','))) \
858 if (next_sym == NULL) \ 1042 next_sym += 1; /* Skip the comma */ \
859 next_sym = this_sym + strlen(this_sym); \ 1043 /* do we want a defined symbol ? */ \
860 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \ 1044 if (*this_sym == '+') { \
861 (strcmp(symname, versioned_symname) == 0)) { \ 1045 if (sym->st_shndx == SHN_UNDEF) \
1046 continue; \
862 ret = this_sym; \ 1047 ++this_sym; \
1048 /* do we want an undefined symbol ? */ \
1049 } else if (*this_sym == '-') { \
1050 if (sym->st_shndx != SHN_UNDEF) \
1051 continue; \
1052 ++this_sym; \
1053 } \
1054 if (next_sym) /* Copy it so that we don't have to worry about the final , */ \
1055 this_sym = strndup(this_sym, next_sym-this_sym); \
1056 /* ok, lets compare the name now */ \
1057 if (scanelf_match_symname(this_sym, symname)) { \
1058 if (be_semi_verbose) { \
1059 char buf[126]; \
1060 snprintf(buf, sizeof(buf), "%lX %s %s", \
1061 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1062 ret = buf; \
1063 } else \
1064 ret = symname; \
863 (*found_sym)++; \ 1065 (*found_sym)++; \
864 goto break_out; \ 1066 goto break_out; \
865 } \ 1067 } \
866 this_sym = next_sym + 1; \ 1068 if (next_sym) free(this_sym); \
867 } while (*next_sym != '\0'); \ 1069 } \
868 } \ 1070 } \
869 } \ 1071 } \
870 ++sym; \ 1072 ++sym; \
871 } } 1073 } }
872 FIND_SYM(32) 1074 FIND_SYM(32)
882 return NULL; 1084 return NULL;
883 else 1085 else
884 return (char *)" - "; 1086 return (char *)" - ";
885} 1087}
886 1088
887
888static char *scanelf_file_sections(elfobj *elf, char *found_section) 1089static char *scanelf_file_sections(elfobj *elf, char *found_section)
889{ 1090{
890 if (!find_section) 1091 if (!find_section)
891 return NULL; 1092 return NULL;
892 1093
893#define FIND_SECTION(B) \ 1094#define FIND_SECTION(B) \
894 if (elf->elf_class == ELFCLASS ## B) { \ 1095 if (elf->elf_class == ELFCLASS ## B) { \
1096 int invert; \
895 Elf ## B ## _Shdr *section; \ 1097 Elf ## B ## _Shdr *section; \
1098 invert = (*find_section == '!' ? 1 : 0); \
896 section = SHDR ## B (elf_findsecbyname(elf, find_section)); \ 1099 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
897 if (section != NULL) \ 1100 if ((section == NULL && invert) || (section != NULL && !invert)) \
898 *found_section = 1; \ 1101 *found_section = 1; \
899 } 1102 }
900 FIND_SECTION(32) 1103 FIND_SECTION(32)
901 FIND_SECTION(64) 1104 FIND_SECTION(64)
902 1105
903
904 if (be_wewy_wewy_quiet) return NULL; 1106 if (be_wewy_wewy_quiet)
1107 return NULL;
905 1108
906 if (*found_section) 1109 if (*found_section)
907 return find_section; 1110 return find_section;
908 1111
909 if (be_quiet) 1112 if (be_quiet)
915/* scan an elf file and show all the fun stuff */ 1118/* scan an elf file and show all the fun stuff */
916#define prints(str) write(fileno(stdout), str, strlen(str)) 1119#define prints(str) write(fileno(stdout), str, strlen(str))
917static int scanelf_elfobj(elfobj *elf) 1120static int scanelf_elfobj(elfobj *elf)
918{ 1121{
919 unsigned long i; 1122 unsigned long i;
920 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1123 char found_pax, found_phdr, found_relro, found_load, found_textrel,
921 found_rpath, found_needed, found_interp, found_bind, found_soname, 1124 found_rpath, found_needed, found_interp, found_bind, found_soname,
922 found_sym, found_lib, found_file, found_textrels, found_section; 1125 found_sym, found_lib, found_file, found_textrels, found_section;
923 static char *out_buffer = NULL; 1126 static char *out_buffer = NULL;
924 static size_t out_len; 1127 static size_t out_len;
925 1128
926 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1129 found_pax = found_phdr = found_relro = found_load = found_textrel = \
935 printf("%s: scanning file\n", elf->filename); 1138 printf("%s: scanning file\n", elf->filename);
936 1139
937 /* init output buffer */ 1140 /* init output buffer */
938 if (!out_buffer) { 1141 if (!out_buffer) {
939 out_len = sizeof(char) * 80; 1142 out_len = sizeof(char) * 80;
940 out_buffer = (char*)xmalloc(out_len); 1143 out_buffer = xmalloc(out_len);
941 } 1144 }
942 *out_buffer = '\0'; 1145 *out_buffer = '\0';
943 1146
944 /* show the header */ 1147 /* show the header */
945 if (!be_quiet && show_banner) { 1148 if (!be_quiet && show_banner) {
946 for (i = 0; out_format[i]; ++i) { 1149 for (i = 0; out_format[i]; ++i) {
947 if (!IS_MODIFIER(out_format[i])) continue; 1150 if (!IS_MODIFIER(out_format[i])) continue;
948 1151
949 switch (out_format[++i]) { 1152 switch (out_format[++i]) {
1153 case '+': break;
950 case '%': break; 1154 case '%': break;
951 case '#': break; 1155 case '#': break;
952 case 'F': 1156 case 'F':
953 case 'p': 1157 case 'p':
954 case 'f': prints("FILE "); found_file = 1; break; 1158 case 'f': prints("FILE "); found_file = 1; break;
955 case 'o': prints(" TYPE "); break; 1159 case 'o': prints(" TYPE "); break;
956 case 'x': prints(" PAX "); break; 1160 case 'x': prints(" PAX "); break;
957 case 'e': prints("STK/REL/PTL "); break; 1161 case 'e': prints("STK/REL/PTL "); break;
958 case 't': prints("TEXTREL "); break; 1162 case 't': prints("TEXTREL "); break;
959 case 'r': prints("RPATH "); break; 1163 case 'r': prints("RPATH "); break;
1164 case 'M': prints("CLASS "); break;
960 case 'n': prints("NEEDED "); break; 1165 case 'n': prints("NEEDED "); break;
961 case 'i': prints("INTERP "); break; 1166 case 'i': prints("INTERP "); break;
962 case 'b': prints("BIND "); break; 1167 case 'b': prints("BIND "); break;
1168 case 'Z': prints("SIZE "); break;
963 case 'S': prints("SONAME "); break; 1169 case 'S': prints("SONAME "); break;
964 case 's': prints("SYM "); break; 1170 case 's': prints("SYM "); break;
965 case 'N': prints("LIB "); break; 1171 case 'N': prints("LIB "); break;
966 case 'T': prints("TEXTRELS "); break; 1172 case 'T': prints("TEXTRELS "); break;
967 case 'k': prints("SECTION "); break; 1173 case 'k': prints("SECTION "); break;
1174 case 'a': prints("ARCH "); break;
1175 case 'I': prints("OSABI "); break;
1176 case 'Y': prints("EABI "); break;
1177 case 'O': prints("PERM "); break;
1178 case 'D': prints("ENDIAN "); break;
968 default: warnf("'%c' has no title ?", out_format[i]); 1179 default: warnf("'%c' has no title ?", out_format[i]);
969 } 1180 }
970 } 1181 }
971 if (!found_file) prints("FILE "); 1182 if (!found_file) prints("FILE ");
972 prints("\n"); 1183 prints("\n");
976 1187
977 /* dump all the good stuff */ 1188 /* dump all the good stuff */
978 for (i = 0; out_format[i]; ++i) { 1189 for (i = 0; out_format[i]; ++i) {
979 const char *out; 1190 const char *out;
980 const char *tmp; 1191 const char *tmp;
981 1192 static char ubuf[sizeof(unsigned long)*2];
982 if (!IS_MODIFIER(out_format[i])) { 1193 if (!IS_MODIFIER(out_format[i])) {
983 xchrcat(&out_buffer, out_format[i], &out_len); 1194 xchrcat(&out_buffer, out_format[i], &out_len);
984 continue; 1195 continue;
985 } 1196 }
986 1197
987 out = NULL; 1198 out = NULL;
988 be_wewy_wewy_quiet = (out_format[i] == '#'); 1199 be_wewy_wewy_quiet = (out_format[i] == '#');
1200 be_semi_verbose = (out_format[i] == '+');
989 switch (out_format[++i]) { 1201 switch (out_format[++i]) {
1202 case '+':
990 case '%': 1203 case '%':
991 case '#': 1204 case '#':
992 xchrcat(&out_buffer, out_format[i], &out_len); break; 1205 xchrcat(&out_buffer, out_format[i], &out_len); break;
993 case 'F': 1206 case 'F':
994 found_file = 1; 1207 found_file = 1;
1020 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1233 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1021 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1234 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1022 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1235 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1023 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; 1236 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1024 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1237 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1238 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1239 case 'D': out = get_endian(elf); break;
1240 case 'O': out = getstr_perms(elf->filename); break;
1025 case 'n': 1241 case 'n':
1026 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1242 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1027 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1243 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1028 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1244 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1029 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1245 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1030 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1246 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1031 case 'k': out = scanelf_file_sections(elf, &found_section); break; 1247 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1248 case 'a': out = get_elfemtype(elf); break;
1249 case 'I': out = get_elfosabi(elf); break;
1250 case 'Y': out = get_elf_eabi(elf); break;
1251 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;;
1032 default: warnf("'%c' has no scan code?", out_format[i]); 1252 default: warnf("'%c' has no scan code?", out_format[i]);
1033 } 1253 }
1034 if (out) { 1254 if (out) {
1035 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1255 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1036 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1256 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1082 if (strlen(match_etypes)) { 1302 if (strlen(match_etypes)) {
1083 char sbuf[126]; 1303 char sbuf[126];
1084 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1304 strncpy(sbuf, match_etypes, sizeof(sbuf));
1085 if (strchr(match_etypes, ',') != NULL) { 1305 if (strchr(match_etypes, ',') != NULL) {
1086 char *p; 1306 char *p;
1087 while((p = strrchr(sbuf, ',')) != NULL) { 1307 while ((p = strrchr(sbuf, ',')) != NULL) {
1088 *p = 0; 1308 *p = 0;
1089 if (atoi(p+1) == get_etype(elf)) 1309 if (etype_lookup(p+1) == get_etype(elf))
1090 goto label_ret; 1310 goto label_ret;
1091 } 1311 }
1092 } 1312 }
1093 if (atoi(sbuf) != get_etype(elf)) 1313 if (etype_lookup(sbuf) != get_etype(elf))
1094 goto label_done; 1314 goto label_done;
1095 } 1315 }
1096 1316
1097label_ret: 1317label_ret:
1098 ret = scanelf_elfobj(elf); 1318 ret = scanelf_elfobj(elf);
1112 1332
1113 ar = ar_open_fd(filename, fd); 1333 ar = ar_open_fd(filename, fd);
1114 if (ar == NULL) 1334 if (ar == NULL)
1115 return 1; 1335 return 1;
1116 1336
1117 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0); 1337 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1118 while ((m=ar_next(ar)) != NULL) { 1338 while ((m=ar_next(ar)) != NULL) {
1119 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size); 1339 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1120 if (elf) { 1340 if (elf) {
1121 scanelf_elfobj(elf); 1341 scanelf_elfobj(elf);
1122 unreadelf(elf); 1342 unreadelf(elf);
1125 munmap(ar_buffer, len); 1345 munmap(ar_buffer, len);
1126 1346
1127 return 0; 1347 return 0;
1128} 1348}
1129/* scan a file which may be an elf or an archive or some other magical beast */ 1349/* scan a file which may be an elf or an archive or some other magical beast */
1130static void scanelf_file(const char *filename) 1350static int scanelf_file(const char *filename, const struct stat *st_cache)
1131{ 1351{
1352 const struct stat *st = st_cache;
1132 struct stat st; 1353 struct stat symlink_st;
1133 int fd; 1354 int fd;
1134 1355
1135 /* make sure 'filename' exists */
1136 if (lstat(filename, &st) == -1) {
1137 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1138 return;
1139 }
1140
1141 /* always handle regular files and handle symlinked files if no -y */ 1356 /* always handle regular files and handle symlinked files if no -y */
1142 if (S_ISLNK(st.st_mode)) { 1357 if (S_ISLNK(st->st_mode)) {
1143 if (!scan_symlink) return; 1358 if (!scan_symlink) return 1;
1144 stat(filename, &st); 1359 stat(filename, &symlink_st);
1360 st = &symlink_st;
1145 } 1361 }
1362
1146 if (!S_ISREG(st.st_mode)) { 1363 if (!S_ISREG(st->st_mode)) {
1147 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1364 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1148 return; 1365 return 1;
1149 } 1366 }
1150 1367
1368 if (match_perms) {
1369 if ((st->st_mode | match_perms) != st->st_mode)
1370 return 1;
1371 }
1151 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1372 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1152 return; 1373 return 1;
1153 1374
1154 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1375 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1155 /* if it isn't an ELF, maybe it's an .a archive */ 1376 /* if it isn't an ELF, maybe it's an .a archive */
1156 scanelf_archive(filename, fd, st.st_size); 1377 scanelf_archive(filename, fd, st->st_size);
1157 1378
1158 close(fd); 1379 close(fd);
1380 return 0;
1159} 1381}
1160 1382
1161/* scan a directory for ET_EXEC files and print when we find one */ 1383/* scan a directory for ET_EXEC files and print when we find one */
1162static void scanelf_dir(const char *path) 1384static int scanelf_dir(const char *path)
1163{ 1385{
1164 register DIR *dir; 1386 register DIR *dir;
1165 register struct dirent *dentry; 1387 register struct dirent *dentry;
1166 struct stat st_top, st; 1388 struct stat st_top, st;
1167 char buf[__PAX_UTILS_PATH_MAX]; 1389 char buf[__PAX_UTILS_PATH_MAX];
1168 size_t pathlen = 0, len = 0; 1390 size_t pathlen = 0, len = 0;
1391 int ret = 0;
1169 1392
1170 /* make sure path exists */ 1393 /* make sure path exists */
1171 if (lstat(path, &st_top) == -1) { 1394 if (lstat(path, &st_top) == -1) {
1172 if (be_verbose > 2) printf("%s: does not exist\n", path); 1395 if (be_verbose > 2) printf("%s: does not exist\n", path);
1173 return; 1396 return 1;
1174 } 1397 }
1175 1398
1176 /* ok, if it isn't a directory, assume we can open it */ 1399 /* ok, if it isn't a directory, assume we can open it */
1177 if (!S_ISDIR(st_top.st_mode)) { 1400 if (!S_ISDIR(st_top.st_mode)) {
1178 scanelf_file(path); 1401 return scanelf_file(path, &st_top);
1179 return;
1180 } 1402 }
1181 1403
1182 /* now scan the dir looking for fun stuff */ 1404 /* now scan the dir looking for fun stuff */
1183 if ((dir = opendir(path)) == NULL) { 1405 if ((dir = opendir(path)) == NULL) {
1184 warnf("could not opendir %s: %s", path, strerror(errno)); 1406 warnf("could not opendir %s: %s", path, strerror(errno));
1185 return; 1407 return 1;
1186 } 1408 }
1187 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1409 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1188 1410
1189 pathlen = strlen(path); 1411 pathlen = strlen(path);
1190 while ((dentry = readdir(dir))) { 1412 while ((dentry = readdir(dir))) {
1194 if (len >= sizeof(buf)) { 1416 if (len >= sizeof(buf)) {
1195 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1417 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1196 (unsigned long)len, (unsigned long)sizeof(buf)); 1418 (unsigned long)len, (unsigned long)sizeof(buf));
1197 continue; 1419 continue;
1198 } 1420 }
1199 sprintf(buf, "%s/%s", path, dentry->d_name); 1421 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1200 if (lstat(buf, &st) != -1) { 1422 if (lstat(buf, &st) != -1) {
1201 if (S_ISREG(st.st_mode)) 1423 if (S_ISREG(st.st_mode))
1202 scanelf_file(buf); 1424 ret = scanelf_file(buf, &st);
1203 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1425 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1204 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1426 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1205 scanelf_dir(buf); 1427 ret = scanelf_dir(buf);
1206 } 1428 }
1207 } 1429 }
1208 } 1430 }
1209 closedir(dir); 1431 closedir(dir);
1432 return ret;
1210} 1433}
1211 1434
1212static int scanelf_from_file(char *filename) 1435static int scanelf_from_file(const char *filename)
1213{ 1436{
1214 FILE *fp = NULL; 1437 FILE *fp = NULL;
1215 char *p; 1438 char *p;
1216 char path[__PAX_UTILS_PATH_MAX]; 1439 char path[__PAX_UTILS_PATH_MAX];
1440 int ret = 0;
1217 1441
1218 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1442 if (strcmp(filename, "-") == 0)
1219 fp = stdin; 1443 fp = stdin;
1220 else if ((fp = fopen(filename, "r")) == NULL) 1444 else if ((fp = fopen(filename, "r")) == NULL)
1221 return 1; 1445 return 1;
1222 1446
1223 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1447 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1224 if ((p = strchr(path, '\n')) != NULL) 1448 if ((p = strchr(path, '\n')) != NULL)
1225 *p = 0; 1449 *p = 0;
1226 search_path = path; 1450 search_path = path;
1227 scanelf_dir(path); 1451 ret = scanelf_dir(path);
1228 } 1452 }
1229 if (fp != stdin) 1453 if (fp != stdin)
1230 fclose(fp); 1454 fclose(fp);
1231 return 0; 1455 return ret;
1232} 1456}
1233 1457
1458#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1459
1234static int load_ld_so_conf(int i, const char *fname) 1460static int load_ld_cache_config(int i, const char *fname)
1235{ 1461{
1236 FILE *fp = NULL; 1462 FILE *fp = NULL;
1237 char *p; 1463 char *p;
1238 char path[__PAX_UTILS_PATH_MAX]; 1464 char path[__PAX_UTILS_PATH_MAX];
1239 1465
1240 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1466 if (i + 1 == ARRAY_SIZE(ldpaths))
1241 return i; 1467 return i;
1242 1468
1243 if ((fp = fopen(fname, "r")) == NULL) 1469 if ((fp = fopen(fname, "r")) == NULL)
1244 return i; 1470 return i;
1245 1471
1246 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1472 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1247 if ((p = strrchr(path, '\r')) != NULL) 1473 if ((p = strrchr(path, '\r')) != NULL)
1248 *p = 0; 1474 *p = 0;
1249 if ((p = strchr(path, '\n')) != NULL) 1475 if ((p = strchr(path, '\n')) != NULL)
1250 *p = 0; 1476 *p = 0;
1251#ifdef HAVE_GLOB 1477#ifdef __linux__
1252 // recursive includes of the same file will make this segfault. 1478 /* recursive includes of the same file will make this segfault. */
1253 if ((*path == 'i') && (strncmp(path, "include", 7) == 0) && isblank(path[7])) { 1479 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1254 glob64_t gl; 1480 glob64_t gl;
1255 size_t x; 1481 size_t x;
1256 char gpath[__PAX_UTILS_PATH_MAX]; 1482 char gpath[__PAX_UTILS_PATH_MAX];
1257 1483
1258 gpath[sizeof(gpath)] = 0; 1484 memset(gpath, 0, sizeof(gpath));
1259 1485
1260 if (path[8] != '/') 1486 if (path[8] != '/')
1261 snprintf(gpath, sizeof(gpath)-1, "/etc/%s", &path[8]); 1487 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1262 else 1488 else
1263 strncpy(gpath, &path[8], sizeof(gpath)-1); 1489 strncpy(gpath, &path[8], sizeof(gpath));
1264 1490
1265 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1491 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1266 for (x = 0; x < gl.gl_pathc; ++x) { 1492 for (x = 0; x < gl.gl_pathc; ++x) {
1267 /* try to avoid direct loops */ 1493 /* try to avoid direct loops */
1268 if (strcmp(gl.gl_pathv[x], fname) == 0) 1494 if (strcmp(gl.gl_pathv[x], fname) == 0)
1269 continue; 1495 continue;
1270 i = load_ld_so_conf(i, gl.gl_pathv[x]); 1496 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1271 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) { 1497 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1272 globfree64(&gl); 1498 globfree64(&gl);
1273 return i; 1499 return i;
1274 } 1500 }
1275 } 1501 }
1276 globfree64 (&gl); 1502 globfree64 (&gl);
1277 continue; 1503 continue;
1278 } else 1504 }
1279 abort();
1280 } 1505 }
1281#endif 1506#endif
1282 if (*path != '/') 1507 if (*path != '/')
1283 continue; 1508 continue;
1284 1509
1285 ldpaths[i++] = xstrdup(path); 1510 ldpaths[i++] = xstrdup(path);
1286 1511
1287 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1512 if (i + 1 == ARRAY_SIZE(ldpaths))
1288 break; 1513 break;
1289 } 1514 }
1290 ldpaths[i] = NULL; 1515 ldpaths[i] = NULL;
1291 1516
1292 fclose(fp); 1517 fclose(fp);
1293 return i; 1518 return i;
1294} 1519}
1295 1520
1521#elif defined(__FreeBSD__) || (__DragonFly__)
1522
1523static int load_ld_cache_config(int i, const char *fname)
1524{
1525 FILE *fp = NULL;
1526 char *b = NULL, *p;
1527 struct elfhints_hdr hdr;
1528
1529 if (i + 1 == ARRAY_SIZE(ldpaths))
1530 return i;
1531
1532 if ((fp = fopen(fname, "r")) == NULL)
1533 return i;
1534
1535 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1536 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1537 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1538 {
1539 fclose(fp);
1540 return i;
1541 }
1542
1543 b = xmalloc(hdr.dirlistlen + 1);
1544 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1545 fclose(fp);
1546 free(b);
1547 return i;
1548 }
1549
1550 while ((p = strsep(&b, ":"))) {
1551 if (*p == '\0') continue;
1552 ldpaths[i++] = xstrdup(p);
1553
1554 if (i + 1 == ARRAY_SIZE(ldpaths))
1555 break;
1556 }
1557 ldpaths[i] = NULL;
1558
1559 free(b);
1560 fclose(fp);
1561 return i;
1562}
1563
1564#else
1565#ifdef __ELF__
1566#warning Cache config support not implemented for your target
1567#endif
1568static int load_ld_cache_config(int i, const char *fname)
1569{
1570 memset(ldpaths, 0x00, sizeof(ldpaths));
1571 return 0;
1572}
1573#endif
1574
1296/* scan /etc/ld.so.conf for paths */ 1575/* scan /etc/ld.so.conf for paths */
1297static void scanelf_ldpath() 1576static void scanelf_ldpath(void)
1298{ 1577{
1299 char scan_l, scan_ul, scan_ull; 1578 char scan_l, scan_ul, scan_ull;
1300 int i = 0; 1579 int i = 0;
1301 1580
1302 if (!ldpaths[0]) 1581 if (!ldpaths[0])
1316 if (!scan_ul) scanelf_dir("/usr/lib"); 1595 if (!scan_ul) scanelf_dir("/usr/lib");
1317 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1596 if (!scan_ull) scanelf_dir("/usr/local/lib");
1318} 1597}
1319 1598
1320/* scan env PATH for paths */ 1599/* scan env PATH for paths */
1321static void scanelf_envpath() 1600static void scanelf_envpath(void)
1322{ 1601{
1323 char *path, *p; 1602 char *path, *p;
1324 1603
1325 path = getenv("PATH"); 1604 path = getenv("PATH");
1326 if (!path) 1605 if (!path)
1333 } 1612 }
1334 1613
1335 free(path); 1614 free(path);
1336} 1615}
1337 1616
1338/* usage / invocation handling functions */ 1617/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H J K P Q U W */
1339#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV" 1618#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZBhV"
1340#define a_argument required_argument 1619#define a_argument required_argument
1341static struct option const long_opts[] = { 1620static struct option const long_opts[] = {
1342 {"path", no_argument, NULL, 'p'}, 1621 {"path", no_argument, NULL, 'p'},
1343 {"ldpath", no_argument, NULL, 'l'}, 1622 {"ldpath", no_argument, NULL, 'l'},
1344 {"recursive", no_argument, NULL, 'R'}, 1623 {"recursive", no_argument, NULL, 'R'},
1361 {"lib", a_argument, NULL, 'N'}, 1640 {"lib", a_argument, NULL, 'N'},
1362 {"gmatch", no_argument, NULL, 'g'}, 1641 {"gmatch", no_argument, NULL, 'g'},
1363 {"textrels", no_argument, NULL, 'T'}, 1642 {"textrels", no_argument, NULL, 'T'},
1364 {"etype", a_argument, NULL, 'E'}, 1643 {"etype", a_argument, NULL, 'E'},
1365 {"bits", a_argument, NULL, 'M'}, 1644 {"bits", a_argument, NULL, 'M'},
1645 {"endian", no_argument, NULL, 'D'},
1646 {"osabi", no_argument, NULL, 'I'},
1647 {"eabi", no_argument, NULL, 'Y'},
1648 {"perms", a_argument, NULL, 'O'},
1649 {"size", no_argument, NULL, 'Z'},
1366 {"all", no_argument, NULL, 'a'}, 1650 {"all", no_argument, NULL, 'a'},
1367 {"quiet", no_argument, NULL, 'q'}, 1651 {"quiet", no_argument, NULL, 'q'},
1368 {"verbose", no_argument, NULL, 'v'}, 1652 {"verbose", no_argument, NULL, 'v'},
1369 {"format", a_argument, NULL, 'F'}, 1653 {"format", a_argument, NULL, 'F'},
1370 {"from", a_argument, NULL, 'f'}, 1654 {"from", a_argument, NULL, 'f'},
1396 "Find a specified symbol", 1680 "Find a specified symbol",
1397 "Find a specified section", 1681 "Find a specified section",
1398 "Find a specified library", 1682 "Find a specified library",
1399 "Use strncmp to match libraries. (use with -N)", 1683 "Use strncmp to match libraries. (use with -N)",
1400 "Locate cause of TEXTREL", 1684 "Locate cause of TEXTREL",
1401 "Print only ELF files matching numeric constant type", 1685 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1402 "Print only ELF files matching numeric bits", 1686 "Print only ELF files matching numeric bits",
1687 "Print Endianness",
1688 "Print OSABI",
1689 "Print EABI (EM_ARM Only)",
1690 "Print only ELF files matching octal permissions",
1691 "Print ELF file size",
1403 "Print all scanned info (-x -e -t -r -b)\n", 1692 "Print all scanned info (-x -e -t -r -b)\n",
1404 "Only output 'bad' things", 1693 "Only output 'bad' things",
1405 "Be verbose (can be specified more than once)", 1694 "Be verbose (can be specified more than once)",
1406 "Use specified format for output", 1695 "Use specified format for output",
1407 "Read input stream from a filename", 1696 "Read input stream from a filename",
1419 printf("* Scan ELF binaries for stuff\n\n" 1708 printf("* Scan ELF binaries for stuff\n\n"
1420 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 1709 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1421 printf("Options: -[%s]\n", PARSE_FLAGS); 1710 printf("Options: -[%s]\n", PARSE_FLAGS);
1422 for (i = 0; long_opts[i].name; ++i) 1711 for (i = 0; long_opts[i].name; ++i)
1423 if (long_opts[i].has_arg == no_argument) 1712 if (long_opts[i].has_arg == no_argument)
1424 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 1713 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1425 long_opts[i].name, opts_help[i]); 1714 long_opts[i].name, opts_help[i]);
1426 else 1715 else
1427 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 1716 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1428 long_opts[i].name, opts_help[i]); 1717 long_opts[i].name, opts_help[i]);
1429 1718
1430 if (status != EXIT_SUCCESS) 1719 puts("\nFor more information, see the scanelf(1) manpage");
1431 exit(status);
1432
1433 puts("\nThe format modifiers for the -F option are:");
1434 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1435 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1436 puts(" i INTERP \tb BIND \ts symbol");
1437 puts(" N library \to Type \tT TEXTRELs");
1438 puts(" S SONAME \tk section");
1439 puts(" p filename (with search path removed)");
1440 puts(" f filename (short name/basename)");
1441 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1442
1443 puts("\nELF Etypes:");
1444 print_etypes(stdout);
1445
1446 exit(status); 1720 exit(status);
1447} 1721}
1448 1722
1449/* parse command line arguments and preform needed actions */ 1723/* parse command line arguments and preform needed actions */
1724#define do_pax_state(option, flag) \
1725 if (islower(option)) { \
1726 flags &= ~PF_##flag; \
1727 flags |= PF_NO##flag; \
1728 } else { \
1729 flags &= ~PF_NO##flag; \
1730 flags |= PF_##flag; \
1731 }
1450static void parseargs(int argc, char *argv[]) 1732static int parseargs(int argc, char *argv[])
1451{ 1733{
1452 int i; 1734 int i;
1453 char *from_file = NULL; 1735 const char *from_file = NULL;
1736 int ret = 0;
1454 1737
1455 opterr = 0; 1738 opterr = 0;
1456 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1739 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1457 switch (i) { 1740 switch (i) {
1458 1741
1470 case 'E': 1753 case 'E':
1471 strncpy(match_etypes, optarg, sizeof(match_etypes)); 1754 strncpy(match_etypes, optarg, sizeof(match_etypes));
1472 break; 1755 break;
1473 case 'M': 1756 case 'M':
1474 match_bits = atoi(optarg); 1757 match_bits = atoi(optarg);
1758 if (match_bits == 0) {
1759 if (strcmp(optarg, "ELFCLASS32") == 0)
1760 match_bits = 32;
1761 if (strcmp(optarg, "ELFCLASS64") == 0)
1762 match_bits = 64;
1763 }
1764 break;
1765 case 'O':
1766 if (sscanf(optarg, "%o", &match_perms) == (-1))
1767 match_bits = 0;
1475 break; 1768 break;
1476 case 'o': { 1769 case 'o': {
1477 FILE *fp = NULL;
1478 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1770 if (freopen(optarg, "w", stdout) == NULL)
1479 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1771 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1480 SET_STDOUT(fp);
1481 break; 1772 break;
1482 } 1773 }
1483 case 'k': 1774 case 'k':
1484 if (find_section) warn("You prob don't want to specify -k twice"); 1775 if (find_section) warn("You prob don't want to specify -k twice");
1485 find_section = optarg; 1776 find_section = optarg;
1486 break; 1777 break;
1487 case 's': { 1778 case 's': {
1488 if (find_sym) warn("You prob don't want to specify -s twice"); 1779 if (find_sym) warn("You prob don't want to specify -s twice");
1489 find_sym = optarg; 1780 find_sym = optarg;
1490 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1491 sprintf(versioned_symname, "%s@", find_sym);
1492 break; 1781 break;
1493 } 1782 }
1494 case 'N': { 1783 case 'N': {
1495 if (find_lib) warn("You prob don't want to specify -N twice"); 1784 if (find_lib) warn("You prob don't want to specify -N twice");
1496 find_lib = optarg; 1785 find_lib = optarg;
1501 if (out_format) warn("You prob don't want to specify -F twice"); 1790 if (out_format) warn("You prob don't want to specify -F twice");
1502 out_format = optarg; 1791 out_format = optarg;
1503 break; 1792 break;
1504 } 1793 }
1505 case 'z': { 1794 case 'z': {
1506 unsigned long flags = 10240; 1795 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1507 size_t x; 1796 size_t x;
1508 1797
1509#define do_state(option, flag) \
1510 if (islower(option)) { \
1511 flags &= ~PF_##flag; \
1512 flags |= PF_NO##flag; \
1513 } else { \
1514 flags &= ~PF_NO##flag; \
1515 flags |= PF_##flag; \
1516 }
1517
1518 for (x = 0 ; x < strlen(optarg); x++) { 1798 for (x = 0; x < strlen(optarg); x++) {
1519 switch(optarg[x]) { 1799 switch (optarg[x]) {
1520 case 'p': 1800 case 'p':
1521 case 'P': 1801 case 'P':
1522 do_state(optarg[x], PAGEEXEC); 1802 do_pax_state(optarg[x], PAGEEXEC);
1523 break; 1803 break;
1524 case 's': 1804 case 's':
1525 case 'S': 1805 case 'S':
1526 do_state(optarg[x], SEGMEXEC); 1806 do_pax_state(optarg[x], SEGMEXEC);
1527 break; 1807 break;
1528 case 'm': 1808 case 'm':
1529 case 'M': 1809 case 'M':
1530 do_state(optarg[x], MPROTECT); 1810 do_pax_state(optarg[x], MPROTECT);
1531 break; 1811 break;
1532 case 'e': 1812 case 'e':
1533 case 'E': 1813 case 'E':
1534 do_state(optarg[x], EMUTRAMP); 1814 do_pax_state(optarg[x], EMUTRAMP);
1535 break; 1815 break;
1536 case 'r': 1816 case 'r':
1537 case 'R': 1817 case 'R':
1538 do_state(optarg[x], RANDMMAP); 1818 do_pax_state(optarg[x], RANDMMAP);
1539 break; 1819 break;
1540 case 'x': 1820 case 'x':
1541 case 'X': 1821 case 'X':
1542 do_state(optarg[x], RANDEXEC); 1822 do_pax_state(optarg[x], RANDEXEC);
1543 break; 1823 break;
1544 default: 1824 default:
1545 break; 1825 break;
1546 } 1826 }
1547 } 1827 }
1552 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) || 1832 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1553 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)))) 1833 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1554 setpax = flags; 1834 setpax = flags;
1555 break; 1835 break;
1556 } 1836 }
1837 case 'Z': show_size = 1; break;
1557 case 'g': gmatch = 1; break; 1838 case 'g': g_match = 1; break;
1558 case 'L': use_ldcache = 1; break; 1839 case 'L': use_ldcache = 1; break;
1559 case 'y': scan_symlink = 0; break; 1840 case 'y': scan_symlink = 0; break;
1560 case 'A': scan_archives = 1; break; 1841 case 'A': scan_archives = 1; break;
1561 case 'B': show_banner = 0; break; 1842 case 'B': show_banner = 0; break;
1562 case 'l': scan_ldpath = 1; break; 1843 case 'l': scan_ldpath = 1; break;
1573 case 'b': show_bind = 1; break; 1854 case 'b': show_bind = 1; break;
1574 case 'S': show_soname = 1; break; 1855 case 'S': show_soname = 1; break;
1575 case 'T': show_textrels = 1; break; 1856 case 'T': show_textrels = 1; break;
1576 case 'q': be_quiet = 1; break; 1857 case 'q': be_quiet = 1; break;
1577 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1858 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1578 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1859 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1579 1860 case 'D': show_endian = 1; break;
1861 case 'I': show_osabi = 1; break;
1862 case 'Y': show_eabi = 1; break;
1580 case ':': 1863 case ':':
1581 err("Option '%c' is missing parameter", optopt); 1864 err("Option '%c' is missing parameter", optopt);
1582 case '?': 1865 case '?':
1583 err("Unknown option '%c' or argument missing", optopt); 1866 err("Unknown option '%c' or argument missing", optopt);
1584 default: 1867 default:
1585 err("Unhandled option '%c'; please report this", i); 1868 err("Unhandled option '%c'; please report this", i);
1586 } 1869 }
1587 } 1870 }
1588 1871 if (show_textrels && be_verbose) {
1872 if (which("objdump") != NULL)
1873 has_objdump = 1;
1874 }
1589 /* let the format option override all other options */ 1875 /* let the format option override all other options */
1590 if (out_format) { 1876 if (out_format) {
1591 show_pax = show_phdr = show_textrel = show_rpath = \ 1877 show_pax = show_phdr = show_textrel = show_rpath = \
1592 show_needed = show_interp = show_bind = show_soname = \ 1878 show_needed = show_interp = show_bind = show_soname = \
1593 show_textrels = 0; 1879 show_textrels = show_perms = show_endian = show_size = \
1880 show_osabi = show_eabi = 0;
1594 for (i = 0; out_format[i]; ++i) { 1881 for (i = 0; out_format[i]; ++i) {
1595 if (!IS_MODIFIER(out_format[i])) continue; 1882 if (!IS_MODIFIER(out_format[i])) continue;
1596 1883
1597 switch (out_format[++i]) { 1884 switch (out_format[++i]) {
1885 case '+': break;
1598 case '%': break; 1886 case '%': break;
1599 case '#': break; 1887 case '#': break;
1600 case 'F': break; 1888 case 'F': break;
1601 case 'p': break; 1889 case 'p': break;
1602 case 'f': break; 1890 case 'f': break;
1603 case 'k': break; 1891 case 'k': break;
1604 case 's': break; 1892 case 's': break;
1605 case 'N': break; 1893 case 'N': break;
1606 case 'o': break; 1894 case 'o': break;
1895 case 'a': break;
1896 case 'M': break;
1897 case 'Z': show_size = 1; break;
1898 case 'D': show_endian = 1; break;
1899 case 'I': show_osabi = 1; break;
1900 case 'Y': show_eabi = 1; break;
1901 case 'O': show_perms = 1; break;
1607 case 'x': show_pax = 1; break; 1902 case 'x': show_pax = 1; break;
1608 case 'e': show_phdr = 1; break; 1903 case 'e': show_phdr = 1; break;
1609 case 't': show_textrel = 1; break; 1904 case 't': show_textrel = 1; break;
1610 case 'r': show_rpath = 1; break; 1905 case 'r': show_rpath = 1; break;
1611 case 'n': show_needed = 1; break; 1906 case 'n': show_needed = 1; break;
1612 case 'i': show_interp = 1; break; 1907 case 'i': show_interp = 1; break;
1613 case 'b': show_bind = 1; break; 1908 case 'b': show_bind = 1; break;
1614 case 'S': show_soname = 1; break; 1909 case 'S': show_soname = 1; break;
1615 case 'T': show_textrels = 1; break; 1910 case 'T': show_textrels = 1; break;
1616 default: 1911 default:
1617 err("Invalid format specifier '%c' (byte %i)", 1912 err("Invalid format specifier '%c' (byte %i)",
1618 out_format[i], i+1); 1913 out_format[i], i+1);
1619 } 1914 }
1620 } 1915 }
1621 1916
1622 /* construct our default format */ 1917 /* construct our default format */
1623 } else { 1918 } else {
1624 size_t fmt_len = 30; 1919 size_t fmt_len = 30;
1625 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1920 out_format = xmalloc(sizeof(char) * fmt_len);
1921 *out_format = '\0';
1626 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1922 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1627 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1923 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1924 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1925 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
1926 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1927 if (show_osabi) xstrcat(&out_format, "%I ", &fmt_len);
1928 if (show_eabi) xstrcat(&out_format, "%Y ", &fmt_len);
1628 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1929 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1629 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1930 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1630 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1931 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1631 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1932 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1632 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1933 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1640 } 1941 }
1641 if (be_verbose > 2) printf("Format: %s\n", out_format); 1942 if (be_verbose > 2) printf("Format: %s\n", out_format);
1642 1943
1643 /* now lets actually do the scanning */ 1944 /* now lets actually do the scanning */
1644 if (scan_ldpath || use_ldcache) 1945 if (scan_ldpath || use_ldcache)
1645 load_ld_so_conf(0, "/etc/ld.so.conf"); 1946 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1646 if (scan_ldpath) scanelf_ldpath(); 1947 if (scan_ldpath) scanelf_ldpath();
1647 if (scan_envpath) scanelf_envpath(); 1948 if (scan_envpath) scanelf_envpath();
1949 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1950 from_file = "-";
1648 if (from_file) { 1951 if (from_file) {
1649 scanelf_from_file(from_file); 1952 scanelf_from_file(from_file);
1650 from_file = *argv; 1953 from_file = *argv;
1651 } 1954 }
1652 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1955 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1653 err("Nothing to scan !?"); 1956 err("Nothing to scan !?");
1654 while (optind < argc) { 1957 while (optind < argc) {
1655 search_path = argv[optind++]; 1958 search_path = argv[optind++];
1656 scanelf_dir(search_path); 1959 ret = scanelf_dir(search_path);
1657 } 1960 }
1658 1961
1659 /* clean up */ 1962 /* clean up */
1660 if (versioned_symname) free(versioned_symname);
1661 for (i = 0; ldpaths[i]; ++i) 1963 for (i = 0; ldpaths[i]; ++i)
1662 free(ldpaths[i]); 1964 free(ldpaths[i]);
1663 1965
1664 if (ldcache != 0) 1966 if (ldcache != 0)
1665 munmap(ldcache, ldcache_size); 1967 munmap(ldcache, ldcache_size);
1666}
1667
1668
1669
1670/* utility funcs */
1671static char *xstrdup(const char *s)
1672{
1673 char *ret = strdup(s);
1674 if (!ret) err("Could not strdup(): %s", strerror(errno));
1675 return ret; 1968 return ret;
1676} 1969}
1677static void *xmalloc(size_t size)
1678{
1679 void *ret = malloc(size);
1680 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1681 return ret;
1682}
1683static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1684{
1685 size_t new_len;
1686 1970
1687 new_len = strlen(*dst) + strlen(src); 1971static char **get_split_env(const char *envvar)
1688 if (*curr_len <= new_len) {
1689 *curr_len = new_len + (*curr_len / 2);
1690 *dst = realloc(*dst, *curr_len);
1691 if (!*dst)
1692 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1693 }
1694
1695 if (n)
1696 strncat(*dst, src, n);
1697 else
1698 strcat(*dst, src);
1699}
1700static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1701{ 1972{
1702 static char my_app[2]; 1973 const char *delims = " \t\n";
1703 my_app[0] = append; 1974 char **envvals = NULL;
1704 my_app[1] = '\0'; 1975 char *env, *s;
1705 xstrcat(dst, my_app, curr_len); 1976 int nentry;
1706}
1707 1977
1978 if ((env = getenv(envvar)) == NULL)
1979 return NULL;
1708 1980
1981 env = xstrdup(env);
1982 if (env == NULL)
1983 return NULL;
1984
1985 s = strtok(env, delims);
1986 if (s == NULL) {
1987 free(env);
1988 return NULL;
1989 }
1990
1991 nentry = 0;
1992 while (s != NULL) {
1993 ++nentry;
1994 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1995 envvals[nentry-1] = s;
1996 s = strtok(NULL, delims);
1997 }
1998 envvals[nentry] = NULL;
1999
2000 /* don't want to free(env) as it contains the memory that backs
2001 * the envvals array of strings */
2002 return envvals;
2003}
2004
2005static void parseenv(void)
2006{
2007 qa_textrels = get_split_env("QA_TEXTRELS");
2008 qa_execstack = get_split_env("QA_EXECSTACK");
2009 qa_wx_load = get_split_env("QA_WX_LOAD");
2010}
2011
2012#ifdef __PAX_UTILS_CLEANUP
2013static void cleanup(void)
2014{
2015 free(out_format);
2016 free(qa_textrels);
2017 free(qa_execstack);
2018 free(qa_wx_load);
2019}
2020#endif
1709 2021
1710int main(int argc, char *argv[]) 2022int main(int argc, char *argv[])
1711{ 2023{
2024 int ret;
1712 if (argc < 2) 2025 if (argc < 2)
1713 usage(EXIT_FAILURE); 2026 usage(EXIT_FAILURE);
2027 parseenv();
1714 parseargs(argc, argv); 2028 ret = parseargs(argc, argv);
1715 fclose(stdout); 2029 fclose(stdout);
1716#ifdef __BOUNDS_CHECKING_ON 2030#ifdef __PAX_UTILS_CLEANUP
1717 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 2031 cleanup();
2032 warn("The calls to add/delete heap should be off:\n"
2033 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
2034 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1718#endif 2035#endif
1719 return EXIT_SUCCESS; 2036 return ret;
1720} 2037}
2038
2039/* Match filename against entries in matchlist, return TRUE
2040 * if the file is listed */
2041static int file_matches_list(const char *filename, char **matchlist)
2042{
2043 char **file;
2044 char *match;
2045 char buf[__PAX_UTILS_PATH_MAX];
2046
2047 if (matchlist == NULL)
2048 return 0;
2049
2050 for (file = matchlist; *file != NULL; file++) {
2051 if (search_path) {
2052 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2053 match = buf;
2054 } else {
2055 match = *file;
2056 }
2057 if (fnmatch(match, filename, 0) == 0)
2058 return 1;
2059 }
2060 return 0;
2061}

Legend:
Removed from v.1.127  
changed lines
  Added in v.1.203

  ViewVC Help
Powered by ViewVC 1.1.20