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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.190 - (show annotations) (download) (as text)
Sat Apr 19 22:31:49 2008 UTC (6 years, 8 months ago) by solar
Branch: MAIN
Changes since 1.189: +14 -6 lines
File MIME type: text/x-csrc
- add -Z/--size option

1 /*
2 * Copyright 2003-2007 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.189 2008/01/17 04:37:19 solar Exp $
5 *
6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 static const char *rcsid = "$Id: scanelf.c,v 1.189 2008/01/17 04:37:19 solar Exp $";
11 const char * const argv0 = "scanelf";
12
13 #include "paxinc.h"
14
15 #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16
17 /* prototypes */
18 static int file_matches_list(const char *filename, char **matchlist);
19 static int scanelf_elfobj(elfobj *elf);
20 static int scanelf_elf(const char *filename, int fd, size_t len);
21 static int scanelf_archive(const char *filename, int fd, size_t len);
22 static int scanelf_file(const char *filename, const struct stat *st_cache);
23 static int scanelf_dir(const char *path);
24 static void scanelf_ldpath(void);
25 static void scanelf_envpath(void);
26 static void usage(int status);
27 static char **get_split_env(const char *envvar);
28 static void parseenv(void);
29 static int parseargs(int argc, char *argv[]);
30 static int rematch(const char *regex, const char *match, int cflags);
31
32 /* variables to control behavior */
33 static char match_etypes[126] = "";
34 static char *ldpaths[256];
35 static char scan_ldpath = 0;
36 static char scan_envpath = 0;
37 static char scan_symlink = 1;
38 static char scan_archives = 0;
39 static char dir_recurse = 0;
40 static char dir_crossmount = 1;
41 static char show_pax = 0;
42 static char show_perms = 0;
43 static char show_size = 0;
44 static char show_phdr = 0;
45 static char show_textrel = 0;
46 static char show_rpath = 0;
47 static char show_needed = 0;
48 static char show_interp = 0;
49 static char show_bind = 0;
50 static char show_soname = 0;
51 static char show_textrels = 0;
52 static char show_banner = 1;
53 static char show_endian = 0;
54 static char be_quiet = 0;
55 static char be_verbose = 0;
56 static char be_wewy_wewy_quiet = 0;
57 static char be_semi_verbose = 0;
58 static char *find_sym = NULL, *versioned_symname = NULL;
59 static char *find_lib = NULL;
60 static char *find_section = NULL;
61 static char *out_format = NULL;
62 static char *search_path = NULL;
63 static char fix_elf = 0;
64 static char g_match = 0;
65 static char use_ldcache = 0;
66
67 static char **qa_textrels = NULL;
68 static char **qa_execstack = NULL;
69 static char **qa_wx_load = NULL;
70
71 int match_bits = 0;
72 unsigned int match_perms = 0;
73 caddr_t ldcache = 0;
74 size_t ldcache_size = 0;
75 unsigned long setpax = 0UL;
76
77 int has_objdump = 0;
78
79 static char *getstr_perms(const char *fname);
80 static char *getstr_perms(const char *fname)
81 {
82 struct stat st;
83 static char buf[8];
84
85 if ((stat(fname, &st)) == (-1))
86 return (char *) "";
87
88 snprintf(buf, sizeof(buf), "%o", st.st_mode);
89
90 return (char *) buf + 2;
91 }
92
93 /* find the path to a file by name */
94 static char *which(const char *fname)
95 {
96 static char fullpath[BUFSIZ];
97 char *path, *p;
98
99 path = getenv("PATH");
100 if (!path)
101 return NULL;
102
103 path = xstrdup(path);
104 while ((p = strrchr(path, ':')) != NULL) {
105 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
106 *p = 0;
107 if (access(fullpath, R_OK) != (-1)) {
108 free(path);
109 return (char *) fullpath;
110 }
111 }
112 free(path);
113 return NULL;
114 }
115
116 /* 1 on failure. 0 otherwise */
117 static int rematch(const char *regex, const char *match, int cflags)
118 {
119 regex_t preg;
120 int ret;
121
122 if ((match == NULL) || (regex == NULL))
123 return EXIT_FAILURE;
124
125 if ((ret = regcomp(&preg, regex, cflags))) {
126 char err[256];
127
128 if (regerror(ret, &preg, err, sizeof(err)))
129 fprintf(stderr, "regcomp failed: %s", err);
130 else
131 fprintf(stderr, "regcomp failed");
132
133 return EXIT_FAILURE;
134 }
135 ret = regexec(&preg, match, 0, NULL, 0);
136 regfree(&preg);
137
138 return ret;
139 }
140
141 /* sub-funcs for scanelf_file() */
142 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
143 {
144 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
145 #define GET_SYMTABS(B) \
146 if (elf->elf_class == ELFCLASS ## B) { \
147 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
148 /* debug sections */ \
149 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
150 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
151 /* runtime sections */ \
152 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
153 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
154 if (symtab && dynsym) { \
155 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
156 } else { \
157 *sym = (void*)(symtab ? symtab : dynsym); \
158 } \
159 if (strtab && dynstr) { \
160 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
161 } else { \
162 *tab = (void*)(strtab ? strtab : dynstr); \
163 } \
164 }
165 GET_SYMTABS(32)
166 GET_SYMTABS(64)
167 }
168
169 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
170 {
171 static char ret[7];
172 unsigned long i, shown;
173
174 if (!show_pax) return NULL;
175
176 shown = 0;
177 memset(&ret, 0, sizeof(ret));
178
179 if (elf->phdr) {
180 #define SHOW_PAX(B) \
181 if (elf->elf_class == ELFCLASS ## B) { \
182 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
183 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
184 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
185 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
186 continue; \
187 if (fix_elf && setpax) { \
188 /* set the paxctl flags */ \
189 ESET(phdr[i].p_flags, setpax); \
190 } \
191 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
192 continue; \
193 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
194 *found_pax = 1; \
195 ++shown; \
196 break; \
197 } \
198 }
199 SHOW_PAX(32)
200 SHOW_PAX(64)
201 }
202
203 if (fix_elf && setpax) {
204 /* set the chpax settings */
205 if (elf->elf_class == ELFCLASS32) {
206 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
207 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
208 } else {
209 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
210 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
211 }
212 }
213
214 /* fall back to EI_PAX if no PT_PAX was found */
215 if (!*ret) {
216 static char *paxflags;
217 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
218 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
219 *found_pax = 1;
220 return (be_wewy_wewy_quiet ? NULL : paxflags);
221 }
222 strncpy(ret, paxflags, sizeof(ret));
223 }
224
225 if (be_wewy_wewy_quiet || (be_quiet && !shown))
226 return NULL;
227 else
228 return ret;
229 }
230
231 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
232 {
233 static char ret[12];
234 char *found;
235 unsigned long i, shown, multi_stack, multi_relro, multi_load;
236 int max_pt_load;
237
238 if (!show_phdr) return NULL;
239
240 memcpy(ret, "--- --- ---\0", 12);
241
242 shown = 0;
243 multi_stack = multi_relro = multi_load = 0;
244 max_pt_load = elf_max_pt_load(elf);
245
246 #define NOTE_GNU_STACK ".note.GNU-stack"
247 #define SHOW_PHDR(B) \
248 if (elf->elf_class == ELFCLASS ## B) { \
249 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
250 Elf ## B ## _Off offset; \
251 uint32_t flags, check_flags; \
252 if (elf->phdr != NULL) { \
253 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
254 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
255 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
256 if (multi_stack++) \
257 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
258 if (file_matches_list(elf->filename, qa_execstack)) \
259 continue; \
260 found = found_phdr; \
261 offset = 0; \
262 check_flags = PF_X; \
263 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
264 if (multi_relro++) \
265 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
266 found = found_relro; \
267 offset = 4; \
268 check_flags = PF_X; \
269 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
270 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
271 if (multi_load++ > max_pt_load) \
272 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
273 if (file_matches_list(elf->filename, qa_wx_load)) \
274 continue; \
275 found = found_load; \
276 offset = 8; \
277 check_flags = PF_W|PF_X; \
278 } else \
279 continue; \
280 flags = EGET(phdr[i].p_flags); \
281 if (be_quiet && ((flags & check_flags) != check_flags)) \
282 continue; \
283 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
284 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
285 ret[3] = ret[7] = '!'; \
286 flags = EGET(phdr[i].p_flags); \
287 } \
288 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
289 *found = 1; \
290 ++shown; \
291 } \
292 } else if (elf->shdr != NULL) { \
293 /* no program headers which means this is prob an object file */ \
294 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
295 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
296 char *str; \
297 if ((void*)strtbl > (void*)elf->data_end) \
298 goto skip_this_shdr##B; \
299 check_flags = SHF_WRITE|SHF_EXECINSTR; \
300 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
301 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
302 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
303 str = elf->data + offset; \
304 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
305 if (!strcmp(str, NOTE_GNU_STACK)) { \
306 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
307 flags = EGET(shdr[i].sh_flags); \
308 if (be_quiet && ((flags & check_flags) != check_flags)) \
309 continue; \
310 ++*found_phdr; \
311 shown = 1; \
312 if (flags & SHF_WRITE) ret[0] = 'W'; \
313 if (flags & SHF_ALLOC) ret[1] = 'A'; \
314 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
315 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
316 break; \
317 } \
318 } \
319 skip_this_shdr##B: \
320 if (!multi_stack) { \
321 if (file_matches_list(elf->filename, qa_execstack)) \
322 return NULL; \
323 *found_phdr = 1; \
324 shown = 1; \
325 memcpy(ret, "!WX", 3); \
326 } \
327 } \
328 }
329 SHOW_PHDR(32)
330 SHOW_PHDR(64)
331
332 if (be_wewy_wewy_quiet || (be_quiet && !shown))
333 return NULL;
334 else
335 return ret;
336 }
337
338 /*
339 * See if this ELF contains a DT_TEXTREL tag in any of its
340 * PT_DYNAMIC sections.
341 */
342 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
343 {
344 static const char *ret = "TEXTREL";
345 unsigned long i;
346
347 if (!show_textrel && !show_textrels) return NULL;
348
349 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
350
351 if (elf->phdr) {
352 #define SHOW_TEXTREL(B) \
353 if (elf->elf_class == ELFCLASS ## B) { \
354 Elf ## B ## _Dyn *dyn; \
355 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
356 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
357 Elf ## B ## _Off offset; \
358 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
359 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
360 offset = EGET(phdr[i].p_offset); \
361 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
362 dyn = DYN ## B (elf->data + offset); \
363 while (EGET(dyn->d_tag) != DT_NULL) { \
364 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
365 *found_textrel = 1; \
366 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
367 return (be_wewy_wewy_quiet ? NULL : ret); \
368 } \
369 ++dyn; \
370 } \
371 } }
372 SHOW_TEXTREL(32)
373 SHOW_TEXTREL(64)
374 }
375
376 if (be_quiet || be_wewy_wewy_quiet)
377 return NULL;
378 else
379 return " - ";
380 }
381
382 /*
383 * Scan the .text section to see if there are any relocations in it.
384 * Should rewrite this to check PT_LOAD sections that are marked
385 * Executable rather than the section named '.text'.
386 */
387 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
388 {
389 unsigned long s, r, rmax;
390 void *symtab_void, *strtab_void, *text_void;
391
392 if (!show_textrels) return NULL;
393
394 /* don't search for TEXTREL's if the ELF doesn't have any */
395 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
396 if (!*found_textrel) return NULL;
397
398 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
399 text_void = elf_findsecbyname(elf, ".text");
400
401 if (symtab_void && strtab_void && text_void && elf->shdr) {
402 #define SHOW_TEXTRELS(B) \
403 if (elf->elf_class == ELFCLASS ## B) { \
404 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
405 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
406 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
407 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
408 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
409 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
410 uint ## B ## _t memsz = EGET(text->sh_size); \
411 Elf ## B ## _Rel *rel; \
412 Elf ## B ## _Rela *rela; \
413 /* search the section headers for relocations */ \
414 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
415 uint32_t sh_type = EGET(shdr[s].sh_type); \
416 if (sh_type == SHT_REL) { \
417 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
418 rela = NULL; \
419 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
420 } else if (sh_type == SHT_RELA) { \
421 rel = NULL; \
422 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
423 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
424 } else \
425 continue; \
426 /* now see if any of the relocs are in the .text */ \
427 for (r = 0; r < rmax; ++r) { \
428 unsigned long sym_max; \
429 Elf ## B ## _Addr offset_tmp; \
430 Elf ## B ## _Sym *func; \
431 Elf ## B ## _Sym *sym; \
432 Elf ## B ## _Addr r_offset; \
433 uint ## B ## _t r_info; \
434 if (sh_type == SHT_REL) { \
435 r_offset = EGET(rel[r].r_offset); \
436 r_info = EGET(rel[r].r_info); \
437 } else { \
438 r_offset = EGET(rela[r].r_offset); \
439 r_info = EGET(rela[r].r_info); \
440 } \
441 /* make sure this relocation is inside of the .text */ \
442 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
443 if (be_verbose <= 2) continue; \
444 } else \
445 *found_textrels = 1; \
446 /* locate this relocation symbol name */ \
447 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
448 if ((void*)sym > (void*)elf->data_end) { \
449 warn("%s: corrupt ELF symbol", elf->filename); \
450 continue; \
451 } \
452 sym_max = ELF ## B ## _R_SYM(r_info); \
453 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
454 sym += sym_max; \
455 else \
456 sym = NULL; \
457 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
458 /* show the raw details about this reloc */ \
459 printf(" %s: ", elf->base_filename); \
460 if (sym && sym->st_name) \
461 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
462 else \
463 printf("(memory/data?)"); \
464 printf(" [0x%lX]", (unsigned long)r_offset); \
465 /* now try to find the closest symbol that this rel is probably in */ \
466 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
467 func = NULL; \
468 offset_tmp = 0; \
469 while (sym_max--) { \
470 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
471 func = sym; \
472 offset_tmp = EGET(sym->st_value); \
473 } \
474 ++sym; \
475 } \
476 printf(" in "); \
477 if (func && func->st_name) { \
478 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
479 if (r_offset > EGET(func->st_size)) \
480 printf("(optimized out: previous %s)", func_name); \
481 else \
482 printf("%s", func_name); \
483 } else \
484 printf("(optimized out)"); \
485 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
486 if (be_verbose && has_objdump) { \
487 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
488 char *sysbuf; \
489 size_t syslen; \
490 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"; \
491 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
492 sysbuf = xmalloc(syslen); \
493 if (end_addr < r_offset) \
494 /* not uncommon when things are optimized out */ \
495 end_addr = r_offset + 0x100; \
496 snprintf(sysbuf, syslen, sysfmt, \
497 (unsigned long)offset_tmp, \
498 (unsigned long)end_addr, \
499 elf->filename, \
500 (unsigned long)r_offset); \
501 fflush(stdout); \
502 system(sysbuf); \
503 fflush(stdout); \
504 free(sysbuf); \
505 } \
506 } \
507 } }
508 SHOW_TEXTRELS(32)
509 SHOW_TEXTRELS(64)
510 }
511 if (!*found_textrels)
512 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
513
514 return NULL;
515 }
516
517 static void rpath_security_checks(elfobj *, char *, const char *);
518 static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
519 {
520 struct stat st;
521 switch (*item) {
522 case '/': break;
523 case '.':
524 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
525 break;
526 case ':':
527 case '\0':
528 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
529 break;
530 case '$':
531 if (fstat(elf->fd, &st) != -1)
532 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
533 warnf("Security problem with %s='%s' in %s with mode set of %o",
534 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
535 break;
536 default:
537 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
538 break;
539 }
540 }
541 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
542 {
543 unsigned long i, s;
544 char *rpath, *runpath, **r;
545 void *strtbl_void;
546
547 if (!show_rpath) return;
548
549 strtbl_void = elf_findsecbyname(elf, ".dynstr");
550 rpath = runpath = NULL;
551
552 if (elf->phdr && strtbl_void) {
553 #define SHOW_RPATH(B) \
554 if (elf->elf_class == ELFCLASS ## B) { \
555 Elf ## B ## _Dyn *dyn; \
556 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
557 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
558 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
559 Elf ## B ## _Off offset; \
560 Elf ## B ## _Xword word; \
561 /* Scan all the program headers */ \
562 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
563 /* Just scan dynamic headers */ \
564 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
565 offset = EGET(phdr[i].p_offset); \
566 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
567 /* Just scan dynamic RPATH/RUNPATH headers */ \
568 dyn = DYN ## B (elf->data + offset); \
569 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
570 if (word == DT_RPATH) { \
571 r = &rpath; \
572 } else if (word == DT_RUNPATH) { \
573 r = &runpath; \
574 } else { \
575 ++dyn; \
576 continue; \
577 } \
578 /* Verify the memory is somewhat sane */ \
579 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
580 if (offset < (Elf ## B ## _Off)elf->len) { \
581 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
582 *r = (char*)(elf->data + offset); \
583 /* cache the length in case we need to nuke this section later on */ \
584 if (fix_elf) \
585 offset = strlen(*r); \
586 /* If quiet, don't output paths in ld.so.conf */ \
587 if (be_quiet) { \
588 size_t len; \
589 char *start, *end; \
590 /* note that we only 'chop' off leading known paths. */ \
591 /* since *r is read-only memory, we can only move the ptr forward. */ \
592 start = *r; \
593 /* scan each path in : delimited list */ \
594 while (start) { \
595 rpath_security_checks(elf, start, get_elfdtype(word)); \
596 end = strchr(start, ':'); \
597 len = (end ? abs(end - start) : strlen(start)); \
598 if (use_ldcache) \
599 for (s = 0; ldpaths[s]; ++s) \
600 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
601 *r = end; \
602 /* corner case ... if RPATH reads "/usr/lib:", we want \
603 * to show ':' rather than '' */ \
604 if (end && end[1] != '\0') \
605 (*r)++; \
606 break; \
607 } \
608 if (!*r || !end) \
609 break; \
610 else \
611 start = start + len + 1; \
612 } \
613 } \
614 if (*r) { \
615 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
616 /* just nuke it */ \
617 nuke_it##B: \
618 memset(*r, 0x00, offset); \
619 *r = NULL; \
620 ESET(dyn->d_tag, DT_DEBUG); \
621 ESET(dyn->d_un.d_ptr, 0); \
622 } else if (fix_elf) { \
623 /* try to clean "bad" paths */ \
624 size_t len, tmpdir_len; \
625 char *start, *end; \
626 const char *tmpdir; \
627 start = *r; \
628 tmpdir = (getenv("TMPDIR") ? : "."); \
629 tmpdir_len = strlen(tmpdir); \
630 while (1) { \
631 end = strchr(start, ':'); \
632 if (start == end) { \
633 eat_this_path##B: \
634 len = strlen(end); \
635 memmove(start, end+1, len); \
636 start[len-1] = '\0'; \
637 end = start - 1; \
638 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
639 if (!end) { \
640 if (start == *r) \
641 goto nuke_it##B; \
642 *--start = '\0'; \
643 } else \
644 goto eat_this_path##B; \
645 } \
646 if (!end) \
647 break; \
648 start = end + 1; \
649 } \
650 if (**r == '\0') \
651 goto nuke_it##B; \
652 } \
653 if (*r) \
654 *found_rpath = 1; \
655 } \
656 } \
657 ++dyn; \
658 } \
659 } }
660 SHOW_RPATH(32)
661 SHOW_RPATH(64)
662 }
663
664 if (be_wewy_wewy_quiet) return;
665
666 if (rpath && runpath) {
667 if (!strcmp(rpath, runpath)) {
668 xstrcat(ret, runpath, ret_len);
669 } else {
670 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
671 xchrcat(ret, '{', ret_len);
672 xstrcat(ret, rpath, ret_len);
673 xchrcat(ret, ',', ret_len);
674 xstrcat(ret, runpath, ret_len);
675 xchrcat(ret, '}', ret_len);
676 }
677 } else if (rpath || runpath)
678 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
679 else if (!be_quiet)
680 xstrcat(ret, " - ", ret_len);
681 }
682
683 #define LDSO_CACHE_MAGIC "ld.so-"
684 #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
685 #define LDSO_CACHE_VER "1.7.0"
686 #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
687 #define FLAG_ANY -1
688 #define FLAG_TYPE_MASK 0x00ff
689 #define FLAG_LIBC4 0x0000
690 #define FLAG_ELF 0x0001
691 #define FLAG_ELF_LIBC5 0x0002
692 #define FLAG_ELF_LIBC6 0x0003
693 #define FLAG_REQUIRED_MASK 0xff00
694 #define FLAG_SPARC_LIB64 0x0100
695 #define FLAG_IA64_LIB64 0x0200
696 #define FLAG_X8664_LIB64 0x0300
697 #define FLAG_S390_LIB64 0x0400
698 #define FLAG_POWERPC_LIB64 0x0500
699 #define FLAG_MIPS64_LIBN32 0x0600
700 #define FLAG_MIPS64_LIBN64 0x0700
701
702 static char *lookup_cache_lib(elfobj *, char *);
703
704 #if defined(__GLIBC__) || defined(__UCLIBC__)
705
706 static char *lookup_cache_lib(elfobj *elf, char *fname)
707 {
708 int fd = 0;
709 char *strs;
710 static char buf[__PAX_UTILS_PATH_MAX] = "";
711 const char *cachefile = "/etc/ld.so.cache";
712 struct stat st;
713
714 typedef struct {
715 char magic[LDSO_CACHE_MAGIC_LEN];
716 char version[LDSO_CACHE_VER_LEN];
717 int nlibs;
718 } header_t;
719 header_t *header;
720
721 typedef struct {
722 int flags;
723 int sooffset;
724 int liboffset;
725 } libentry_t;
726 libentry_t *libent;
727
728 if (fname == NULL)
729 return NULL;
730
731 if (ldcache == 0) {
732 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
733 return NULL;
734
735 /* cache these values so we only map/unmap the cache file once */
736 ldcache_size = st.st_size;
737 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
738
739 close(fd);
740
741 if (ldcache == (caddr_t)-1) {
742 ldcache = 0;
743 return NULL;
744 }
745
746 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
747 return NULL;
748 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
749 return NULL;
750 }
751
752 header = (header_t *) ldcache;
753 libent = (libentry_t *) (ldcache + sizeof(header_t));
754 strs = (char *) &libent[header->nlibs];
755
756 for (fd = 0; fd < header->nlibs; fd++) {
757 /* this should be more fine grained, but for now we assume that
758 * diff arches will not be cached together. and we ignore the
759 * the different multilib mips cases. */
760 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
761 continue;
762 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
763 continue;
764
765 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
766 continue;
767 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
768 }
769 return buf;
770 }
771 #elif defined(__NetBSD__)
772 static char *lookup_cache_lib(elfobj *elf, char *fname)
773 {
774 static char buf[__PAX_UTILS_PATH_MAX] = "";
775 static struct stat st;
776
777 char **ldpath;
778 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
779 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
780 continue; /* if the pathname is too long, or something went wrong, ignore */
781
782 if (stat(buf, &st) != 0)
783 continue; /* if the lib doesn't exist in *ldpath, look further */
784
785 /* NetBSD doesn't actually do sanity checks, it just loads the file
786 * and if that doesn't work, continues looking in other directories.
787 * This cannot easily be safely emulated, unfortunately. For now,
788 * just assume that if it exists, it's a valid library. */
789
790 return buf;
791 }
792
793 /* not found in any path */
794 return NULL;
795 }
796 #else
797 #warning Cache support not implemented for your target
798 static char *lookup_cache_lib(elfobj *elf, char *fname)
799 {
800 return NULL;
801 }
802 #endif
803
804 static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
805 {
806 unsigned long i;
807 char *needed;
808 void *strtbl_void;
809 char *p;
810
811 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
812
813 strtbl_void = elf_findsecbyname(elf, ".dynstr");
814
815 if (elf->phdr && strtbl_void) {
816 #define SHOW_NEEDED(B) \
817 if (elf->elf_class == ELFCLASS ## B) { \
818 Elf ## B ## _Dyn *dyn; \
819 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
820 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
821 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
822 Elf ## B ## _Off offset; \
823 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
824 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
825 offset = EGET(phdr[i].p_offset); \
826 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
827 dyn = DYN ## B (elf->data + offset); \
828 while (EGET(dyn->d_tag) != DT_NULL) { \
829 if (EGET(dyn->d_tag) == DT_NEEDED) { \
830 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
831 if (offset >= (Elf ## B ## _Off)elf->len) { \
832 ++dyn; \
833 continue; \
834 } \
835 needed = (char*)(elf->data + offset); \
836 if (op == 0) { \
837 if (!be_wewy_wewy_quiet) { \
838 if (*found_needed) xchrcat(ret, ',', ret_len); \
839 if (use_ldcache) \
840 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
841 needed = p; \
842 xstrcat(ret, needed, ret_len); \
843 } \
844 *found_needed = 1; \
845 } else { \
846 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
847 *found_lib = 1; \
848 return (be_wewy_wewy_quiet ? NULL : needed); \
849 } \
850 } \
851 } \
852 ++dyn; \
853 } \
854 } }
855 SHOW_NEEDED(32)
856 SHOW_NEEDED(64)
857 if (op == 0 && !*found_needed && be_verbose)
858 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
859 }
860
861 return NULL;
862 }
863 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
864 {
865 void *strtbl_void;
866
867 if (!show_interp) return NULL;
868
869 strtbl_void = elf_findsecbyname(elf, ".interp");
870
871 if (strtbl_void) {
872 #define SHOW_INTERP(B) \
873 if (elf->elf_class == ELFCLASS ## B) { \
874 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
875 *found_interp = 1; \
876 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
877 }
878 SHOW_INTERP(32)
879 SHOW_INTERP(64)
880 }
881 return NULL;
882 }
883 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
884 {
885 unsigned long i;
886 struct stat s;
887 char dynamic = 0;
888
889 if (!show_bind) return NULL;
890 if (!elf->phdr) return NULL;
891
892 #define SHOW_BIND(B) \
893 if (elf->elf_class == ELFCLASS ## B) { \
894 Elf ## B ## _Dyn *dyn; \
895 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
896 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
897 Elf ## B ## _Off offset; \
898 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
899 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
900 dynamic = 1; \
901 offset = EGET(phdr[i].p_offset); \
902 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
903 dyn = DYN ## B (elf->data + offset); \
904 while (EGET(dyn->d_tag) != DT_NULL) { \
905 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
906 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
907 { \
908 if (be_quiet) return NULL; \
909 *found_bind = 1; \
910 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
911 } \
912 ++dyn; \
913 } \
914 } \
915 }
916 SHOW_BIND(32)
917 SHOW_BIND(64)
918
919 if (be_wewy_wewy_quiet) return NULL;
920
921 /* don't output anything if quiet mode and the ELF is static or not setuid */
922 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
923 return NULL;
924 } else {
925 *found_bind = 1;
926 return (char *) (dynamic ? "LAZY" : "STATIC");
927 }
928 }
929 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
930 {
931 unsigned long i;
932 char *soname;
933 void *strtbl_void;
934
935 if (!show_soname) return NULL;
936
937 strtbl_void = elf_findsecbyname(elf, ".dynstr");
938
939 if (elf->phdr && strtbl_void) {
940 #define SHOW_SONAME(B) \
941 if (elf->elf_class == ELFCLASS ## B) { \
942 Elf ## B ## _Dyn *dyn; \
943 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
944 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
945 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
946 Elf ## B ## _Off offset; \
947 /* only look for soname in shared objects */ \
948 if (EGET(ehdr->e_type) != ET_DYN) \
949 return NULL; \
950 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
951 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
952 offset = EGET(phdr[i].p_offset); \
953 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
954 dyn = DYN ## B (elf->data + offset); \
955 while (EGET(dyn->d_tag) != DT_NULL) { \
956 if (EGET(dyn->d_tag) == DT_SONAME) { \
957 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
958 if (offset >= (Elf ## B ## _Off)elf->len) { \
959 ++dyn; \
960 continue; \
961 } \
962 soname = (char*)(elf->data + offset); \
963 *found_soname = 1; \
964 return (be_wewy_wewy_quiet ? NULL : soname); \
965 } \
966 ++dyn; \
967 } \
968 } }
969 SHOW_SONAME(32)
970 SHOW_SONAME(64)
971 }
972
973 return NULL;
974 }
975
976 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
977 {
978 unsigned long i;
979 char *ret;
980 void *symtab_void, *strtab_void;
981
982 if (!find_sym) return NULL;
983 ret = find_sym;
984
985 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
986
987 if (symtab_void && strtab_void) {
988 #define FIND_SYM(B) \
989 if (elf->elf_class == ELFCLASS ## B) { \
990 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
991 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
992 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
993 unsigned long cnt = EGET(symtab->sh_entsize); \
994 char *symname; \
995 if (cnt) \
996 cnt = EGET(symtab->sh_size) / cnt; \
997 for (i = 0; i < cnt; ++i) { \
998 if (sym->st_name) { \
999 /* make sure the symbol name is in acceptable memory range */ \
1000 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
1001 if ((void*)symname > (void*)elf->data_end) { \
1002 warnf("%s: corrupt ELF symbols", elf->filename); \
1003 ++sym; \
1004 continue; \
1005 } \
1006 /* debug display ... show all symbols and some extra info */ \
1007 if (g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
1008 printf("%s(%s) %5lX %15s %s %s\n", \
1009 ((*found_sym == 0) ? "\n\t" : "\t"), \
1010 elf->base_filename, \
1011 (unsigned long)sym->st_size, \
1012 get_elfstttype(sym->st_info), \
1013 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
1014 *found_sym = 1; \
1015 } else { \
1016 /* allow the user to specify a comma delimited list of symbols to search for */ \
1017 char *this_sym, *this_sym_ver, *next_sym; \
1018 this_sym = ret; \
1019 this_sym_ver = versioned_symname; \
1020 do { \
1021 next_sym = strchr(this_sym, ','); \
1022 if (next_sym == NULL) \
1023 next_sym = this_sym + strlen(this_sym); \
1024 /* do we want a defined symbol ? */ \
1025 if (*this_sym == '+') { \
1026 if (sym->st_shndx == SHN_UNDEF) \
1027 goto skip_this_sym##B; \
1028 ++this_sym; \
1029 ++this_sym_ver; \
1030 /* do we want an undefined symbol ? */ \
1031 } else if (*this_sym == '-') { \
1032 if (sym->st_shndx != SHN_UNDEF) \
1033 goto skip_this_sym##B; \
1034 ++this_sym; \
1035 ++this_sym_ver; \
1036 } \
1037 /* ok, lets compare the name now */ \
1038 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
1039 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
1040 if (be_semi_verbose) { \
1041 char buf[126]; \
1042 snprintf(buf, sizeof(buf), "%lX %s %s", \
1043 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1044 ret = buf; \
1045 } else \
1046 ret = this_sym; \
1047 (*found_sym)++; \
1048 goto break_out; \
1049 } \
1050 skip_this_sym##B: this_sym = next_sym + 1; \
1051 } while (*next_sym != '\0'); \
1052 } \
1053 } \
1054 ++sym; \
1055 } }
1056 FIND_SYM(32)
1057 FIND_SYM(64)
1058 }
1059
1060 break_out:
1061 if (be_wewy_wewy_quiet) return NULL;
1062
1063 if (*find_sym != '*' && *found_sym)
1064 return ret;
1065 if (be_quiet)
1066 return NULL;
1067 else
1068 return (char *)" - ";
1069 }
1070
1071 static char *scanelf_file_sections(elfobj *elf, char *found_section)
1072 {
1073 if (!find_section)
1074 return NULL;
1075
1076 #define FIND_SECTION(B) \
1077 if (elf->elf_class == ELFCLASS ## B) { \
1078 int invert; \
1079 Elf ## B ## _Shdr *section; \
1080 invert = (*find_section == '!' ? 1 : 0); \
1081 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1082 if ((section == NULL && invert) || (section != NULL && !invert)) \
1083 *found_section = 1; \
1084 }
1085 FIND_SECTION(32)
1086 FIND_SECTION(64)
1087
1088 if (be_wewy_wewy_quiet)
1089 return NULL;
1090
1091 if (*found_section)
1092 return find_section;
1093
1094 if (be_quiet)
1095 return NULL;
1096 else
1097 return (char *)" - ";
1098 }
1099
1100 /* scan an elf file and show all the fun stuff */
1101 #define prints(str) write(fileno(stdout), str, strlen(str))
1102 static int scanelf_elfobj(elfobj *elf)
1103 {
1104 unsigned long i;
1105 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1106 found_rpath, found_needed, found_interp, found_bind, found_soname,
1107 found_sym, found_lib, found_file, found_textrels, found_section;
1108 static char *out_buffer = NULL;
1109 static size_t out_len;
1110
1111 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1112 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1113 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1114
1115 if (be_verbose > 2)
1116 printf("%s: scanning file {%s,%s}\n", elf->filename,
1117 get_elfeitype(EI_CLASS, elf->elf_class),
1118 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1119 else if (be_verbose > 1)
1120 printf("%s: scanning file\n", elf->filename);
1121
1122 /* init output buffer */
1123 if (!out_buffer) {
1124 out_len = sizeof(char) * 80;
1125 out_buffer = xmalloc(out_len);
1126 }
1127 *out_buffer = '\0';
1128
1129 /* show the header */
1130 if (!be_quiet && show_banner) {
1131 for (i = 0; out_format[i]; ++i) {
1132 if (!IS_MODIFIER(out_format[i])) continue;
1133
1134 switch (out_format[++i]) {
1135 case '+': break;
1136 case '%': break;
1137 case '#': break;
1138 case 'F':
1139 case 'p':
1140 case 'f': prints("FILE "); found_file = 1; break;
1141 case 'o': prints(" TYPE "); break;
1142 case 'x': prints(" PAX "); break;
1143 case 'e': prints("STK/REL/PTL "); break;
1144 case 't': prints("TEXTREL "); break;
1145 case 'r': prints("RPATH "); break;
1146 case 'M': prints("CLASS "); break;
1147 case 'n': prints("NEEDED "); break;
1148 case 'i': prints("INTERP "); break;
1149 case 'b': prints("BIND "); break;
1150 case 'Z': prints("SIZE "); break;
1151 case 'S': prints("SONAME "); break;
1152 case 's': prints("SYM "); break;
1153 case 'N': prints("LIB "); break;
1154 case 'T': prints("TEXTRELS "); break;
1155 case 'k': prints("SECTION "); break;
1156 case 'a': prints("ARCH "); break;
1157 case 'O': prints("PERM "); break;
1158 case 'D': prints("ENDIAN "); break;
1159 default: warnf("'%c' has no title ?", out_format[i]);
1160 }
1161 }
1162 if (!found_file) prints("FILE ");
1163 prints("\n");
1164 found_file = 0;
1165 show_banner = 0;
1166 }
1167
1168 /* dump all the good stuff */
1169 for (i = 0; out_format[i]; ++i) {
1170 const char *out;
1171 const char *tmp;
1172 static char ubuf[sizeof(unsigned long)*2];
1173 if (!IS_MODIFIER(out_format[i])) {
1174 xchrcat(&out_buffer, out_format[i], &out_len);
1175 continue;
1176 }
1177
1178 out = NULL;
1179 be_wewy_wewy_quiet = (out_format[i] == '#');
1180 be_semi_verbose = (out_format[i] == '+');
1181 switch (out_format[++i]) {
1182 case '+':
1183 case '%':
1184 case '#':
1185 xchrcat(&out_buffer, out_format[i], &out_len); break;
1186 case 'F':
1187 found_file = 1;
1188 if (be_wewy_wewy_quiet) break;
1189 xstrcat(&out_buffer, elf->filename, &out_len);
1190 break;
1191 case 'p':
1192 found_file = 1;
1193 if (be_wewy_wewy_quiet) break;
1194 tmp = elf->filename;
1195 if (search_path) {
1196 ssize_t len_search = strlen(search_path);
1197 ssize_t len_file = strlen(elf->filename);
1198 if (!strncmp(elf->filename, search_path, len_search) && \
1199 len_file > len_search)
1200 tmp += len_search;
1201 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1202 }
1203 xstrcat(&out_buffer, tmp, &out_len);
1204 break;
1205 case 'f':
1206 found_file = 1;
1207 if (be_wewy_wewy_quiet) break;
1208 tmp = strrchr(elf->filename, '/');
1209 tmp = (tmp == NULL ? elf->filename : tmp+1);
1210 xstrcat(&out_buffer, tmp, &out_len);
1211 break;
1212 case 'o': out = get_elfetype(elf); break;
1213 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1214 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1215 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1216 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1217 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1218 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1219 case 'D': out = get_endian(elf); break;
1220 case 'O': out = getstr_perms(elf->filename); break;
1221 case 'n':
1222 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1223 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1224 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1225 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1226 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1227 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1228 case 'a': out = get_elfemtype(elf); break;
1229 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", elf->len); out = ubuf; break;;
1230 default: warnf("'%c' has no scan code?", out_format[i]);
1231 }
1232 if (out) {
1233 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1234 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1235 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1236 else
1237 xstrcat(&out_buffer, out, &out_len);
1238 }
1239 }
1240
1241 #define FOUND_SOMETHING() \
1242 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1243 found_rpath || found_needed || found_interp || found_bind || \
1244 found_soname || found_sym || found_lib || found_textrels || found_section )
1245
1246 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1247 xchrcat(&out_buffer, ' ', &out_len);
1248 xstrcat(&out_buffer, elf->filename, &out_len);
1249 }
1250 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1251 puts(out_buffer);
1252 fflush(stdout);
1253 }
1254
1255 return 0;
1256 }
1257
1258 /* scan a single elf */
1259 static int scanelf_elf(const char *filename, int fd, size_t len)
1260 {
1261 int ret = 1;
1262 elfobj *elf;
1263
1264 /* verify this is real ELF */
1265 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1266 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1267 return ret;
1268 }
1269 switch (match_bits) {
1270 case 32:
1271 if (elf->elf_class != ELFCLASS32)
1272 goto label_done;
1273 break;
1274 case 64:
1275 if (elf->elf_class != ELFCLASS64)
1276 goto label_done;
1277 break;
1278 default: break;
1279 }
1280 if (strlen(match_etypes)) {
1281 char sbuf[126];
1282 strncpy(sbuf, match_etypes, sizeof(sbuf));
1283 if (strchr(match_etypes, ',') != NULL) {
1284 char *p;
1285 while ((p = strrchr(sbuf, ',')) != NULL) {
1286 *p = 0;
1287 if (etype_lookup(p+1) == get_etype(elf))
1288 goto label_ret;
1289 }
1290 }
1291 if (etype_lookup(sbuf) != get_etype(elf))
1292 goto label_done;
1293 }
1294
1295 label_ret:
1296 ret = scanelf_elfobj(elf);
1297
1298 label_done:
1299 unreadelf(elf);
1300 return ret;
1301 }
1302
1303 /* scan an archive of elfs */
1304 static int scanelf_archive(const char *filename, int fd, size_t len)
1305 {
1306 archive_handle *ar;
1307 archive_member *m;
1308 char *ar_buffer;
1309 elfobj *elf;
1310
1311 ar = ar_open_fd(filename, fd);
1312 if (ar == NULL)
1313 return 1;
1314
1315 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1316 while ((m=ar_next(ar)) != NULL) {
1317 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1318 if (elf) {
1319 scanelf_elfobj(elf);
1320 unreadelf(elf);
1321 }
1322 }
1323 munmap(ar_buffer, len);
1324
1325 return 0;
1326 }
1327 /* scan a file which may be an elf or an archive or some other magical beast */
1328 static int scanelf_file(const char *filename, const struct stat *st_cache)
1329 {
1330 const struct stat *st = st_cache;
1331 struct stat symlink_st;
1332 int fd;
1333
1334 /* always handle regular files and handle symlinked files if no -y */
1335 if (S_ISLNK(st->st_mode)) {
1336 if (!scan_symlink) return 1;
1337 stat(filename, &symlink_st);
1338 st = &symlink_st;
1339 }
1340
1341 if (!S_ISREG(st->st_mode)) {
1342 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1343 return 1;
1344 }
1345
1346 if (match_perms) {
1347 if ((st->st_mode | match_perms) != st->st_mode)
1348 return 1;
1349 }
1350 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1351 return 1;
1352
1353 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1354 /* if it isn't an ELF, maybe it's an .a archive */
1355 scanelf_archive(filename, fd, st->st_size);
1356
1357 close(fd);
1358 return 0;
1359 }
1360
1361 /* scan a directory for ET_EXEC files and print when we find one */
1362 static int scanelf_dir(const char *path)
1363 {
1364 register DIR *dir;
1365 register struct dirent *dentry;
1366 struct stat st_top, st;
1367 char buf[__PAX_UTILS_PATH_MAX];
1368 size_t pathlen = 0, len = 0;
1369 int ret = 0;
1370
1371 /* make sure path exists */
1372 if (lstat(path, &st_top) == -1) {
1373 if (be_verbose > 2) printf("%s: does not exist\n", path);
1374 return 1;
1375 }
1376
1377 /* ok, if it isn't a directory, assume we can open it */
1378 if (!S_ISDIR(st_top.st_mode)) {
1379 return scanelf_file(path, &st_top);
1380 }
1381
1382 /* now scan the dir looking for fun stuff */
1383 if ((dir = opendir(path)) == NULL) {
1384 warnf("could not opendir %s: %s", path, strerror(errno));
1385 return 1;
1386 }
1387 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1388
1389 pathlen = strlen(path);
1390 while ((dentry = readdir(dir))) {
1391 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1392 continue;
1393 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1394 if (len >= sizeof(buf)) {
1395 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1396 (unsigned long)len, (unsigned long)sizeof(buf));
1397 continue;
1398 }
1399 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1400 if (lstat(buf, &st) != -1) {
1401 if (S_ISREG(st.st_mode))
1402 ret = scanelf_file(buf, &st);
1403 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1404 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1405 ret = scanelf_dir(buf);
1406 }
1407 }
1408 }
1409 closedir(dir);
1410 return ret;
1411 }
1412
1413 static int scanelf_from_file(const char *filename)
1414 {
1415 FILE *fp = NULL;
1416 char *p;
1417 char path[__PAX_UTILS_PATH_MAX];
1418 int ret = 0;
1419
1420 if (strcmp(filename, "-") == 0)
1421 fp = stdin;
1422 else if ((fp = fopen(filename, "r")) == NULL)
1423 return 1;
1424
1425 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1426 if ((p = strchr(path, '\n')) != NULL)
1427 *p = 0;
1428 search_path = path;
1429 ret = scanelf_dir(path);
1430 }
1431 if (fp != stdin)
1432 fclose(fp);
1433 return ret;
1434 }
1435
1436 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1437
1438 static int load_ld_cache_config(int i, const char *fname)
1439 {
1440 FILE *fp = NULL;
1441 char *p;
1442 char path[__PAX_UTILS_PATH_MAX];
1443
1444 if (i + 1 == ARRAY_SIZE(ldpaths))
1445 return i;
1446
1447 if ((fp = fopen(fname, "r")) == NULL)
1448 return i;
1449
1450 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1451 if ((p = strrchr(path, '\r')) != NULL)
1452 *p = 0;
1453 if ((p = strchr(path, '\n')) != NULL)
1454 *p = 0;
1455 #ifdef __linux__
1456 /* recursive includes of the same file will make this segfault. */
1457 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1458 glob64_t gl;
1459 size_t x;
1460 char gpath[__PAX_UTILS_PATH_MAX];
1461
1462 memset(gpath, 0, sizeof(gpath));
1463
1464 if (path[8] != '/')
1465 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1466 else
1467 strncpy(gpath, &path[8], sizeof(gpath));
1468
1469 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1470 for (x = 0; x < gl.gl_pathc; ++x) {
1471 /* try to avoid direct loops */
1472 if (strcmp(gl.gl_pathv[x], fname) == 0)
1473 continue;
1474 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1475 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1476 globfree64(&gl);
1477 return i;
1478 }
1479 }
1480 globfree64 (&gl);
1481 continue;
1482 }
1483 }
1484 #endif
1485 if (*path != '/')
1486 continue;
1487
1488 ldpaths[i++] = xstrdup(path);
1489
1490 if (i + 1 == ARRAY_SIZE(ldpaths))
1491 break;
1492 }
1493 ldpaths[i] = NULL;
1494
1495 fclose(fp);
1496 return i;
1497 }
1498
1499 #elif defined(__FreeBSD__) || (__DragonFly__)
1500
1501 static int load_ld_cache_config(int i, const char *fname)
1502 {
1503 FILE *fp = NULL;
1504 char *b = NULL, *p;
1505 struct elfhints_hdr hdr;
1506
1507 if (i + 1 == ARRAY_SIZE(ldpaths))
1508 return i;
1509
1510 if ((fp = fopen(fname, "r")) == NULL)
1511 return i;
1512
1513 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1514 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1515 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1516 {
1517 fclose(fp);
1518 return i;
1519 }
1520
1521 b = xmalloc(hdr.dirlistlen + 1);
1522 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1523 fclose(fp);
1524 free(b);
1525 return i;
1526 }
1527
1528 while ((p = strsep(&b, ":"))) {
1529 if (*p == '\0') continue;
1530 ldpaths[i++] = xstrdup(p);
1531
1532 if (i + 1 == ARRAY_SIZE(ldpaths))
1533 break;
1534 }
1535 ldpaths[i] = NULL;
1536
1537 free(b);
1538 fclose(fp);
1539 return i;
1540 }
1541
1542 #else
1543
1544 #warning Cache config support not implemented for your target
1545 static int load_ld_cache_config(int i, const char *fname)
1546 {
1547 memset(ldpaths, 0x00, sizeof(ldpaths));
1548 }
1549
1550 #endif
1551
1552 /* scan /etc/ld.so.conf for paths */
1553 static void scanelf_ldpath(void)
1554 {
1555 char scan_l, scan_ul, scan_ull;
1556 int i = 0;
1557
1558 if (!ldpaths[0])
1559 err("Unable to load any paths from ld.so.conf");
1560
1561 scan_l = scan_ul = scan_ull = 0;
1562
1563 while (ldpaths[i]) {
1564 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1565 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1566 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1567 scanelf_dir(ldpaths[i]);
1568 ++i;
1569 }
1570
1571 if (!scan_l) scanelf_dir("/lib");
1572 if (!scan_ul) scanelf_dir("/usr/lib");
1573 if (!scan_ull) scanelf_dir("/usr/local/lib");
1574 }
1575
1576 /* scan env PATH for paths */
1577 static void scanelf_envpath(void)
1578 {
1579 char *path, *p;
1580
1581 path = getenv("PATH");
1582 if (!path)
1583 err("PATH is not set in your env !");
1584 path = xstrdup(path);
1585
1586 while ((p = strrchr(path, ':')) != NULL) {
1587 scanelf_dir(p + 1);
1588 *p = 0;
1589 }
1590
1591 free(path);
1592 }
1593
1594 /* usage / invocation handling functions */ /* Free Flags: c d j u w C G H I J K P Q U W Y */
1595 #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DO:ZBhV"
1596 #define a_argument required_argument
1597 static struct option const long_opts[] = {
1598 {"path", no_argument, NULL, 'p'},
1599 {"ldpath", no_argument, NULL, 'l'},
1600 {"recursive", no_argument, NULL, 'R'},
1601 {"mount", no_argument, NULL, 'm'},
1602 {"symlink", no_argument, NULL, 'y'},
1603 {"archives", no_argument, NULL, 'A'},
1604 {"ldcache", no_argument, NULL, 'L'},
1605 {"fix", no_argument, NULL, 'X'},
1606 {"setpax", a_argument, NULL, 'z'},
1607 {"pax", no_argument, NULL, 'x'},
1608 {"header", no_argument, NULL, 'e'},
1609 {"textrel", no_argument, NULL, 't'},
1610 {"rpath", no_argument, NULL, 'r'},
1611 {"needed", no_argument, NULL, 'n'},
1612 {"interp", no_argument, NULL, 'i'},
1613 {"bind", no_argument, NULL, 'b'},
1614 {"soname", no_argument, NULL, 'S'},
1615 {"symbol", a_argument, NULL, 's'},
1616 {"section", a_argument, NULL, 'k'},
1617 {"lib", a_argument, NULL, 'N'},
1618 {"gmatch", no_argument, NULL, 'g'},
1619 {"textrels", no_argument, NULL, 'T'},
1620 {"etype", a_argument, NULL, 'E'},
1621 {"bits", a_argument, NULL, 'M'},
1622 {"endian", no_argument, NULL, 'D'},
1623 {"perms", a_argument, NULL, 'O'},
1624 {"size", no_argument, NULL, 'Z'},
1625 {"all", no_argument, NULL, 'a'},
1626 {"quiet", no_argument, NULL, 'q'},
1627 {"verbose", no_argument, NULL, 'v'},
1628 {"format", a_argument, NULL, 'F'},
1629 {"from", a_argument, NULL, 'f'},
1630 {"file", a_argument, NULL, 'o'},
1631 {"nobanner", no_argument, NULL, 'B'},
1632 {"help", no_argument, NULL, 'h'},
1633 {"version", no_argument, NULL, 'V'},
1634 {NULL, no_argument, NULL, 0x0}
1635 };
1636
1637 static const char *opts_help[] = {
1638 "Scan all directories in PATH environment",
1639 "Scan all directories in /etc/ld.so.conf",
1640 "Scan directories recursively",
1641 "Don't recursively cross mount points",
1642 "Don't scan symlinks",
1643 "Scan archives (.a files)",
1644 "Utilize ld.so.cache information (use with -r/-n)",
1645 "Try and 'fix' bad things (use with -r/-e)",
1646 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1647 "Print PaX markings",
1648 "Print GNU_STACK/PT_LOAD markings",
1649 "Print TEXTREL information",
1650 "Print RPATH information",
1651 "Print NEEDED information",
1652 "Print INTERP information",
1653 "Print BIND information",
1654 "Print SONAME information",
1655 "Find a specified symbol",
1656 "Find a specified section",
1657 "Find a specified library",
1658 "Use strncmp to match libraries. (use with -N)",
1659 "Locate cause of TEXTREL",
1660 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1661 "Print only ELF files matching numeric bits",
1662 "Print Endianness",
1663 "Print only ELF files matching octal permissions",
1664 "Print ELF file size",
1665 "Print all scanned info (-x -e -t -r -b)\n",
1666 "Only output 'bad' things",
1667 "Be verbose (can be specified more than once)",
1668 "Use specified format for output",
1669 "Read input stream from a filename",
1670 "Write output stream to a filename",
1671 "Don't display the header",
1672 "Print this help and exit",
1673 "Print version and exit",
1674 NULL
1675 };
1676
1677 /* display usage and exit */
1678 static void usage(int status)
1679 {
1680 unsigned long i;
1681 printf("* Scan ELF binaries for stuff\n\n"
1682 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1683 printf("Options: -[%s]\n", PARSE_FLAGS);
1684 for (i = 0; long_opts[i].name; ++i)
1685 if (long_opts[i].has_arg == no_argument)
1686 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1687 long_opts[i].name, opts_help[i]);
1688 else
1689 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1690 long_opts[i].name, opts_help[i]);
1691
1692 puts("\nFor more information, see the scanelf(1) manpage");
1693 exit(status);
1694 }
1695
1696 /* parse command line arguments and preform needed actions */
1697 #define do_pax_state(option, flag) \
1698 if (islower(option)) { \
1699 flags &= ~PF_##flag; \
1700 flags |= PF_NO##flag; \
1701 } else { \
1702 flags &= ~PF_NO##flag; \
1703 flags |= PF_##flag; \
1704 }
1705 static int parseargs(int argc, char *argv[])
1706 {
1707 int i;
1708 const char *from_file = NULL;
1709 int ret = 0;
1710
1711 opterr = 0;
1712 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1713 switch (i) {
1714
1715 case 'V':
1716 printf("pax-utils-%s: %s compiled %s\n%s\n"
1717 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1718 VERSION, __FILE__, __DATE__, rcsid, argv0);
1719 exit(EXIT_SUCCESS);
1720 break;
1721 case 'h': usage(EXIT_SUCCESS); break;
1722 case 'f':
1723 if (from_file) warn("You prob don't want to specify -f twice");
1724 from_file = optarg;
1725 break;
1726 case 'E':
1727 strncpy(match_etypes, optarg, sizeof(match_etypes));
1728 break;
1729 case 'M':
1730 match_bits = atoi(optarg);
1731 if (match_bits == 0) {
1732 if (strcmp(optarg, "ELFCLASS32") == 0)
1733 match_bits = 32;
1734 if (strcmp(optarg, "ELFCLASS64") == 0)
1735 match_bits = 64;
1736 }
1737 break;
1738 case 'O':
1739 if (sscanf(optarg, "%o", &match_perms) == (-1))
1740 match_bits = 0;
1741 break;
1742 case 'o': {
1743 if (freopen(optarg, "w", stdout) == NULL)
1744 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1745 break;
1746 }
1747 case 'k':
1748 if (find_section) warn("You prob don't want to specify -k twice");
1749 find_section = optarg;
1750 break;
1751 case 's': {
1752 if (find_sym) warn("You prob don't want to specify -s twice");
1753 find_sym = optarg;
1754 versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1755 sprintf(versioned_symname, "%s@", find_sym);
1756 break;
1757 }
1758 case 'N': {
1759 if (find_lib) warn("You prob don't want to specify -N twice");
1760 find_lib = optarg;
1761 break;
1762 }
1763
1764 case 'F': {
1765 if (out_format) warn("You prob don't want to specify -F twice");
1766 out_format = optarg;
1767 break;
1768 }
1769 case 'z': {
1770 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1771 size_t x;
1772
1773 for (x = 0; x < strlen(optarg); x++) {
1774 switch (optarg[x]) {
1775 case 'p':
1776 case 'P':
1777 do_pax_state(optarg[x], PAGEEXEC);
1778 break;
1779 case 's':
1780 case 'S':
1781 do_pax_state(optarg[x], SEGMEXEC);
1782 break;
1783 case 'm':
1784 case 'M':
1785 do_pax_state(optarg[x], MPROTECT);
1786 break;
1787 case 'e':
1788 case 'E':
1789 do_pax_state(optarg[x], EMUTRAMP);
1790 break;
1791 case 'r':
1792 case 'R':
1793 do_pax_state(optarg[x], RANDMMAP);
1794 break;
1795 case 'x':
1796 case 'X':
1797 do_pax_state(optarg[x], RANDEXEC);
1798 break;
1799 default:
1800 break;
1801 }
1802 }
1803 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1804 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1805 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1806 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1807 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1808 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1809 setpax = flags;
1810 break;
1811 }
1812 case 'Z': show_size = 1; break;
1813 case 'g': g_match = 1; break;
1814 case 'L': use_ldcache = 1; break;
1815 case 'y': scan_symlink = 0; break;
1816 case 'A': scan_archives = 1; break;
1817 case 'B': show_banner = 0; break;
1818 case 'l': scan_ldpath = 1; break;
1819 case 'p': scan_envpath = 1; break;
1820 case 'R': dir_recurse = 1; break;
1821 case 'm': dir_crossmount = 0; break;
1822 case 'X': ++fix_elf; break;
1823 case 'x': show_pax = 1; break;
1824 case 'e': show_phdr = 1; break;
1825 case 't': show_textrel = 1; break;
1826 case 'r': show_rpath = 1; break;
1827 case 'n': show_needed = 1; break;
1828 case 'i': show_interp = 1; break;
1829 case 'b': show_bind = 1; break;
1830 case 'S': show_soname = 1; break;
1831 case 'T': show_textrels = 1; break;
1832 case 'q': be_quiet = 1; break;
1833 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1834 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1835 case 'D': show_endian = 1; break;
1836 case ':':
1837 err("Option '%c' is missing parameter", optopt);
1838 case '?':
1839 err("Unknown option '%c' or argument missing", optopt);
1840 default:
1841 err("Unhandled option '%c'; please report this", i);
1842 }
1843 }
1844 if (show_textrels && be_verbose) {
1845 if (which("objdump") != NULL)
1846 has_objdump = 1;
1847 }
1848 /* let the format option override all other options */
1849 if (out_format) {
1850 show_pax = show_phdr = show_textrel = show_rpath = \
1851 show_needed = show_interp = show_bind = show_soname = \
1852 show_textrels = show_perms = show_endian = show_size = 0;
1853 for (i = 0; out_format[i]; ++i) {
1854 if (!IS_MODIFIER(out_format[i])) continue;
1855
1856 switch (out_format[++i]) {
1857 case '+': break;
1858 case '%': break;
1859 case '#': break;
1860 case 'F': break;
1861 case 'p': break;
1862 case 'f': break;
1863 case 'k': break;
1864 case 's': break;
1865 case 'N': break;
1866 case 'o': break;
1867 case 'a': break;
1868 case 'M': break;
1869 case 'Z': show_size = 1; break;
1870 case 'D': show_endian = 1; break;
1871 case 'O': show_perms = 1; break;
1872 case 'x': show_pax = 1; break;
1873 case 'e': show_phdr = 1; break;
1874 case 't': show_textrel = 1; break;
1875 case 'r': show_rpath = 1; break;
1876 case 'n': show_needed = 1; break;
1877 case 'i': show_interp = 1; break;
1878 case 'b': show_bind = 1; break;
1879 case 'S': show_soname = 1; break;
1880 case 'T': show_textrels = 1; break;
1881 default:
1882 err("Invalid format specifier '%c' (byte %i)",
1883 out_format[i], i+1);
1884 }
1885 }
1886
1887 /* construct our default format */
1888 } else {
1889 size_t fmt_len = 30;
1890 out_format = xmalloc(sizeof(char) * fmt_len);
1891 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1892 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1893 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1894 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
1895 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1896 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1897 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1898 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1899 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1900 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1901 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1902 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1903 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1904 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1905 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1906 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1907 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1908 }
1909 if (be_verbose > 2) printf("Format: %s\n", out_format);
1910
1911 /* now lets actually do the scanning */
1912 if (scan_ldpath || use_ldcache)
1913 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1914 if (scan_ldpath) scanelf_ldpath();
1915 if (scan_envpath) scanelf_envpath();
1916 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1917 from_file = "-";
1918 if (from_file) {
1919 scanelf_from_file(from_file);
1920 from_file = *argv;
1921 }
1922 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1923 err("Nothing to scan !?");
1924 while (optind < argc) {
1925 search_path = argv[optind++];
1926 ret = scanelf_dir(search_path);
1927 }
1928
1929 /* clean up */
1930 free(versioned_symname);
1931 for (i = 0; ldpaths[i]; ++i)
1932 free(ldpaths[i]);
1933
1934 if (ldcache != 0)
1935 munmap(ldcache, ldcache_size);
1936 return ret;
1937 }
1938
1939 static char **get_split_env(const char *envvar)
1940 {
1941 const char *delims = " \t\n";
1942 char **envvals = NULL;
1943 char *env, *s;
1944 int nentry;
1945
1946 if ((env = getenv(envvar)) == NULL)
1947 return NULL;
1948
1949 env = xstrdup(env);
1950 if (env == NULL)
1951 return NULL;
1952
1953 s = strtok(env, delims);
1954 if (s == NULL) {
1955 free(env);
1956 return NULL;
1957 }
1958
1959 nentry = 0;
1960 while (s != NULL) {
1961 ++nentry;
1962 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1963 envvals[nentry-1] = s;
1964 s = strtok(NULL, delims);
1965 }
1966 envvals[nentry] = NULL;
1967
1968 /* don't want to free(env) as it contains the memory that backs
1969 * the envvals array of strings */
1970 return envvals;
1971 }
1972
1973 static void parseenv(void)
1974 {
1975 qa_textrels = get_split_env("QA_TEXTRELS");
1976 qa_execstack = get_split_env("QA_EXECSTACK");
1977 qa_wx_load = get_split_env("QA_WX_LOAD");
1978 }
1979
1980 #ifdef __PAX_UTILS_CLEANUP
1981 static void cleanup(void)
1982 {
1983 free(out_format);
1984 free(qa_textrels);
1985 free(qa_execstack);
1986 free(qa_wx_load);
1987 }
1988 #endif
1989
1990 int main(int argc, char *argv[])
1991 {
1992 int ret;
1993 if (argc < 2)
1994 usage(EXIT_FAILURE);
1995 parseenv();
1996 ret = parseargs(argc, argv);
1997 fclose(stdout);
1998 #ifdef __PAX_UTILS_CLEANUP
1999 cleanup();
2000 warn("The calls to add/delete heap should be off:\n"
2001 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
2002 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
2003 #endif
2004 return ret;
2005 }
2006
2007 /* Match filename against entries in matchlist, return TRUE
2008 * if the file is listed */
2009 static int file_matches_list(const char *filename, char **matchlist)
2010 {
2011 char **file;
2012 char *match;
2013 char buf[__PAX_UTILS_PATH_MAX];
2014
2015 if (matchlist == NULL)
2016 return 0;
2017
2018 for (file = matchlist; *file != NULL; file++) {
2019 if (search_path) {
2020 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2021 match = buf;
2022 } else {
2023 match = *file;
2024 }
2025 if (fnmatch(match, filename, 0) == 0)
2026 return 1;
2027 }
2028 return 0;
2029 }

  ViewVC Help
Powered by ViewVC 1.1.20