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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.186 - (hide annotations) (download) (as text)
Mon Aug 20 09:54:15 2007 UTC (7 years, 3 months ago) by vapier
Branch: MAIN
Changes since 1.185: +23 -64 lines
File MIME type: text/x-csrc
split xfuncs off into a sep file for all utils to use, cleanup misc things, and add some more comments

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