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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.189 - (hide annotations) (download) (as text)
Thu Jan 17 04:37:19 2008 UTC (6 years, 8 months ago) by solar
Branch: MAIN
Changes since 1.188: +2 -8 lines
File MIME type: text/x-csrc
- mainly whitespace updates

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

  ViewVC Help
Powered by ViewVC 1.1.20