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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.187 - (hide annotations) (download) (as text)
Sat Aug 25 02:46:18 2007 UTC (7 years, 4 months ago) by vapier
Branch: MAIN
Changes since 1.186: +15 -17 lines
File MIME type: text/x-csrc
residual xfunc changeover: dont check return value of xmalloc()

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

  ViewVC Help
Powered by ViewVC 1.1.20