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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.184 - (hide annotations) (download) (as text)
Sun Aug 12 16:35:25 2007 UTC (6 years, 11 months ago) by vapier
Branch: MAIN
Changes since 1.183: +6 -6 lines
File MIME type: text/x-csrc
add missing void into empty function definitions

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.184 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.183 2007/06/29 19:49:26 solar Exp $
5 solar 1.1 *
6 solar 1.179 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.89 #include "paxinc.h"
11 flameeyes 1.141
12 vapier 1.184 static const char *rcsid = "$Id: scanelf.c,v 1.183 2007/06/29 19:49:26 solar Exp $";
13 vapier 1.36 #define argv0 "scanelf"
14 vapier 1.10
15 solar 1.132 #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16 vapier 1.70
17 vapier 1.10 /* prototypes */
18 kevquinn 1.142 static int file_matches_list(const char *filename, char **matchlist);
19 vapier 1.106 static int scanelf_elfobj(elfobj *elf);
20     static int scanelf_elf(const char *filename, int fd, size_t len);
21     static int scanelf_archive(const char *filename, int fd, size_t len);
22 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache);
23     static int scanelf_dir(const char *path);
24 vapier 1.106 static void scanelf_ldpath(void);
25     static void scanelf_envpath(void);
26 vapier 1.10 static void usage(int status);
27 kevquinn 1.142 static char **get_split_env(const char *envvar);
28     static void parseenv(void);
29 solar 1.164 static int parseargs(int argc, char *argv[]);
30 vapier 1.60 static char *xstrdup(const char *s);
31 vapier 1.41 static void *xmalloc(size_t size);
32 kevquinn 1.142 static void *xrealloc(void *ptr, size_t size);
33 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
34     #define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
35 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len);
36 solar 1.174 static int rematch(const char *regex, const char *match, int cflags);
37 vapier 1.10
38     /* variables to control behavior */
39 solar 1.119 static char match_etypes[126] = "";
40 vapier 1.48 static char *ldpaths[256];
41 vapier 1.10 static char scan_ldpath = 0;
42     static char scan_envpath = 0;
43 vapier 1.37 static char scan_symlink = 1;
44 vapier 1.105 static char scan_archives = 0;
45 vapier 1.10 static char dir_recurse = 0;
46 vapier 1.14 static char dir_crossmount = 1;
47 vapier 1.10 static char show_pax = 0;
48 solar 1.180 static char show_perms = 0;
49 solar 1.73 static char show_phdr = 0;
50 vapier 1.10 static char show_textrel = 0;
51     static char show_rpath = 0;
52 vapier 1.32 static char show_needed = 0;
53 vapier 1.38 static char show_interp = 0;
54 vapier 1.49 static char show_bind = 0;
55 vapier 1.84 static char show_soname = 0;
56 vapier 1.76 static char show_textrels = 0;
57 solar 1.16 static char show_banner = 1;
58 solar 1.181 static char show_endian = 0;
59 vapier 1.10 static char be_quiet = 0;
60 vapier 1.14 static char be_verbose = 0;
61 solar 1.127 static char be_wewy_wewy_quiet = 0;
62 solar 1.132 static char be_semi_verbose = 0;
63 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
64 vapier 1.72 static char *find_lib = NULL;
65 solar 1.124 static char *find_section = NULL;
66 vapier 1.39 static char *out_format = NULL;
67 vapier 1.66 static char *search_path = NULL;
68 vapier 1.101 static char fix_elf = 0;
69 solar 1.176 static char g_match = 0;
70 vapier 1.102 static char use_ldcache = 0;
71 solar 1.1
72 kevquinn 1.142 static char **qa_textrels = NULL;
73     static char **qa_execstack = NULL;
74 kevquinn 1.145 static char **qa_wx_load = NULL;
75 kevquinn 1.142
76 solar 1.120 int match_bits = 0;
77 solar 1.180 unsigned int match_perms = 0;
78 solar 1.96 caddr_t ldcache = 0;
79     size_t ldcache_size = 0;
80 solar 1.127 unsigned long setpax = 0UL;
81 solar 1.96
82 solar 1.170 int has_objdump = 0;
83 solar 1.175
84 solar 1.180 static char *getstr_perms(const char *fname);
85     static char *getstr_perms(const char *fname) {
86     struct stat st;
87     static char buf[8];
88    
89     if ((stat(fname, &st)) == (-1))
90     return (char *) "";
91    
92     snprintf(buf, sizeof(buf), "%o", st.st_mode);
93    
94     return (char *) buf + 2;
95     }
96    
97 solar 1.174 /* find the path to a file by name */
98 solar 1.170 static char *which(const char *fname)
99     {
100     static char fullpath[BUFSIZ];
101 vapier 1.172 char *path, *p;
102 solar 1.170
103 vapier 1.172 path = getenv("PATH");
104     if (!path)
105 solar 1.170 return NULL;
106    
107 vapier 1.172 path = xstrdup(path);
108     while ((p = strrchr(path, ':')) != NULL) {
109 solar 1.170 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
110 vapier 1.172 *p = 0;
111 solar 1.170 if (access(fullpath, R_OK) != (-1)) {
112     free(path);
113     return (char *) fullpath;
114     }
115 vapier 1.172 }
116     free(path);
117 solar 1.170 return NULL;
118     }
119 vapier 1.152
120 solar 1.175 /* 1 on failure. 0 otherwise */
121 solar 1.174 static int rematch(const char *regex, const char *match, int cflags)
122     {
123     regex_t preg;
124     int ret;
125    
126     if ((match == NULL) || (regex == NULL))
127     return EXIT_FAILURE;
128    
129    
130     if ((ret = regcomp(&preg, regex, cflags))) {
131     char err[256];
132    
133     if (regerror(ret, &preg, err, sizeof(err)))
134     fprintf(stderr, "regcomp failed: %s", err);
135     else
136     fprintf(stderr, "regcomp failed");
137    
138     return EXIT_FAILURE;
139     }
140     ret = regexec(&preg, match, 0, NULL, 0);
141     regfree(&preg);
142    
143     return ret;
144     }
145    
146 vapier 1.39 /* sub-funcs for scanelf_file() */
147 vapier 1.77 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
148     {
149     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
150     #define GET_SYMTABS(B) \
151     if (elf->elf_class == ELFCLASS ## B) { \
152     Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
153     /* debug sections */ \
154     symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
155     strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
156     /* runtime sections */ \
157     dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
158     dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
159     if (symtab && dynsym) { \
160     *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
161     } else { \
162     *sym = (void*)(symtab ? symtab : dynsym); \
163     } \
164     if (strtab && dynstr) { \
165     *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
166     } else { \
167     *tab = (void*)(strtab ? strtab : dynstr); \
168     } \
169     }
170     GET_SYMTABS(32)
171     GET_SYMTABS(64)
172     }
173 solar 1.127
174 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
175 solar 1.6 {
176 solar 1.61 static char ret[7];
177     unsigned long i, shown;
178    
179 vapier 1.41 if (!show_pax) return NULL;
180 vapier 1.10
181 solar 1.61 shown = 0;
182     memset(&ret, 0, sizeof(ret));
183    
184     if (elf->phdr) {
185     #define SHOW_PAX(B) \
186     if (elf->elf_class == ELFCLASS ## B) { \
187     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
188     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
189     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
190     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
191     continue; \
192 solar 1.127 if (fix_elf && setpax) { \
193     /* set the paxctl flags */ \
194     ESET(phdr[i].p_flags, setpax); \
195     } \
196 solar 1.129 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
197 solar 1.61 continue; \
198     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
199     *found_pax = 1; \
200     ++shown; \
201     break; \
202     } \
203     }
204     SHOW_PAX(32)
205     SHOW_PAX(64)
206     }
207    
208 solar 1.128
209     if (fix_elf && setpax) {
210     /* set the chpax settings */
211 solar 1.129 if (elf->elf_class == ELFCLASS32) {
212     if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
213     ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
214     } else {
215     if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
216     ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
217     }
218 solar 1.128 }
219    
220 solar 1.61 /* fall back to EI_PAX if no PT_PAX was found */
221     if (!*ret) {
222 vapier 1.90 static char *paxflags;
223 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
224     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
225     *found_pax = 1;
226 solar 1.127 return (be_wewy_wewy_quiet ? NULL : paxflags);
227 solar 1.61 }
228     strncpy(ret, paxflags, sizeof(ret));
229 vapier 1.14 }
230 vapier 1.41
231 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
232 solar 1.61 return NULL;
233 vapier 1.90 else
234     return ret;
235     }
236 solar 1.61
237 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
238 vapier 1.39 {
239 vapier 1.71 static char ret[12];
240 vapier 1.41 char *found;
241 vapier 1.99 unsigned long i, shown, multi_stack, multi_relro, multi_load;
242     int max_pt_load;
243 vapier 1.41
244 solar 1.73 if (!show_phdr) return NULL;
245 vapier 1.41
246 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
247    
248 vapier 1.41 shown = 0;
249 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
250 vapier 1.99 max_pt_load = elf_max_pt_load(elf);
251 vapier 1.44
252 vapier 1.108 #define NOTE_GNU_STACK ".note.GNU-stack"
253 solar 1.73 #define SHOW_PHDR(B) \
254 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
255     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
256 vapier 1.91 Elf ## B ## _Off offset; \
257     uint32_t flags, check_flags; \
258     if (elf->phdr != NULL) { \
259     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
260     for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
261     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
262 vapier 1.152 if (multi_stack++) \
263     warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
264     if (file_matches_list(elf->filename, qa_execstack)) \
265     continue; \
266     found = found_phdr; \
267     offset = 0; \
268     check_flags = PF_X; \
269 vapier 1.91 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
270 vapier 1.152 if (multi_relro++) \
271     warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
272 vapier 1.91 found = found_relro; \
273     offset = 4; \
274     check_flags = PF_X; \
275     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
276 solar 1.117 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
277 vapier 1.152 if (multi_load++ > max_pt_load) \
278     warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
279     if (file_matches_list(elf->filename, qa_wx_load)) \
280     continue; \
281     found = found_load; \
282     offset = 8; \
283     check_flags = PF_W|PF_X; \
284 vapier 1.91 } else \
285     continue; \
286     flags = EGET(phdr[i].p_flags); \
287     if (be_quiet && ((flags & check_flags) != check_flags)) \
288     continue; \
289 solar 1.130 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
290 vapier 1.101 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
291     ret[3] = ret[7] = '!'; \
292     flags = EGET(phdr[i].p_flags); \
293     } \
294 vapier 1.91 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
295     *found = 1; \
296     ++shown; \
297     } \
298     } else if (elf->shdr != NULL) { \
299     /* no program headers which means this is prob an object file */ \
300     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
301     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
302 vapier 1.108 char *str; \
303 vapier 1.118 if ((void*)strtbl > (void*)elf->data_end) \
304 vapier 1.108 goto skip_this_shdr##B; \
305 vapier 1.91 check_flags = SHF_WRITE|SHF_EXECINSTR; \
306     for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
307     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
308     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
309 vapier 1.108 str = elf->data + offset; \
310     if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
311     if (!strcmp(str, NOTE_GNU_STACK)) { \
312 vapier 1.91 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
313     flags = EGET(shdr[i].sh_flags); \
314     if (be_quiet && ((flags & check_flags) != check_flags)) \
315     continue; \
316     ++*found_phdr; \
317     shown = 1; \
318     if (flags & SHF_WRITE) ret[0] = 'W'; \
319     if (flags & SHF_ALLOC) ret[1] = 'A'; \
320     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
321     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
322     break; \
323     } \
324     } \
325 vapier 1.108 skip_this_shdr##B: \
326 vapier 1.91 if (!multi_stack) { \
327 vapier 1.158 if (file_matches_list(elf->filename, qa_execstack)) \
328     return NULL; \
329 vapier 1.91 *found_phdr = 1; \
330     shown = 1; \
331     memcpy(ret, "!WX", 3); \
332     } \
333 vapier 1.39 } \
334     }
335 solar 1.73 SHOW_PHDR(32)
336     SHOW_PHDR(64)
337 vapier 1.44
338 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
339 vapier 1.41 return NULL;
340     else
341     return ret;
342 vapier 1.39 }
343 kevquinn 1.142
344 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
345 vapier 1.39 {
346 vapier 1.90 static const char *ret = "TEXTREL";
347 vapier 1.44 unsigned long i;
348 vapier 1.41
349 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
350 vapier 1.41
351 kevquinn 1.142 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
352    
353 vapier 1.44 if (elf->phdr) {
354 vapier 1.39 #define SHOW_TEXTREL(B) \
355     if (elf->elf_class == ELFCLASS ## B) { \
356     Elf ## B ## _Dyn *dyn; \
357     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
358     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
359 vapier 1.44 Elf ## B ## _Off offset; \
360 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
361 vapier 1.59 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
362 vapier 1.44 offset = EGET(phdr[i].p_offset); \
363     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
364     dyn = DYN ## B (elf->data + offset); \
365 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
366     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
367     *found_textrel = 1; \
368     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
369 solar 1.127 return (be_wewy_wewy_quiet ? NULL : ret); \
370 vapier 1.39 } \
371     ++dyn; \
372 vapier 1.26 } \
373 vapier 1.39 } }
374     SHOW_TEXTREL(32)
375     SHOW_TEXTREL(64)
376 vapier 1.44 }
377    
378 solar 1.127 if (be_quiet || be_wewy_wewy_quiet)
379 vapier 1.41 return NULL;
380     else
381 vapier 1.90 return " - ";
382 vapier 1.39 }
383 solar 1.180
384 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
385 vapier 1.76 {
386 vapier 1.82 unsigned long s, r, rmax;
387     void *symtab_void, *strtab_void, *text_void;
388 vapier 1.76
389     if (!show_textrels) return NULL;
390    
391 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
392     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
393     if (!*found_textrel) return NULL;
394    
395 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
396 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
397 vapier 1.76
398 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
399 vapier 1.76 #define SHOW_TEXTRELS(B) \
400     if (elf->elf_class == ELFCLASS ## B) { \
401     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
402     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
403     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
404     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
405 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
406     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
407     uint ## B ## _t memsz = EGET(text->sh_size); \
408 vapier 1.76 Elf ## B ## _Rel *rel; \
409     Elf ## B ## _Rela *rela; \
410     /* search the section headers for relocations */ \
411     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
412     uint32_t sh_type = EGET(shdr[s].sh_type); \
413     if (sh_type == SHT_REL) { \
414     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
415     rela = NULL; \
416     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
417     } else if (sh_type == SHT_RELA) { \
418     rel = NULL; \
419     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
420     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
421     } else \
422     continue; \
423 vapier 1.82 /* now see if any of the relocs are in the .text */ \
424     for (r = 0; r < rmax; ++r) { \
425     unsigned long sym_max; \
426     Elf ## B ## _Addr offset_tmp; \
427     Elf ## B ## _Sym *func; \
428     Elf ## B ## _Sym *sym; \
429     Elf ## B ## _Addr r_offset; \
430     uint ## B ## _t r_info; \
431     if (sh_type == SHT_REL) { \
432     r_offset = EGET(rel[r].r_offset); \
433     r_info = EGET(rel[r].r_info); \
434     } else { \
435     r_offset = EGET(rela[r].r_offset); \
436     r_info = EGET(rela[r].r_info); \
437     } \
438     /* make sure this relocation is inside of the .text */ \
439     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
440     if (be_verbose <= 2) continue; \
441     } else \
442 vapier 1.78 *found_textrels = 1; \
443 vapier 1.82 /* locate this relocation symbol name */ \
444     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
445 vapier 1.112 if ((void*)sym > (void*)elf->data_end) { \
446 vapier 1.111 warn("%s: corrupt ELF symbol", elf->filename); \
447 vapier 1.109 continue; \
448     } \
449 vapier 1.82 sym_max = ELF ## B ## _R_SYM(r_info); \
450     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
451     sym += sym_max; \
452     else \
453     sym = NULL; \
454     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
455     /* show the raw details about this reloc */ \
456 vapier 1.88 printf(" %s: ", elf->base_filename); \
457 vapier 1.82 if (sym && sym->st_name) \
458     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
459     else \
460 vapier 1.169 printf("(memory/data?)"); \
461 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
462     /* now try to find the closest symbol that this rel is probably in */ \
463     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
464     func = NULL; \
465     offset_tmp = 0; \
466     while (sym_max--) { \
467     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
468     func = sym; \
469     offset_tmp = EGET(sym->st_value); \
470 vapier 1.76 } \
471 vapier 1.82 ++sym; \
472 vapier 1.76 } \
473 vapier 1.82 printf(" in "); \
474 vapier 1.169 if (func && func->st_name) { \
475     const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
476     if (r_offset > EGET(func->st_size)) \
477     printf("(optimized out: previous %s)", func_name); \
478     else \
479     printf("%s", func_name); \
480     } else \
481     printf("(optimized out)"); \
482 vapier 1.82 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
483 solar 1.170 if (be_verbose && has_objdump) { \
484 vapier 1.167 char *sysbuf; \
485     size_t syslen; \
486     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"; \
487     syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
488     sysbuf = xmalloc(syslen); \
489     if (sysbuf) { \
490 vapier 1.169 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
491     if (end_addr < r_offset) \
492     /* not uncommon when things are optimized out */ \
493     end_addr = r_offset + 0x100; \
494 vapier 1.167 snprintf(sysbuf, syslen, sysfmt, \
495     (unsigned long)offset_tmp, \
496 vapier 1.169 (unsigned long)end_addr, \
497 vapier 1.167 elf->filename, \
498     (unsigned long)r_offset); \
499 vapier 1.168 fflush(stdout); \
500 vapier 1.167 system(sysbuf); \
501 vapier 1.168 fflush(stdout); \
502 vapier 1.167 free(sysbuf); \
503     } \
504     } \
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.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) 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     if (EGET(phdr[i].p_type) != PT_DYNAMIC) 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     if (EGET(phdr[i].p_type) != PT_DYNAMIC) 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     if (ehdr->e_type != ET_DYN) \
948     return NULL; \
949     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
950     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
951     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    
1071 solar 1.124 static char *scanelf_file_sections(elfobj *elf, char *found_section)
1072     {
1073     if (!find_section)
1074     return NULL;
1075    
1076     #define FIND_SECTION(B) \
1077     if (elf->elf_class == ELFCLASS ## B) { \
1078 solar 1.136 int invert; \
1079 solar 1.124 Elf ## B ## _Shdr *section; \
1080 solar 1.136 invert = (*find_section == '!' ? 1 : 0); \
1081     section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1082     if ((section == NULL && invert) || (section != NULL && !invert)) \
1083 solar 1.124 *found_section = 1; \
1084     }
1085     FIND_SECTION(32)
1086     FIND_SECTION(64)
1087    
1088 vapier 1.138 if (be_wewy_wewy_quiet)
1089     return NULL;
1090 solar 1.124
1091     if (*found_section)
1092     return find_section;
1093    
1094     if (be_quiet)
1095     return NULL;
1096     else
1097     return (char *)" - ";
1098     }
1099    
1100 vapier 1.39 /* scan an elf file and show all the fun stuff */
1101 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
1102 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
1103 vapier 1.39 {
1104 vapier 1.44 unsigned long i;
1105 vapier 1.162 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1106     found_rpath, found_needed, found_interp, found_bind, found_soname,
1107 solar 1.124 found_sym, found_lib, found_file, found_textrels, found_section;
1108 vapier 1.41 static char *out_buffer = NULL;
1109     static size_t out_len;
1110 vapier 1.39
1111 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1112 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1113 solar 1.124 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1114 vapier 1.39
1115 vapier 1.114 if (be_verbose > 2)
1116 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
1117 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
1118     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1119 vapier 1.114 else if (be_verbose > 1)
1120 vapier 1.106 printf("%s: scanning file\n", elf->filename);
1121 vapier 1.39
1122 vapier 1.41 /* init output buffer */
1123     if (!out_buffer) {
1124     out_len = sizeof(char) * 80;
1125     out_buffer = (char*)xmalloc(out_len);
1126     }
1127     *out_buffer = '\0';
1128    
1129 vapier 1.39 /* show the header */
1130     if (!be_quiet && show_banner) {
1131 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1132 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1133 vapier 1.41
1134     switch (out_format[++i]) {
1135 solar 1.132 case '+': break;
1136 vapier 1.41 case '%': break;
1137 vapier 1.70 case '#': break;
1138 vapier 1.66 case 'F':
1139     case 'p':
1140     case 'f': prints("FILE "); found_file = 1; break;
1141 vapier 1.41 case 'o': prints(" TYPE "); break;
1142     case 'x': prints(" PAX "); break;
1143 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
1144 vapier 1.41 case 't': prints("TEXTREL "); break;
1145     case 'r': prints("RPATH "); break;
1146 vapier 1.171 case 'M': prints("CLASS "); break;
1147 vapier 1.41 case 'n': prints("NEEDED "); break;
1148     case 'i': prints("INTERP "); break;
1149 vapier 1.49 case 'b': prints("BIND "); break;
1150 vapier 1.84 case 'S': prints("SONAME "); break;
1151 vapier 1.41 case 's': prints("SYM "); break;
1152 vapier 1.72 case 'N': prints("LIB "); break;
1153 vapier 1.76 case 'T': prints("TEXTRELS "); break;
1154 vapier 1.126 case 'k': prints("SECTION "); break;
1155 vapier 1.166 case 'a': prints("ARCH "); break;
1156 solar 1.180 case 'O': prints("PERM "); break;
1157 solar 1.181 case 'D': prints("ENDIAN "); break;
1158 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
1159 vapier 1.39 }
1160 vapier 1.27 }
1161 vapier 1.49 if (!found_file) prints("FILE ");
1162 vapier 1.41 prints("\n");
1163 vapier 1.49 found_file = 0;
1164 vapier 1.39 show_banner = 0;
1165     }
1166    
1167     /* dump all the good stuff */
1168 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1169 vapier 1.41 const char *out;
1170 vapier 1.66 const char *tmp;
1171 vapier 1.41
1172 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
1173 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
1174     continue;
1175     }
1176 vapier 1.39
1177 vapier 1.41 out = NULL;
1178 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
1179 solar 1.132 be_semi_verbose = (out_format[i] == '+');
1180 vapier 1.41 switch (out_format[++i]) {
1181 solar 1.132 case '+':
1182 vapier 1.70 case '%':
1183     case '#':
1184     xchrcat(&out_buffer, out_format[i], &out_len); break;
1185     case 'F':
1186 vapier 1.76 found_file = 1;
1187 solar 1.127 if (be_wewy_wewy_quiet) break;
1188 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1189 vapier 1.70 break;
1190 vapier 1.66 case 'p':
1191 vapier 1.76 found_file = 1;
1192 solar 1.127 if (be_wewy_wewy_quiet) break;
1193 vapier 1.106 tmp = elf->filename;
1194 vapier 1.66 if (search_path) {
1195     ssize_t len_search = strlen(search_path);
1196 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1197     if (!strncmp(elf->filename, search_path, len_search) && \
1198 vapier 1.66 len_file > len_search)
1199     tmp += len_search;
1200     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1201     }
1202     xstrcat(&out_buffer, tmp, &out_len);
1203     break;
1204     case 'f':
1205 vapier 1.76 found_file = 1;
1206 solar 1.127 if (be_wewy_wewy_quiet) break;
1207 vapier 1.106 tmp = strrchr(elf->filename, '/');
1208     tmp = (tmp == NULL ? elf->filename : tmp+1);
1209 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1210     break;
1211 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1212     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1213 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1214 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1215 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1216 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1217 vapier 1.171 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1218 solar 1.181 case 'D': out = get_endian(elf); break;
1219 solar 1.180 case 'O': out = getstr_perms(elf->filename); break;
1220 vapier 1.72 case 'n':
1221     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1222 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1223 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1224 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1225 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1226 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1227 vapier 1.166 case 'a': out = get_elfemtype(elf); break;
1228 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1229 vapier 1.29 }
1230 vapier 1.95 if (out) {
1231     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1232     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1233     xstrncat(&out_buffer, out, &out_len, (tmp-out));
1234     else
1235     xstrcat(&out_buffer, out, &out_len);
1236     }
1237 vapier 1.39 }
1238    
1239 vapier 1.54 #define FOUND_SOMETHING() \
1240 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1241 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1242 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1243 vapier 1.54
1244     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1245     xchrcat(&out_buffer, ' ', &out_len);
1246 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1247 vapier 1.27 }
1248 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1249 vapier 1.41 puts(out_buffer);
1250 vapier 1.79 fflush(stdout);
1251     }
1252 vapier 1.10
1253 vapier 1.105 return 0;
1254     }
1255    
1256 vapier 1.106 /* scan a single elf */
1257     static int scanelf_elf(const char *filename, int fd, size_t len)
1258     {
1259 solar 1.120 int ret = 1;
1260 vapier 1.106 elfobj *elf;
1261    
1262     /* verify this is real ELF */
1263     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1264     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1265 solar 1.120 return ret;
1266     }
1267     switch (match_bits) {
1268     case 32:
1269     if (elf->elf_class != ELFCLASS32)
1270     goto label_done;
1271     break;
1272     case 64:
1273     if (elf->elf_class != ELFCLASS64)
1274     goto label_done;
1275     break;
1276     default: break;
1277 vapier 1.106 }
1278 solar 1.119 if (strlen(match_etypes)) {
1279     char sbuf[126];
1280     strncpy(sbuf, match_etypes, sizeof(sbuf));
1281     if (strchr(match_etypes, ',') != NULL) {
1282     char *p;
1283     while((p = strrchr(sbuf, ',')) != NULL) {
1284     *p = 0;
1285 solar 1.129 if (etype_lookup(p+1) == get_etype(elf))
1286 solar 1.119 goto label_ret;
1287     }
1288     }
1289 solar 1.129 if (etype_lookup(sbuf) != get_etype(elf))
1290 solar 1.119 goto label_done;
1291     }
1292    
1293     label_ret:
1294 vapier 1.106 ret = scanelf_elfobj(elf);
1295 solar 1.119
1296     label_done:
1297 vapier 1.106 unreadelf(elf);
1298     return ret;
1299     }
1300 solar 1.119
1301 vapier 1.105 /* scan an archive of elfs */
1302 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1303 vapier 1.105 {
1304 vapier 1.106 archive_handle *ar;
1305 vapier 1.105 archive_member *m;
1306 vapier 1.106 char *ar_buffer;
1307     elfobj *elf;
1308    
1309     ar = ar_open_fd(filename, fd);
1310     if (ar == NULL)
1311     return 1;
1312    
1313     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1314     while ((m=ar_next(ar)) != NULL) {
1315     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1316     if (elf) {
1317     scanelf_elfobj(elf);
1318     unreadelf(elf);
1319     }
1320     }
1321     munmap(ar_buffer, len);
1322    
1323 vapier 1.105 return 0;
1324     }
1325     /* scan a file which may be an elf or an archive or some other magical beast */
1326 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache)
1327 vapier 1.105 {
1328 vapier 1.161 const struct stat *st = st_cache;
1329     struct stat symlink_st;
1330 vapier 1.106 int fd;
1331 vapier 1.105
1332     /* always handle regular files and handle symlinked files if no -y */
1333 vapier 1.161 if (S_ISLNK(st->st_mode)) {
1334 solar 1.164 if (!scan_symlink) return 1;
1335 vapier 1.161 stat(filename, &symlink_st);
1336     st = &symlink_st;
1337 vapier 1.105 }
1338 vapier 1.161
1339     if (!S_ISREG(st->st_mode)) {
1340 vapier 1.105 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1341 solar 1.164 return 1;
1342 vapier 1.105 }
1343    
1344 solar 1.180 if (match_perms) {
1345     if ((st->st_mode | match_perms) != st->st_mode)
1346     return 1;
1347     }
1348 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1349 solar 1.164 return 1;
1350 vapier 1.106
1351 vapier 1.161 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1352 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1353 vapier 1.161 scanelf_archive(filename, fd, st->st_size);
1354 vapier 1.106
1355     close(fd);
1356 solar 1.164 return 0;
1357 solar 1.6 }
1358    
1359 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1360 solar 1.164 static int scanelf_dir(const char *path)
1361 solar 1.1 {
1362 vapier 1.10 register DIR *dir;
1363     register struct dirent *dentry;
1364 vapier 1.14 struct stat st_top, st;
1365 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1366 vapier 1.32 size_t pathlen = 0, len = 0;
1367 solar 1.164 int ret = 0;
1368 vapier 1.10
1369     /* make sure path exists */
1370 vapier 1.39 if (lstat(path, &st_top) == -1) {
1371     if (be_verbose > 2) printf("%s: does not exist\n", path);
1372 solar 1.164 return 1;
1373 vapier 1.39 }
1374 solar 1.11
1375 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1376 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1377 solar 1.164 return scanelf_file(path, &st_top);
1378 vapier 1.10 }
1379    
1380     /* now scan the dir looking for fun stuff */
1381     if ((dir = opendir(path)) == NULL) {
1382     warnf("could not opendir %s: %s", path, strerror(errno));
1383 solar 1.164 return 1;
1384 vapier 1.10 }
1385 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1386 solar 1.11
1387 vapier 1.32 pathlen = strlen(path);
1388 vapier 1.10 while ((dentry = readdir(dir))) {
1389     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1390     continue;
1391 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1392     if (len >= sizeof(buf)) {
1393 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1394     (unsigned long)len, (unsigned long)sizeof(buf));
1395 vapier 1.32 continue;
1396     }
1397 solar 1.143 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1398 solar 1.20 if (lstat(buf, &st) != -1) {
1399 vapier 1.10 if (S_ISREG(st.st_mode))
1400 solar 1.164 ret = scanelf_file(buf, &st);
1401 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1402 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1403 solar 1.164 ret = scanelf_dir(buf);
1404 vapier 1.10 }
1405     }
1406     }
1407     closedir(dir);
1408 solar 1.164 return ret;
1409 solar 1.1 }
1410    
1411 vapier 1.133 static int scanelf_from_file(const char *filename)
1412 vapier 1.47 {
1413 solar 1.45 FILE *fp = NULL;
1414     char *p;
1415 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1416 solar 1.164 int ret = 0;
1417 solar 1.45
1418 solar 1.132 if (strcmp(filename, "-") == 0)
1419 solar 1.45 fp = stdin;
1420     else if ((fp = fopen(filename, "r")) == NULL)
1421     return 1;
1422    
1423 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1424 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1425     *p = 0;
1426 vapier 1.66 search_path = path;
1427 solar 1.164 ret = scanelf_dir(path);
1428 solar 1.45 }
1429     if (fp != stdin)
1430     fclose(fp);
1431 solar 1.164 return ret;
1432 solar 1.45 }
1433    
1434 solar 1.154 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1435 vapier 1.148
1436     static int load_ld_cache_config(int i, const char *fname)
1437 vapier 1.48 {
1438     FILE *fp = NULL;
1439     char *p;
1440 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1441 vapier 1.48
1442 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1443 solar 1.123 return i;
1444    
1445     if ((fp = fopen(fname, "r")) == NULL)
1446     return i;
1447 vapier 1.48
1448 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1449 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1450     *p = 0;
1451     if ((p = strchr(path, '\n')) != NULL)
1452     *p = 0;
1453 solar 1.154 #ifdef __linux__
1454 solar 1.123 // recursive includes of the same file will make this segfault.
1455 solar 1.129 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1456 solar 1.123 glob64_t gl;
1457     size_t x;
1458     char gpath[__PAX_UTILS_PATH_MAX];
1459    
1460 solar 1.129 memset(gpath, 0, sizeof(gpath));
1461 solar 1.123
1462     if (path[8] != '/')
1463 solar 1.129 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1464 solar 1.123 else
1465 solar 1.129 strncpy(gpath, &path[8], sizeof(gpath));
1466 solar 1.123
1467     if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1468     for (x = 0; x < gl.gl_pathc; ++x) {
1469     /* try to avoid direct loops */
1470     if (strcmp(gl.gl_pathv[x], fname) == 0)
1471     continue;
1472 vapier 1.148 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1473 vapier 1.149 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1474 solar 1.123 globfree64(&gl);
1475     return i;
1476     }
1477     }
1478     globfree64 (&gl);
1479     continue;
1480 solar 1.160 }
1481 solar 1.123 }
1482 solar 1.154 #endif
1483 solar 1.123 if (*path != '/')
1484     continue;
1485 vapier 1.48
1486     ldpaths[i++] = xstrdup(path);
1487    
1488 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1489 vapier 1.48 break;
1490     }
1491     ldpaths[i] = NULL;
1492    
1493     fclose(fp);
1494 solar 1.123 return i;
1495 vapier 1.48 }
1496 flameeyes 1.141
1497 vapier 1.148 #elif defined(__FreeBSD__) || (__DragonFly__)
1498    
1499     static int load_ld_cache_config(int i, const char *fname)
1500 flameeyes 1.141 {
1501     FILE *fp = NULL;
1502     char *b = NULL, *p;
1503     struct elfhints_hdr hdr;
1504 vapier 1.152
1505 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1506 flameeyes 1.141 return i;
1507    
1508     if ((fp = fopen(fname, "r")) == NULL)
1509     return i;
1510    
1511 vapier 1.152 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1512     hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1513     fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1514     {
1515 flameeyes 1.141 fclose(fp);
1516     return i;
1517     }
1518 vapier 1.152
1519 flameeyes 1.141 b = (char*)malloc(hdr.dirlistlen+1);
1520 vapier 1.152 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1521 flameeyes 1.141 fclose(fp);
1522     free(b);
1523     return i;
1524     }
1525 vapier 1.152
1526     while ((p = strsep(&b, ":"))) {
1527     if (*p == '\0') continue;
1528 flameeyes 1.141 ldpaths[i++] = xstrdup(p);
1529 vapier 1.152
1530 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1531 flameeyes 1.141 break;
1532     }
1533     ldpaths[i] = NULL;
1534 vapier 1.157
1535 flameeyes 1.141 free(b);
1536     fclose(fp);
1537     return i;
1538     }
1539 vapier 1.148
1540     #else
1541    
1542     #warning Cache config support not implemented for your target
1543     static int load_ld_cache_config(int i, const char *fname)
1544     {
1545     memset(ldpaths, 0x00, sizeof(ldpaths));
1546     }
1547    
1548 flameeyes 1.141 #endif
1549 vapier 1.48
1550 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1551 vapier 1.184 static void scanelf_ldpath(void)
1552 vapier 1.10 {
1553 vapier 1.17 char scan_l, scan_ul, scan_ull;
1554 vapier 1.48 int i = 0;
1555 vapier 1.10
1556 vapier 1.48 if (!ldpaths[0])
1557     err("Unable to load any paths from ld.so.conf");
1558 vapier 1.10
1559 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1560    
1561 vapier 1.48 while (ldpaths[i]) {
1562     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1563     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1564     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1565     scanelf_dir(ldpaths[i]);
1566     ++i;
1567     }
1568 vapier 1.10
1569 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1570     if (!scan_ul) scanelf_dir("/usr/lib");
1571     if (!scan_ull) scanelf_dir("/usr/local/lib");
1572 vapier 1.10 }
1573 solar 1.1
1574 vapier 1.10 /* scan env PATH for paths */
1575 vapier 1.184 static void scanelf_envpath(void)
1576 solar 1.1 {
1577 solar 1.34 char *path, *p;
1578 vapier 1.10
1579     path = getenv("PATH");
1580     if (!path)
1581     err("PATH is not set in your env !");
1582 vapier 1.41 path = xstrdup(path);
1583 vapier 1.10
1584     while ((p = strrchr(path, ':')) != NULL) {
1585     scanelf_dir(p + 1);
1586     *p = 0;
1587     }
1588 vapier 1.17
1589 solar 1.34 free(path);
1590 solar 1.1 }
1591    
1592 solar 1.181
1593     /* usage / invocation handling functions */ /* Free Flags: c d j u w C G H I J K P Q U W Y Z */
1594     #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DO:BhV"
1595 vapier 1.27 #define a_argument required_argument
1596 vapier 1.10 static struct option const long_opts[] = {
1597     {"path", no_argument, NULL, 'p'},
1598     {"ldpath", no_argument, NULL, 'l'},
1599     {"recursive", no_argument, NULL, 'R'},
1600 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1601 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1602 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1603     {"ldcache", no_argument, NULL, 'L'},
1604 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1605 solar 1.127 {"setpax", a_argument, NULL, 'z'},
1606 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1607 solar 1.16 {"header", no_argument, NULL, 'e'},
1608 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1609     {"rpath", no_argument, NULL, 'r'},
1610 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1611 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1612 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1613 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1614 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1615 solar 1.124 {"section", a_argument, NULL, 'k'},
1616 vapier 1.76 {"lib", a_argument, NULL, 'N'},
1617 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1618 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1619 solar 1.119 {"etype", a_argument, NULL, 'E'},
1620 solar 1.120 {"bits", a_argument, NULL, 'M'},
1621 solar 1.181 {"endian", no_argument, NULL, 'D'},
1622 solar 1.180 {"perms", a_argument, NULL, 'O'},
1623 vapier 1.10 {"all", no_argument, NULL, 'a'},
1624     {"quiet", no_argument, NULL, 'q'},
1625 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1626 vapier 1.76 {"format", a_argument, NULL, 'F'},
1627     {"from", a_argument, NULL, 'f'},
1628     {"file", a_argument, NULL, 'o'},
1629 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1630 vapier 1.10 {"help", no_argument, NULL, 'h'},
1631     {"version", no_argument, NULL, 'V'},
1632     {NULL, no_argument, NULL, 0x0}
1633     };
1634 solar 1.57
1635 solar 1.68 static const char *opts_help[] = {
1636 vapier 1.10 "Scan all directories in PATH environment",
1637     "Scan all directories in /etc/ld.so.conf",
1638 vapier 1.14 "Scan directories recursively",
1639 vapier 1.37 "Don't recursively cross mount points",
1640 vapier 1.101 "Don't scan symlinks",
1641 vapier 1.105 "Scan archives (.a files)",
1642     "Utilize ld.so.cache information (use with -r/-n)",
1643 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
1644     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1645 vapier 1.10 "Print PaX markings",
1646 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1647 vapier 1.10 "Print TEXTREL information",
1648     "Print RPATH information",
1649 vapier 1.32 "Print NEEDED information",
1650 vapier 1.38 "Print INTERP information",
1651 vapier 1.49 "Print BIND information",
1652 vapier 1.84 "Print SONAME information",
1653 vapier 1.27 "Find a specified symbol",
1654 solar 1.124 "Find a specified section",
1655 vapier 1.72 "Find a specified library",
1656 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1657 vapier 1.76 "Locate cause of TEXTREL",
1658 solar 1.129 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1659 solar 1.120 "Print only ELF files matching numeric bits",
1660 solar 1.181 "Print Endianness",
1661 solar 1.180 "Print only ELF files matching octal permissions",
1662 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1663 vapier 1.14 "Only output 'bad' things",
1664     "Be verbose (can be specified more than once)",
1665 vapier 1.39 "Use specified format for output",
1666 solar 1.45 "Read input stream from a filename",
1667 vapier 1.24 "Write output stream to a filename",
1668 vapier 1.14 "Don't display the header",
1669 vapier 1.10 "Print this help and exit",
1670     "Print version and exit",
1671     NULL
1672     };
1673    
1674     /* display usage and exit */
1675     static void usage(int status)
1676 solar 1.1 {
1677 vapier 1.44 unsigned long i;
1678 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1679 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1680 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1681 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1682 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1683 vapier 1.157 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1684 vapier 1.27 long_opts[i].name, opts_help[i]);
1685     else
1686 solar 1.124 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1687 vapier 1.27 long_opts[i].name, opts_help[i]);
1688 solar 1.45
1689 vapier 1.173 puts("\nFor more information, see the scanelf(1) manpage");
1690 vapier 1.10 exit(status);
1691 solar 1.1 }
1692    
1693     /* parse command line arguments and preform needed actions */
1694 vapier 1.165 #define do_pax_state(option, flag) \
1695     if (islower(option)) { \
1696     flags &= ~PF_##flag; \
1697     flags |= PF_NO##flag; \
1698     } else { \
1699     flags &= ~PF_NO##flag; \
1700     flags |= PF_##flag; \
1701     }
1702 solar 1.164 static int parseargs(int argc, char *argv[])
1703 vapier 1.10 {
1704 vapier 1.48 int i;
1705 vapier 1.133 const char *from_file = NULL;
1706 solar 1.164 int ret = 0;
1707 vapier 1.10
1708     opterr = 0;
1709 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1710     switch (i) {
1711 vapier 1.10
1712 vapier 1.39 case 'V':
1713 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1714     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1715     VERSION, __FILE__, __DATE__, rcsid, argv0);
1716 vapier 1.10 exit(EXIT_SUCCESS);
1717     break;
1718     case 'h': usage(EXIT_SUCCESS); break;
1719 solar 1.45 case 'f':
1720 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1721     from_file = optarg;
1722 solar 1.45 break;
1723 solar 1.119 case 'E':
1724     strncpy(match_etypes, optarg, sizeof(match_etypes));
1725     break;
1726 solar 1.120 case 'M':
1727     match_bits = atoi(optarg);
1728 solar 1.182 if (match_bits == 0) {
1729     if (strcmp(optarg, "ELFCLASS32") == 0)
1730     match_bits = 32;
1731     if (strcmp(optarg, "ELFCLASS64") == 0)
1732     match_bits = 64;
1733     }
1734 solar 1.120 break;
1735 solar 1.180 case 'O':
1736     if (sscanf(optarg, "%o", &match_perms) == (-1))
1737     match_bits = 0;
1738     break;
1739 vapier 1.24 case 'o': {
1740 vapier 1.146 if (freopen(optarg, "w", stdout) == NULL)
1741 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1742 solar 1.21 break;
1743     }
1744 solar 1.124 case 'k':
1745 vapier 1.126 if (find_section) warn("You prob don't want to specify -k twice");
1746 solar 1.124 find_section = optarg;
1747     break;
1748 vapier 1.39 case 's': {
1749 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1750     find_sym = optarg;
1751     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1752 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1753     break;
1754     }
1755 vapier 1.72 case 'N': {
1756 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1757     find_lib = optarg;
1758 vapier 1.72 break;
1759     }
1760 vapier 1.39
1761     case 'F': {
1762 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1763     out_format = optarg;
1764 vapier 1.39 break;
1765     }
1766 solar 1.127 case 'z': {
1767 solar 1.129 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1768 solar 1.127 size_t x;
1769 vapier 1.27
1770 solar 1.127 for (x = 0 ; x < strlen(optarg); x++) {
1771     switch(optarg[x]) {
1772     case 'p':
1773     case 'P':
1774 vapier 1.165 do_pax_state(optarg[x], PAGEEXEC);
1775 solar 1.127 break;
1776     case 's':
1777     case 'S':
1778 vapier 1.165 do_pax_state(optarg[x], SEGMEXEC);
1779 solar 1.127 break;
1780     case 'm':
1781     case 'M':
1782 vapier 1.165 do_pax_state(optarg[x], MPROTECT);
1783 solar 1.127 break;
1784     case 'e':
1785     case 'E':
1786 vapier 1.165 do_pax_state(optarg[x], EMUTRAMP);
1787 solar 1.127 break;
1788     case 'r':
1789     case 'R':
1790 vapier 1.165 do_pax_state(optarg[x], RANDMMAP);
1791 solar 1.127 break;
1792     case 'x':
1793     case 'X':
1794 vapier 1.165 do_pax_state(optarg[x], RANDEXEC);
1795 solar 1.127 break;
1796     default:
1797     break;
1798     }
1799     }
1800     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1801     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1802     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1803     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1804     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1805     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1806     setpax = flags;
1807     break;
1808     }
1809 solar 1.176 case 'g': g_match = 1; break;
1810 vapier 1.102 case 'L': use_ldcache = 1; break;
1811 vapier 1.37 case 'y': scan_symlink = 0; break;
1812 vapier 1.105 case 'A': scan_archives = 1; break;
1813 solar 1.16 case 'B': show_banner = 0; break;
1814 vapier 1.10 case 'l': scan_ldpath = 1; break;
1815     case 'p': scan_envpath = 1; break;
1816     case 'R': dir_recurse = 1; break;
1817 vapier 1.14 case 'm': dir_crossmount = 0; break;
1818 vapier 1.101 case 'X': ++fix_elf; break;
1819 vapier 1.10 case 'x': show_pax = 1; break;
1820 solar 1.73 case 'e': show_phdr = 1; break;
1821 vapier 1.10 case 't': show_textrel = 1; break;
1822     case 'r': show_rpath = 1; break;
1823 vapier 1.32 case 'n': show_needed = 1; break;
1824 vapier 1.38 case 'i': show_interp = 1; break;
1825 vapier 1.49 case 'b': show_bind = 1; break;
1826 vapier 1.84 case 'S': show_soname = 1; break;
1827 vapier 1.76 case 'T': show_textrels = 1; break;
1828 vapier 1.10 case 'q': be_quiet = 1; break;
1829 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1830 solar 1.183 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1831 solar 1.181 case 'D': show_endian = 1; break;
1832 vapier 1.10 case ':':
1833 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1834 vapier 1.10 case '?':
1835 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1836 vapier 1.10 default:
1837 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1838 vapier 1.10 }
1839     }
1840 solar 1.170 if (show_textrels && be_verbose) {
1841     if (which("objdump") != NULL)
1842     has_objdump = 1;
1843     }
1844 vapier 1.39 /* let the format option override all other options */
1845     if (out_format) {
1846 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1847 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1848 solar 1.181 show_textrels = show_perms = show_endian = 0;
1849 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1850 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1851 vapier 1.39
1852 vapier 1.48 switch (out_format[++i]) {
1853 solar 1.132 case '+': break;
1854 vapier 1.39 case '%': break;
1855 vapier 1.70 case '#': break;
1856 vapier 1.39 case 'F': break;
1857 vapier 1.66 case 'p': break;
1858     case 'f': break;
1859 solar 1.124 case 'k': break;
1860 vapier 1.39 case 's': break;
1861 vapier 1.72 case 'N': break;
1862 vapier 1.41 case 'o': break;
1863 vapier 1.166 case 'a': break;
1864 vapier 1.171 case 'M': break;
1865 solar 1.181 case 'D': show_endian = 1; break;
1866 solar 1.180 case 'O': show_perms = 1; break;
1867 vapier 1.39 case 'x': show_pax = 1; break;
1868 solar 1.73 case 'e': show_phdr = 1; break;
1869 vapier 1.39 case 't': show_textrel = 1; break;
1870     case 'r': show_rpath = 1; break;
1871     case 'n': show_needed = 1; break;
1872     case 'i': show_interp = 1; break;
1873 vapier 1.49 case 'b': show_bind = 1; break;
1874 vapier 1.84 case 'S': show_soname = 1; break;
1875 vapier 1.76 case 'T': show_textrels = 1; break;
1876 vapier 1.39 default:
1877 vapier 1.162 err("Invalid format specifier '%c' (byte %i)",
1878 vapier 1.48 out_format[i], i+1);
1879 vapier 1.39 }
1880     }
1881 vapier 1.41
1882     /* construct our default format */
1883     } else {
1884     size_t fmt_len = 30;
1885     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1886 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1887     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1888 solar 1.180 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1889 solar 1.181 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1890 vapier 1.76 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1891     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1892     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1893     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1894     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1895     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1896 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1897 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1898     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1899 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1900 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1901     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1902 vapier 1.39 }
1903 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1904 vapier 1.39
1905     /* now lets actually do the scanning */
1906 vapier 1.102 if (scan_ldpath || use_ldcache)
1907 vapier 1.148 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1908 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1909     if (scan_envpath) scanelf_envpath();
1910 solar 1.153 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1911 vapier 1.133 from_file = "-";
1912 solar 1.45 if (from_file) {
1913     scanelf_from_file(from_file);
1914     from_file = *argv;
1915     }
1916     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1917 vapier 1.25 err("Nothing to scan !?");
1918 vapier 1.66 while (optind < argc) {
1919     search_path = argv[optind++];
1920 solar 1.164 ret = scanelf_dir(search_path);
1921 vapier 1.66 }
1922 vapier 1.27
1923 vapier 1.39 /* clean up */
1924 vapier 1.152 free(versioned_symname);
1925 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1926     free(ldpaths[i]);
1927 solar 1.96
1928     if (ldcache != 0)
1929     munmap(ldcache, ldcache_size);
1930 solar 1.164 return ret;
1931 vapier 1.10 }
1932    
1933 vapier 1.150 static char **get_split_env(const char *envvar)
1934     {
1935 vapier 1.152 const char *delims = " \t\n";
1936 solar 1.143 char **envvals = NULL;
1937 vapier 1.152 char *env, *s;
1938 kevquinn 1.142 int nentry;
1939    
1940 solar 1.143 if ((env = getenv(envvar)) == NULL)
1941     return NULL;
1942 kevquinn 1.142
1943 solar 1.143 env = xstrdup(env);
1944     if (env == NULL)
1945     return NULL;
1946 kevquinn 1.142
1947 vapier 1.152 s = strtok(env, delims);
1948     if (s == NULL) {
1949     free(env);
1950     return NULL;
1951     }
1952    
1953 solar 1.143 nentry = 0;
1954 vapier 1.152 while (s != NULL) {
1955     ++nentry;
1956     envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1957     envvals[nentry-1] = s;
1958     s = strtok(NULL, delims);
1959 kevquinn 1.142 }
1960 vapier 1.152 envvals[nentry] = NULL;
1961 kevquinn 1.142
1962 vapier 1.152 /* don't want to free(env) as it contains the memory that backs
1963     * the envvals array of strings */
1964 kevquinn 1.142 return envvals;
1965     }
1966 solar 1.181
1967 vapier 1.184 static void parseenv(void)
1968 vapier 1.150 {
1969     qa_textrels = get_split_env("QA_TEXTRELS");
1970     qa_execstack = get_split_env("QA_EXECSTACK");
1971     qa_wx_load = get_split_env("QA_WX_LOAD");
1972 vapier 1.41 }
1973 solar 1.163
1974 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1975 vapier 1.184 static void cleanup(void)
1976 vapier 1.152 {
1977     free(out_format);
1978     free(qa_textrels);
1979     free(qa_execstack);
1980     free(qa_wx_load);
1981     }
1982     #endif
1983 vapier 1.41
1984    
1985 vapier 1.10 int main(int argc, char *argv[])
1986 solar 1.1 {
1987 solar 1.164 int ret;
1988 vapier 1.10 if (argc < 2)
1989     usage(EXIT_FAILURE);
1990 kevquinn 1.142 parseenv();
1991 solar 1.164 ret = parseargs(argc, argv);
1992 solar 1.21 fclose(stdout);
1993 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1994     cleanup();
1995     warn("The calls to add/delete heap should be off:\n"
1996     "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1997     "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1998 solar 1.61 #endif
1999 solar 1.164 return ret;
2000 solar 1.1 }
2001 vapier 1.155
2002    
2003    
2004     /* utility funcs */
2005     static char *xstrdup(const char *s)
2006     {
2007     char *ret = strdup(s);
2008     if (!ret) err("Could not strdup(): %s", strerror(errno));
2009     return ret;
2010     }
2011     static void *xmalloc(size_t size)
2012     {
2013     void *ret = malloc(size);
2014     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
2015     return ret;
2016     }
2017     static void *xrealloc(void *ptr, size_t size)
2018     {
2019     void *ret = realloc(ptr, size);
2020     if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
2021     return ret;
2022     }
2023     static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
2024     {
2025     size_t new_len;
2026    
2027     new_len = strlen(*dst) + strlen(src);
2028     if (*curr_len <= new_len) {
2029     *curr_len = new_len + (*curr_len / 2);
2030     *dst = realloc(*dst, *curr_len);
2031     if (!*dst)
2032     err("could not realloc() %li bytes", (unsigned long)*curr_len);
2033     }
2034    
2035     if (n)
2036     strncat(*dst, src, n);
2037     else
2038     strcat(*dst, src);
2039     }
2040     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
2041     {
2042     static char my_app[2];
2043     my_app[0] = append;
2044     my_app[1] = '\0';
2045     xstrcat(dst, my_app, curr_len);
2046     }
2047    
2048     /* Match filename against entries in matchlist, return TRUE
2049     * if the file is listed */
2050     static int file_matches_list(const char *filename, char **matchlist)
2051     {
2052     char **file;
2053     char *match;
2054     char buf[__PAX_UTILS_PATH_MAX];
2055    
2056     if (matchlist == NULL)
2057     return 0;
2058    
2059     for (file = matchlist; *file != NULL; file++) {
2060     if (search_path) {
2061     snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2062     match = buf;
2063     } else {
2064     match = *file;
2065     }
2066     if (fnmatch(match, filename, 0) == 0)
2067     return 1;
2068     }
2069     return 0;
2070     }

  ViewVC Help
Powered by ViewVC 1.1.20