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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.217 - (hide annotations) (download) (as text)
Fri Jan 15 10:29:17 2010 UTC (4 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.216: +22 -22 lines
File MIME type: text/x-csrc
convert core pointers to void* to avoid ugly casts and gcc alignment warnings #290543

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

  ViewVC Help
Powered by ViewVC 1.1.20