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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.231 - (hide annotations) (download) (as text)
Tue Sep 27 19:58:09 2011 UTC (2 years, 10 months ago) by vapier
Branch: MAIN
Changes since 1.230: +2 -2 lines
File MIME type: text/x-csrc
simplify rcsid a little

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

  ViewVC Help
Powered by ViewVC 1.1.20