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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.180 - (hide annotations) (download) (as text)
Sat Jun 9 21:43:53 2007 UTC (7 years, 1 month ago) by solar
Branch: MAIN
Changes since 1.179: +35 -5 lines
File MIME type: text/x-csrc
- Print only ELF files with matching specified octal bits (like 755)

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

  ViewVC Help
Powered by ViewVC 1.1.20