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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.228 - (hide annotations) (download) (as text)
Tue Sep 27 19:21:56 2011 UTC (2 years, 9 months ago) by vapier
Branch: MAIN
Changes since 1.227: +3 -3 lines
File MIME type: text/x-csrc
simplify match_etype logic

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

  ViewVC Help
Powered by ViewVC 1.1.20