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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.229 - (hide annotations) (download) (as text)
Tue Sep 27 19:29:19 2011 UTC (2 years, 11 months ago) by vapier
Branch: MAIN
Changes since 1.228: +2 -16 lines
File MIME type: text/x-csrc
remove useless duplicate prototypes

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

  ViewVC Help
Powered by ViewVC 1.1.20