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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.190 - (hide annotations) (download) (as text)
Sat Apr 19 22:31:49 2008 UTC (6 years ago) by solar
Branch: MAIN
Changes since 1.189: +14 -6 lines
File MIME type: text/x-csrc
- add -Z/--size option

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

  ViewVC Help
Powered by ViewVC 1.1.20