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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.191 - (hide annotations) (download) (as text)
Tue Jun 17 17:07:57 2008 UTC (6 years, 1 month ago) by solar
Branch: MAIN
Changes since 1.190: +22 -5 lines
File MIME type: text/x-csrc
- add OSABI/EABI support to scanelf --osabi/--eabi to scanelf. Update elf.h

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

  ViewVC Help
Powered by ViewVC 1.1.20