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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.269 - (hide annotations) (download) (as text)
Thu Nov 20 01:25:56 2014 UTC (5 weeks ago) by vapier
Branch: MAIN
CVS Tags: HEAD
Changes since 1.268: +4 -2 lines
File MIME type: text/x-csrc
scanelf: add a note in the rpath warning when we fix the ELF automatically #334819 by Dennis Schridde

1 solar 1.1 /*
2 vapier 1.247 * Copyright 2003-2012 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 vapier 1.269 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.268 2014/11/05 02:02:03 vapier Exp $
5 solar 1.1 *
6 vapier 1.247 * Copyright 2003-2012 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2012 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.269 static const char rcsid[] = "$Id: scanelf.c,v 1.268 2014/11/05 02:02:03 vapier Exp $";
11 vapier 1.220 const char argv0[] = "scanelf";
12 vapier 1.186
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.10
20     /* variables to control behavior */
21 vapier 1.262 static array_t _match_etypes = array_init_decl, *match_etypes = &_match_etypes;
22 vapier 1.227 static array_t _ldpaths = array_init_decl, *ldpaths = &_ldpaths;
23 vapier 1.10 static char scan_ldpath = 0;
24     static char scan_envpath = 0;
25 vapier 1.37 static char scan_symlink = 1;
26 vapier 1.105 static char scan_archives = 0;
27 vapier 1.10 static char dir_recurse = 0;
28 vapier 1.14 static char dir_crossmount = 1;
29 vapier 1.10 static char show_pax = 0;
30 solar 1.180 static char show_perms = 0;
31 solar 1.190 static char show_size = 0;
32 solar 1.73 static char show_phdr = 0;
33 vapier 1.10 static char show_textrel = 0;
34     static char show_rpath = 0;
35 vapier 1.32 static char show_needed = 0;
36 vapier 1.38 static char show_interp = 0;
37 vapier 1.49 static char show_bind = 0;
38 vapier 1.84 static char show_soname = 0;
39 vapier 1.76 static char show_textrels = 0;
40 solar 1.16 static char show_banner = 1;
41 solar 1.181 static char show_endian = 0;
42 solar 1.191 static char show_osabi = 0;
43     static char show_eabi = 0;
44 vapier 1.10 static char be_quiet = 0;
45 vapier 1.14 static char be_verbose = 0;
46 solar 1.127 static char be_wewy_wewy_quiet = 0;
47 solar 1.132 static char be_semi_verbose = 0;
48 flameeyes 1.198 static char *find_sym = NULL;
49 vapier 1.248 static array_t _find_sym_arr = array_init_decl, *find_sym_arr = &_find_sym_arr;
50 vapier 1.249 static array_t _find_sym_regex_arr = array_init_decl, *find_sym_regex_arr = &_find_sym_regex_arr;
51 vapier 1.72 static char *find_lib = NULL;
52 vapier 1.226 static array_t _find_lib_arr = array_init_decl, *find_lib_arr = &_find_lib_arr;
53 solar 1.124 static char *find_section = NULL;
54 vapier 1.226 static array_t _find_section_arr = array_init_decl, *find_section_arr = &_find_section_arr;
55 vapier 1.39 static char *out_format = NULL;
56 vapier 1.66 static char *search_path = NULL;
57 vapier 1.101 static char fix_elf = 0;
58 solar 1.176 static char g_match = 0;
59 vapier 1.102 static char use_ldcache = 0;
60 vapier 1.240 static char use_ldpath = 0;
61 solar 1.1
62 kevquinn 1.142 static char **qa_textrels = NULL;
63     static char **qa_execstack = NULL;
64 kevquinn 1.145 static char **qa_wx_load = NULL;
65 vapier 1.232 static int root_fd = AT_FDCWD;
66 kevquinn 1.142
67 vapier 1.203 static int match_bits = 0;
68     static unsigned int match_perms = 0;
69 vapier 1.212 static void *ldcache = NULL;
70 vapier 1.203 static size_t ldcache_size = 0;
71     static unsigned long setpax = 0UL;
72 solar 1.96
73 vapier 1.264 static const char *objdump;
74 solar 1.175
75 vapier 1.265 /* Find the path to a file by name. Note: we do not currently handle the
76     * empty path element correctly (should behave by searching $PWD). */
77 vapier 1.264 static const char *which(const char *fname, const char *envvar)
78 solar 1.170 {
79 vapier 1.264 size_t path_len, fname_len;
80     const char *env_path;
81     char *path, *p, *ep;
82    
83     p = getenv(envvar);
84     if (p)
85     return p;
86    
87     env_path = getenv("PATH");
88     if (!env_path)
89     return NULL;
90    
91     /* Create a copy of the $PATH that we can safely modify.
92     * Make it a little bigger so we can append "/fname".
93     * We do this twice -- once for a perm copy, and once for
94     * room at the end of the last element. */
95     path_len = strlen(env_path);
96     fname_len = strlen(fname);
97     path = xmalloc(path_len + (fname_len * 2) + 2 + 2);
98     memcpy(path, env_path, path_len + 1);
99    
100     p = path + path_len + 1 + fname_len + 1;
101     *p = '/';
102     memcpy(p + 1, fname, fname_len + 1);
103    
104     /* Repoint fname to the copy in the env string as it has
105     * the leading slash which we can include in a single memcpy.
106     * Increase the fname len to include the '/' and '\0'. */
107     fname = p;
108     fname_len += 2;
109    
110     p = path;
111     while (p) {
112     ep = strchr(p, ':');
113     /* Append the /foo path to the current element. */
114     if (ep)
115     memcpy(ep, fname, fname_len);
116     else
117     memcpy(path + path_len, fname, fname_len);
118 solar 1.170
119 vapier 1.264 if (access(p, R_OK) != -1)
120     return p;
121 solar 1.170
122 vapier 1.264 p = ep;
123     if (ep) {
124     /* If not the last element, restore the chunk we clobbered. */
125     size_t offset = ep - path;
126     size_t restore = min(path_len - offset, fname_len);
127     memcpy(ep, env_path + offset, restore);
128     ++p;
129     }
130 vapier 1.172 }
131 vapier 1.230
132 vapier 1.264 free(path);
133     return NULL;
134 solar 1.170 }
135 vapier 1.152
136 vapier 1.232 static FILE *fopenat_r(int dir_fd, const char *path)
137     {
138     int fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
139     if (fd == -1)
140     return NULL;
141     return fdopen(fd, "re");
142     }
143    
144     static const char *root_rel_path(const char *path)
145     {
146     /*
147     * openat() will ignore the dirfd if path starts with
148     * a /, so consume all of that noise
149     *
150     * XXX: we don't handle relative paths like ../ that
151     * break out of the --root option, but for now, just
152     * don't do that :P.
153     */
154     if (root_fd != AT_FDCWD) {
155     while (*path == '/')
156     ++path;
157     if (*path == '\0')
158     path = ".";
159     }
160    
161     return path;
162     }
163    
164     /* sub-funcs for scanelf_fileat() */
165 vapier 1.234 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
166 vapier 1.77 {
167     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
168 vapier 1.213
169     /* debug sections */
170     void *symtab = elf_findsecbyname(elf, ".symtab");
171     void *strtab = elf_findsecbyname(elf, ".strtab");
172     /* runtime sections */
173     void *dynsym = elf_findsecbyname(elf, ".dynsym");
174     void *dynstr = elf_findsecbyname(elf, ".dynstr");
175    
176 vapier 1.244 /*
177     * If the sections are marked NOBITS, then they don't exist, so we just
178     * skip them. This let's us work sanely with splitdebug ELFs (rather
179     * than spewing a lot of "corrupt ELF" messages later on). In malformed
180     * ELFs, the section might be wrongly set to NOBITS, but screw em.
181 vapier 1.267 *
182     * We need to make sure the debug/runtime sym/str sets are used together
183     * as they are generated in sync. Trying to mix them won't work.
184 vapier 1.244 */
185 vapier 1.77 #define GET_SYMTABS(B) \
186     if (elf->elf_class == ELFCLASS ## B) { \
187 vapier 1.244 Elf ## B ## _Shdr *esymtab = symtab; \
188     Elf ## B ## _Shdr *estrtab = strtab; \
189     Elf ## B ## _Shdr *edynsym = dynsym; \
190     Elf ## B ## _Shdr *edynstr = dynstr; \
191     \
192     if (symtab && EGET(esymtab->sh_type) == SHT_NOBITS) \
193     symtab = NULL; \
194     if (dynsym && EGET(edynsym->sh_type) == SHT_NOBITS) \
195     dynsym = NULL; \
196     if (strtab && EGET(estrtab->sh_type) == SHT_NOBITS) \
197     strtab = NULL; \
198     if (dynstr && EGET(edynstr->sh_type) == SHT_NOBITS) \
199     dynstr = NULL; \
200 vapier 1.267 \
201     /* Use the set with more symbols if both exist. */ \
202     if (symtab && dynsym && strtab && dynstr) { \
203     if (EGET(esymtab->sh_size) > EGET(edynsym->sh_size)) \
204     goto debug##B; \
205     else \
206     goto runtime##B; \
207     } else if (symtab && strtab) { \
208     debug##B: \
209     *sym = symtab; \
210     *str = strtab; \
211     return; \
212     } else if (dynsym && dynstr) { \
213     runtime##B: \
214     *sym = dynsym; \
215     *str = dynstr; \
216     return; \
217 vapier 1.268 } else { \
218     *sym = *str = NULL; \
219 vapier 1.267 } \
220 vapier 1.77 }
221     GET_SYMTABS(32)
222     GET_SYMTABS(64)
223 vapier 1.234
224     if (*sym && *str)
225     return;
226    
227     /*
228     * damn, they're really going to make us work for it huh?
229     * reconstruct the section header info out of the dynamic
230     * tags so we can see what symbols this guy uses at runtime.
231     */
232     #define GET_SYMTABS_DT(B) \
233     if (elf->elf_class == ELFCLASS ## B) { \
234     size_t i; \
235     static Elf ## B ## _Shdr sym_shdr, str_shdr; \
236     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
237     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
238     Elf ## B ## _Addr vsym, vstr, vhash, vgnu_hash; \
239     Elf ## B ## _Dyn *dyn; \
240     Elf ## B ## _Off offset; \
241     \
242     /* lookup symbols used at runtime with DT_SYMTAB / DT_STRTAB */ \
243     vsym = vstr = vhash = vgnu_hash = 0; \
244     memset(&sym_shdr, 0, sizeof(sym_shdr)); \
245     memset(&str_shdr, 0, sizeof(str_shdr)); \
246     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
247     if (EGET(phdr[i].p_type) != PT_DYNAMIC) \
248     continue; \
249     \
250     offset = EGET(phdr[i].p_offset); \
251     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) \
252     continue; \
253     \
254     dyn = DYN ## B (elf->vdata + offset); \
255     while (EGET(dyn->d_tag) != DT_NULL) { \
256     switch (EGET(dyn->d_tag)) { \
257     case DT_SYMTAB: vsym = EGET(dyn->d_un.d_val); break; \
258     case DT_SYMENT: sym_shdr.sh_entsize = dyn->d_un.d_val; break; \
259     case DT_STRTAB: vstr = EGET(dyn->d_un.d_val); break; \
260     case DT_STRSZ: str_shdr.sh_size = dyn->d_un.d_val; break; \
261     case DT_HASH: vhash = EGET(dyn->d_un.d_val); break; \
262     /*case DT_GNU_HASH: vgnu_hash = EGET(dyn->d_un.d_val); break;*/ \
263     } \
264     ++dyn; \
265     } \
266     if (vsym && vstr) \
267     break; \
268     } \
269     if (!vsym || !vstr || !(vhash || vgnu_hash)) \
270     return; \
271     \
272     /* calc offset into the ELF by finding the load addr of the syms */ \
273     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
274     Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \
275     Elf ## B ## _Addr filesz = EGET(phdr[i].p_filesz); \
276     offset = EGET(phdr[i].p_offset); \
277     \
278     if (EGET(phdr[i].p_type) != PT_LOAD) \
279     continue; \
280     \
281     if (vhash >= vaddr && vhash < vaddr + filesz) { \
282     /* Scan the hash table to see how many entries we have */ \
283     Elf32_Word max_sym_idx = 0; \
284     Elf32_Word *hashtbl = elf->vdata + offset + (vhash - vaddr); \
285     Elf32_Word b, nbuckets = EGET(hashtbl[0]); \
286     Elf32_Word nchains = EGET(hashtbl[1]); \
287     Elf32_Word *buckets = &hashtbl[2]; \
288     Elf32_Word *chains = &buckets[nbuckets]; \
289     Elf32_Word sym_idx; \
290     \
291     for (b = 0; b < nbuckets; ++b) { \
292     if (!buckets[b]) \
293     continue; \
294     for (sym_idx = buckets[b]; sym_idx < nchains && sym_idx; sym_idx = chains[sym_idx]) \
295     if (max_sym_idx < sym_idx) \
296     max_sym_idx = sym_idx; \
297     } \
298     ESET(sym_shdr.sh_size, sym_shdr.sh_entsize * max_sym_idx); \
299     } \
300     \
301     if (vsym >= vaddr && vsym < vaddr + filesz) { \
302     ESET(sym_shdr.sh_offset, offset + (vsym - vaddr)); \
303     *sym = &sym_shdr; \
304     } \
305     \
306     if (vstr >= vaddr && vstr < vaddr + filesz) { \
307     ESET(str_shdr.sh_offset, offset + (vstr - vaddr)); \
308     *str = &str_shdr; \
309     } \
310     } \
311     }
312     GET_SYMTABS_DT(32)
313     GET_SYMTABS_DT(64)
314 vapier 1.77 }
315 solar 1.127
316 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
317 solar 1.6 {
318 solar 1.61 static char ret[7];
319     unsigned long i, shown;
320    
321 vapier 1.41 if (!show_pax) return NULL;
322 vapier 1.10
323 solar 1.61 shown = 0;
324     memset(&ret, 0, sizeof(ret));
325    
326     if (elf->phdr) {
327     #define SHOW_PAX(B) \
328     if (elf->elf_class == ELFCLASS ## B) { \
329     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
330     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
331     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
332     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
333     continue; \
334 solar 1.127 if (fix_elf && setpax) { \
335     /* set the paxctl flags */ \
336     ESET(phdr[i].p_flags, setpax); \
337     } \
338 solar 1.129 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
339 solar 1.61 continue; \
340     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
341     *found_pax = 1; \
342     ++shown; \
343     break; \
344     } \
345     }
346     SHOW_PAX(32)
347     SHOW_PAX(64)
348     }
349    
350 vapier 1.242 /* Note: We do not support setting EI_PAX if not PT_PAX_FLAGS
351     * was found. This is known to break ELFs on glibc systems,
352     * and mainline PaX has deprecated use of this for a long time.
353     * We could support changing PT_GNU_STACK, but that doesn't
354     * seem like it's worth the effort. #411919
355     */
356 solar 1.128
357 solar 1.61 /* fall back to EI_PAX if no PT_PAX was found */
358     if (!*ret) {
359 vapier 1.90 static char *paxflags;
360 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
361     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
362     *found_pax = 1;
363 solar 1.127 return (be_wewy_wewy_quiet ? NULL : paxflags);
364 solar 1.61 }
365     strncpy(ret, paxflags, sizeof(ret));
366 vapier 1.14 }
367 vapier 1.41
368 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
369 solar 1.61 return NULL;
370 vapier 1.90 else
371     return ret;
372     }
373 solar 1.61
374 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
375 vapier 1.39 {
376 vapier 1.71 static char ret[12];
377 vapier 1.41 char *found;
378 vapier 1.99 unsigned long i, shown, multi_stack, multi_relro, multi_load;
379 vapier 1.41
380 solar 1.73 if (!show_phdr) return NULL;
381 vapier 1.41
382 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
383    
384 vapier 1.41 shown = 0;
385 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
386 vapier 1.44
387 vapier 1.108 #define NOTE_GNU_STACK ".note.GNU-stack"
388 solar 1.73 #define SHOW_PHDR(B) \
389 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
390     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
391 vapier 1.91 Elf ## B ## _Off offset; \
392     uint32_t flags, check_flags; \
393     if (elf->phdr != NULL) { \
394     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
395     for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
396     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
397 vapier 1.152 if (multi_stack++) \
398     warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
399     if (file_matches_list(elf->filename, qa_execstack)) \
400     continue; \
401     found = found_phdr; \
402     offset = 0; \
403     check_flags = PF_X; \
404 vapier 1.91 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
405 vapier 1.152 if (multi_relro++) \
406     warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
407 vapier 1.91 found = found_relro; \
408     offset = 4; \
409     check_flags = PF_X; \
410     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
411 vapier 1.152 if (file_matches_list(elf->filename, qa_wx_load)) \
412     continue; \
413     found = found_load; \
414     offset = 8; \
415     check_flags = PF_W|PF_X; \
416 vapier 1.91 } else \
417     continue; \
418     flags = EGET(phdr[i].p_flags); \
419     if (be_quiet && ((flags & check_flags) != check_flags)) \
420     continue; \
421 solar 1.130 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
422 vapier 1.101 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
423     ret[3] = ret[7] = '!'; \
424     flags = EGET(phdr[i].p_flags); \
425     } \
426 vapier 1.91 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
427     *found = 1; \
428     ++shown; \
429     } \
430     } else if (elf->shdr != NULL) { \
431     /* no program headers which means this is prob an object file */ \
432     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
433     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
434 vapier 1.108 char *str; \
435 vapier 1.217 if ((void*)strtbl > elf->data_end) \
436 vapier 1.108 goto skip_this_shdr##B; \
437 vapier 1.260 /* let's flag -w/+x object files since the final ELF will most likely \
438     * need write access to the stack (who doesn't !?). so the combined \
439     * output will bring in +w automatically and that's bad. \
440     */ \
441 vapier 1.259 check_flags = /*SHF_WRITE|*/SHF_EXECINSTR; \
442 vapier 1.91 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
443     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
444     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
445 vapier 1.108 str = elf->data + offset; \
446     if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
447     if (!strcmp(str, NOTE_GNU_STACK)) { \
448 vapier 1.91 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
449     flags = EGET(shdr[i].sh_flags); \
450     if (be_quiet && ((flags & check_flags) != check_flags)) \
451     continue; \
452     ++*found_phdr; \
453     shown = 1; \
454     if (flags & SHF_WRITE) ret[0] = 'W'; \
455     if (flags & SHF_ALLOC) ret[1] = 'A'; \
456     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
457     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
458     break; \
459     } \
460     } \
461 vapier 1.108 skip_this_shdr##B: \
462 vapier 1.91 if (!multi_stack) { \
463 vapier 1.158 if (file_matches_list(elf->filename, qa_execstack)) \
464     return NULL; \
465 vapier 1.91 *found_phdr = 1; \
466     shown = 1; \
467     memcpy(ret, "!WX", 3); \
468     } \
469 vapier 1.39 } \
470     }
471 solar 1.73 SHOW_PHDR(32)
472     SHOW_PHDR(64)
473 vapier 1.44
474 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
475 vapier 1.41 return NULL;
476     else
477     return ret;
478 vapier 1.39 }
479 kevquinn 1.142
480 vapier 1.186 /*
481     * See if this ELF contains a DT_TEXTREL tag in any of its
482     * PT_DYNAMIC sections.
483     */
484 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
485 vapier 1.39 {
486 vapier 1.90 static const char *ret = "TEXTREL";
487 vapier 1.44 unsigned long i;
488 vapier 1.41
489 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
490 vapier 1.41
491 kevquinn 1.142 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
492    
493 vapier 1.44 if (elf->phdr) {
494 vapier 1.39 #define SHOW_TEXTREL(B) \
495     if (elf->elf_class == ELFCLASS ## B) { \
496     Elf ## B ## _Dyn *dyn; \
497     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
498     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
499 vapier 1.44 Elf ## B ## _Off offset; \
500 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
501 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
502 vapier 1.44 offset = EGET(phdr[i].p_offset); \
503     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
504 vapier 1.217 dyn = DYN ## B (elf->vdata + offset); \
505 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
506     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
507     *found_textrel = 1; \
508     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
509 solar 1.127 return (be_wewy_wewy_quiet ? NULL : ret); \
510 vapier 1.39 } \
511     ++dyn; \
512 vapier 1.26 } \
513 vapier 1.39 } }
514     SHOW_TEXTREL(32)
515     SHOW_TEXTREL(64)
516 vapier 1.44 }
517    
518 solar 1.127 if (be_quiet || be_wewy_wewy_quiet)
519 vapier 1.41 return NULL;
520     else
521 vapier 1.90 return " - ";
522 vapier 1.39 }
523 solar 1.180
524 vapier 1.186 /*
525     * Scan the .text section to see if there are any relocations in it.
526     * Should rewrite this to check PT_LOAD sections that are marked
527     * Executable rather than the section named '.text'.
528     */
529 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
530 vapier 1.76 {
531 vapier 1.82 unsigned long s, r, rmax;
532     void *symtab_void, *strtab_void, *text_void;
533 vapier 1.76
534     if (!show_textrels) return NULL;
535    
536 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
537     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
538     if (!*found_textrel) return NULL;
539    
540 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
541 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
542 vapier 1.76
543 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
544 vapier 1.76 #define SHOW_TEXTRELS(B) \
545     if (elf->elf_class == ELFCLASS ## B) { \
546     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
547     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
548     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
549     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
550 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
551     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
552     uint ## B ## _t memsz = EGET(text->sh_size); \
553 vapier 1.76 Elf ## B ## _Rel *rel; \
554     Elf ## B ## _Rela *rela; \
555     /* search the section headers for relocations */ \
556     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
557     uint32_t sh_type = EGET(shdr[s].sh_type); \
558     if (sh_type == SHT_REL) { \
559 vapier 1.217 rel = REL ## B (elf->vdata + EGET(shdr[s].sh_offset)); \
560 vapier 1.76 rela = NULL; \
561     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
562     } else if (sh_type == SHT_RELA) { \
563     rel = NULL; \
564 vapier 1.217 rela = RELA ## B (elf->vdata + EGET(shdr[s].sh_offset)); \
565 vapier 1.76 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
566     } else \
567     continue; \
568 vapier 1.82 /* now see if any of the relocs are in the .text */ \
569     for (r = 0; r < rmax; ++r) { \
570     unsigned long sym_max; \
571     Elf ## B ## _Addr offset_tmp; \
572     Elf ## B ## _Sym *func; \
573     Elf ## B ## _Sym *sym; \
574     Elf ## B ## _Addr r_offset; \
575     uint ## B ## _t r_info; \
576     if (sh_type == SHT_REL) { \
577     r_offset = EGET(rel[r].r_offset); \
578     r_info = EGET(rel[r].r_info); \
579     } else { \
580     r_offset = EGET(rela[r].r_offset); \
581     r_info = EGET(rela[r].r_info); \
582     } \
583     /* make sure this relocation is inside of the .text */ \
584     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
585     if (be_verbose <= 2) continue; \
586     } else \
587 vapier 1.78 *found_textrels = 1; \
588 vapier 1.82 /* locate this relocation symbol name */ \
589 vapier 1.217 sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
590     if ((void*)sym > elf->data_end) { \
591 vapier 1.111 warn("%s: corrupt ELF symbol", elf->filename); \
592 vapier 1.109 continue; \
593     } \
594 vapier 1.82 sym_max = ELF ## B ## _R_SYM(r_info); \
595     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
596     sym += sym_max; \
597     else \
598     sym = NULL; \
599     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
600     /* show the raw details about this reloc */ \
601 vapier 1.88 printf(" %s: ", elf->base_filename); \
602 vapier 1.82 if (sym && sym->st_name) \
603 vapier 1.217 printf("%s", elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
604 vapier 1.82 else \
605 vapier 1.169 printf("(memory/data?)"); \
606 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
607     /* now try to find the closest symbol that this rel is probably in */ \
608 vapier 1.217 sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
609 vapier 1.82 func = NULL; \
610     offset_tmp = 0; \
611     while (sym_max--) { \
612     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
613     func = sym; \
614     offset_tmp = EGET(sym->st_value); \
615 vapier 1.76 } \
616 vapier 1.82 ++sym; \
617 vapier 1.76 } \
618 vapier 1.82 printf(" in "); \
619 vapier 1.169 if (func && func->st_name) { \
620     const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
621     if (r_offset > EGET(func->st_size)) \
622     printf("(optimized out: previous %s)", func_name); \
623     else \
624     printf("%s", func_name); \
625     } else \
626     printf("(optimized out)"); \
627 vapier 1.82 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
628 vapier 1.264 if (be_verbose && objdump) { \
629 vapier 1.187 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
630 vapier 1.167 char *sysbuf; \
631     size_t syslen; \
632 vapier 1.264 const char sysfmt[] = "%s -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
633     syslen = sizeof(sysfmt) + strlen(objdump) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
634 vapier 1.167 sysbuf = xmalloc(syslen); \
635 vapier 1.187 if (end_addr < r_offset) \
636     /* not uncommon when things are optimized out */ \
637     end_addr = r_offset + 0x100; \
638     snprintf(sysbuf, syslen, sysfmt, \
639 vapier 1.264 objdump, \
640 vapier 1.187 (unsigned long)offset_tmp, \
641     (unsigned long)end_addr, \
642     elf->filename, \
643     (unsigned long)r_offset); \
644     fflush(stdout); \
645 vapier 1.257 if (system(sysbuf)) {/* don't care */} \
646 vapier 1.187 fflush(stdout); \
647     free(sysbuf); \
648 vapier 1.167 } \
649 vapier 1.76 } \
650     } }
651     SHOW_TEXTRELS(32)
652     SHOW_TEXTRELS(64)
653     }
654 vapier 1.82 if (!*found_textrels)
655     warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
656 vapier 1.76
657     return NULL;
658     }
659 solar 1.83
660 vapier 1.102 static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
661 vapier 1.100 {
662 solar 1.83 struct stat st;
663 vapier 1.84 switch (*item) {
664 vapier 1.89 case '/': break;
665     case '.':
666 vapier 1.102 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
667 vapier 1.89 break;
668 vapier 1.100 case ':':
669 vapier 1.89 case '\0':
670 vapier 1.102 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
671 solar 1.83 break;
672     case '$':
673 vapier 1.84 if (fstat(elf->fd, &st) != -1)
674 solar 1.83 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
675 vapier 1.157 warnf("Security problem with %s='%s' in %s with mode set of %o",
676 solar 1.176 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
677 solar 1.83 break;
678     default:
679 vapier 1.102 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
680 solar 1.83 break;
681     }
682 vapier 1.269 if (fix_elf)
683     warnf("Note: RPATH has been automatically fixed, but this should be fixed in the package itself");
684 solar 1.83 }
685 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
686 vapier 1.39 {
687 vapier 1.227 unsigned long i;
688 vapier 1.48 char *rpath, *runpath, **r;
689 vapier 1.39 void *strtbl_void;
690 vapier 1.10
691 vapier 1.39 if (!show_rpath) return;
692 vapier 1.10
693 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
694     rpath = runpath = NULL;
695 vapier 1.10
696 vapier 1.44 if (elf->phdr && strtbl_void) {
697 vapier 1.26 #define SHOW_RPATH(B) \
698     if (elf->elf_class == ELFCLASS ## B) { \
699     Elf ## B ## _Dyn *dyn; \
700     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
701     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
702     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
703 vapier 1.44 Elf ## B ## _Off offset; \
704 vapier 1.60 Elf ## B ## _Xword word; \
705 vapier 1.48 /* Scan all the program headers */ \
706 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
707 vapier 1.48 /* Just scan dynamic headers */ \
708 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
709 vapier 1.44 offset = EGET(phdr[i].p_offset); \
710     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
711 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
712 vapier 1.217 dyn = DYN ## B (elf->vdata + offset); \
713 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
714     if (word == DT_RPATH) { \
715     r = &rpath; \
716     } else if (word == DT_RUNPATH) { \
717     r = &runpath; \
718     } else { \
719     ++dyn; \
720     continue; \
721     } \
722     /* Verify the memory is somewhat sane */ \
723     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
724 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
725 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
726 vapier 1.217 *r = elf->data + offset; \
727 vapier 1.103 /* cache the length in case we need to nuke this section later on */ \
728     if (fix_elf) \
729     offset = strlen(*r); \
730 vapier 1.48 /* If quiet, don't output paths in ld.so.conf */ \
731 vapier 1.69 if (be_quiet) { \
732     size_t len; \
733     char *start, *end; \
734 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
735     /* since *r is read-only memory, we can only move the ptr forward. */ \
736     start = *r; \
737     /* scan each path in : delimited list */ \
738     while (start) { \
739 vapier 1.102 rpath_security_checks(elf, start, get_elfdtype(word)); \
740 vapier 1.69 end = strchr(start, ':'); \
741 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
742 vapier 1.227 if (use_ldcache) { \
743     size_t n; \
744     const char *ldpath; \
745     array_for_each(ldpaths, n, ldpath) \
746     if (!strncmp(ldpath, start, len) && !ldpath[len]) { \
747 vapier 1.102 *r = end; \
748     /* corner case ... if RPATH reads "/usr/lib:", we want \
749     * to show ':' rather than '' */ \
750     if (end && end[1] != '\0') \
751     (*r)++; \
752     break; \
753     } \
754 vapier 1.227 } \
755 vapier 1.100 if (!*r || !end) \
756     break; \
757 vapier 1.75 else \
758     start = start + len + 1; \
759 vapier 1.69 } \
760     } \
761 vapier 1.101 if (*r) { \
762 solar 1.107 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
763 vapier 1.101 /* just nuke it */ \
764     nuke_it##B: \
765 vapier 1.103 memset(*r, 0x00, offset); \
766 vapier 1.102 *r = NULL; \
767 vapier 1.101 ESET(dyn->d_tag, DT_DEBUG); \
768 vapier 1.103 ESET(dyn->d_un.d_ptr, 0); \
769 vapier 1.101 } else if (fix_elf) { \
770     /* try to clean "bad" paths */ \
771     size_t len, tmpdir_len; \
772     char *start, *end; \
773     const char *tmpdir; \
774     start = *r; \
775     tmpdir = (getenv("TMPDIR") ? : "."); \
776     tmpdir_len = strlen(tmpdir); \
777     while (1) { \
778     end = strchr(start, ':'); \
779     if (start == end) { \
780     eat_this_path##B: \
781     len = strlen(end); \
782     memmove(start, end+1, len); \
783     start[len-1] = '\0'; \
784     end = start - 1; \
785     } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
786     if (!end) { \
787     if (start == *r) \
788     goto nuke_it##B; \
789     *--start = '\0'; \
790     } else \
791     goto eat_this_path##B; \
792     } \
793     if (!end) \
794     break; \
795     start = end + 1; \
796     } \
797 vapier 1.102 if (**r == '\0') \
798     goto nuke_it##B; \
799 vapier 1.101 } \
800 vapier 1.102 if (*r) \
801     *found_rpath = 1; \
802 vapier 1.101 } \
803 vapier 1.26 } \
804     ++dyn; \
805     } \
806     } }
807     SHOW_RPATH(32)
808     SHOW_RPATH(64)
809 vapier 1.10 }
810 vapier 1.41
811 solar 1.127 if (be_wewy_wewy_quiet) return;
812 vapier 1.70
813 vapier 1.39 if (rpath && runpath) {
814 vapier 1.41 if (!strcmp(rpath, runpath)) {
815     xstrcat(ret, runpath, ret_len);
816     } else {
817 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
818 vapier 1.41 xchrcat(ret, '{', ret_len);
819     xstrcat(ret, rpath, ret_len);
820     xchrcat(ret, ',', ret_len);
821     xstrcat(ret, runpath, ret_len);
822     xchrcat(ret, '}', ret_len);
823 vapier 1.39 }
824     } else if (rpath || runpath)
825 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
826     else if (!be_quiet)
827     xstrcat(ret, " - ", ret_len);
828 vapier 1.39 }
829 solar 1.96
830 vapier 1.253 /* Defines can be seen in glibc's sysdeps/generic/ldconfig.h */
831 solar 1.96 #define LDSO_CACHE_MAGIC "ld.so-"
832     #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
833     #define LDSO_CACHE_VER "1.7.0"
834     #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
835 vapier 1.97 #define FLAG_ANY -1
836     #define FLAG_TYPE_MASK 0x00ff
837     #define FLAG_LIBC4 0x0000
838     #define FLAG_ELF 0x0001
839     #define FLAG_ELF_LIBC5 0x0002
840     #define FLAG_ELF_LIBC6 0x0003
841     #define FLAG_REQUIRED_MASK 0xff00
842     #define FLAG_SPARC_LIB64 0x0100
843     #define FLAG_IA64_LIB64 0x0200
844     #define FLAG_X8664_LIB64 0x0300
845     #define FLAG_S390_LIB64 0x0400
846     #define FLAG_POWERPC_LIB64 0x0500
847     #define FLAG_MIPS64_LIBN32 0x0600
848     #define FLAG_MIPS64_LIBN64 0x0700
849 vapier 1.253 #define FLAG_X8664_LIBX32 0x0800
850     #define FLAG_ARM_LIBHF 0x0900
851     #define FLAG_AARCH64_LIB64 0x0a00
852 solar 1.96
853 flameeyes 1.141 #if defined(__GLIBC__) || defined(__UCLIBC__)
854 vapier 1.148
855 vapier 1.240 static char *lookup_cache_lib(elfobj *elf, const char *fname)
856 solar 1.96 {
857 vapier 1.212 int fd;
858 solar 1.96 char *strs;
859 vapier 1.104 static char buf[__PAX_UTILS_PATH_MAX] = "";
860 vapier 1.232 const char *cachefile = root_rel_path("/etc/ld.so.cache");
861 solar 1.96 struct stat st;
862    
863     typedef struct {
864     char magic[LDSO_CACHE_MAGIC_LEN];
865     char version[LDSO_CACHE_VER_LEN];
866     int nlibs;
867     } header_t;
868 vapier 1.97 header_t *header;
869 solar 1.96
870     typedef struct {
871     int flags;
872     int sooffset;
873     int liboffset;
874     } libentry_t;
875     libentry_t *libent;
876    
877     if (fname == NULL)
878     return NULL;
879    
880 vapier 1.212 if (ldcache == NULL) {
881 vapier 1.232 if (fstatat(root_fd, cachefile, &st, 0))
882 vapier 1.212 return NULL;
883    
884 vapier 1.232 fd = openat(root_fd, cachefile, O_RDONLY);
885 vapier 1.212 if (fd == -1)
886 solar 1.96 return NULL;
887 vapier 1.97
888     /* cache these values so we only map/unmap the cache file once */
889 solar 1.96 ldcache_size = st.st_size;
890 vapier 1.212 header = ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
891 vapier 1.97 close(fd);
892 solar 1.96
893 vapier 1.202 if (ldcache == MAP_FAILED) {
894 vapier 1.212 ldcache = NULL;
895 solar 1.96 return NULL;
896 solar 1.116 }
897 solar 1.96
898 vapier 1.212 if (memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
899     memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
900     {
901     munmap(ldcache, ldcache_size);
902     ldcache = NULL;
903 solar 1.96 return NULL;
904 vapier 1.212 }
905     } else
906     header = ldcache;
907 solar 1.96
908 vapier 1.212 libent = ldcache + sizeof(header_t);
909 solar 1.96 strs = (char *) &libent[header->nlibs];
910    
911 vapier 1.212 for (fd = 0; fd < header->nlibs; ++fd) {
912     /* This should be more fine grained, but for now we assume that
913     * diff arches will not be cached together, and we ignore the
914     * the different multilib mips cases.
915     */
916 vapier 1.97 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
917     continue;
918     if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
919     continue;
920    
921 solar 1.96 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
922     continue;
923 vapier 1.212
924     /* Return first hit because that is how the ldso rolls */
925 solar 1.96 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
926 vapier 1.212 break;
927 solar 1.96 }
928 vapier 1.212
929 solar 1.96 return buf;
930     }
931 vapier 1.212
932 solar 1.154 #elif defined(__NetBSD__)
933 vapier 1.240 static char *lookup_cache_lib(elfobj *elf, const char *fname)
934 solar 1.154 {
935     static char buf[__PAX_UTILS_PATH_MAX] = "";
936     static struct stat st;
937 vapier 1.227 size_t n;
938     char *ldpath;
939 solar 1.154
940 vapier 1.227 array_for_each(ldpath, n, ldpath) {
941     if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", ldpath, fname) >= sizeof(buf))
942 solar 1.154 continue; /* if the pathname is too long, or something went wrong, ignore */
943    
944     if (stat(buf, &st) != 0)
945     continue; /* if the lib doesn't exist in *ldpath, look further */
946    
947     /* NetBSD doesn't actually do sanity checks, it just loads the file
948     * and if that doesn't work, continues looking in other directories.
949     * This cannot easily be safely emulated, unfortunately. For now,
950     * just assume that if it exists, it's a valid library. */
951 vapier 1.148
952 solar 1.154 return buf;
953     }
954    
955     /* not found in any path */
956     return NULL;
957     }
958 flameeyes 1.141 #else
959 vapier 1.192 #ifdef __ELF__
960 vapier 1.148 #warning Cache support not implemented for your target
961 vapier 1.192 #endif
962 vapier 1.240 static char *lookup_cache_lib(elfobj *elf, const char *fname)
963 flameeyes 1.141 {
964     return NULL;
965     }
966     #endif
967 solar 1.96
968 vapier 1.257 static char *lookup_config_lib(const char *fname)
969 vapier 1.240 {
970     static char buf[__PAX_UTILS_PATH_MAX] = "";
971     const char *ldpath;
972     size_t n;
973    
974     array_for_each(ldpaths, n, ldpath) {
975     snprintf(buf, sizeof(buf), "%s/%s", root_rel_path(ldpath), fname);
976     if (faccessat(root_fd, buf, F_OK, AT_SYMLINK_NOFOLLOW) == 0)
977     return buf;
978     }
979    
980     return NULL;
981     }
982    
983 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)
984 vapier 1.39 {
985 vapier 1.44 unsigned long i;
986 vapier 1.39 char *needed;
987     void *strtbl_void;
988 solar 1.96 char *p;
989 vapier 1.39
990 vapier 1.226 /*
991     * -n -> op==0 -> print all
992     * -N -> op==1 -> print requested
993     */
994     if ((op == 0 && !show_needed) || (op == 1 && !find_lib))
995     return NULL;
996 vapier 1.10
997 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
998 vapier 1.32
999 vapier 1.44 if (elf->phdr && strtbl_void) {
1000 vapier 1.32 #define SHOW_NEEDED(B) \
1001     if (elf->elf_class == ELFCLASS ## B) { \
1002     Elf ## B ## _Dyn *dyn; \
1003     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
1004     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
1005     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
1006 vapier 1.44 Elf ## B ## _Off offset; \
1007 vapier 1.226 size_t matched = 0; \
1008     /* Walk all the program headers to find the PT_DYNAMIC */ \
1009 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
1010 vapier 1.226 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) \
1011     continue; \
1012 vapier 1.44 offset = EGET(phdr[i].p_offset); \
1013 vapier 1.226 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) \
1014     continue; \
1015     /* Walk all the dynamic tags to find NEEDED entries */ \
1016 vapier 1.217 dyn = DYN ## B (elf->vdata + offset); \
1017 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
1018     if (EGET(dyn->d_tag) == DT_NEEDED) { \
1019 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
1020 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
1021 vapier 1.49 ++dyn; \
1022     continue; \
1023     } \
1024 vapier 1.217 needed = elf->data + offset; \
1025 vapier 1.72 if (op == 0) { \
1026 vapier 1.226 /* -n -> print all entries */ \
1027 solar 1.127 if (!be_wewy_wewy_quiet) { \
1028 vapier 1.72 if (*found_needed) xchrcat(ret, ',', ret_len); \
1029 vapier 1.240 if (use_ldpath) { \
1030 vapier 1.257 if ((p = lookup_config_lib(needed)) != NULL) \
1031 vapier 1.240 needed = p; \
1032     } else if (use_ldcache) { \
1033 vapier 1.97 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
1034 solar 1.96 needed = p; \
1035 vapier 1.240 } \
1036 vapier 1.72 xstrcat(ret, needed, ret_len); \
1037     } \
1038     *found_needed = 1; \
1039     } else { \
1040 vapier 1.226 /* -N -> print matching entries */ \
1041     size_t n; \
1042     const char *find_lib_name; \
1043     \
1044 vapier 1.236 array_for_each(find_lib_arr, n, find_lib_name) { \
1045     int invert = 1; \
1046     if (find_lib_name[0] == '!') \
1047     invert = 0, ++find_lib_name; \
1048     if (!strcmp(find_lib_name, needed) == invert) \
1049 vapier 1.226 ++matched; \
1050 vapier 1.236 } \
1051 vapier 1.226 \
1052     if (matched == array_cnt(find_lib_arr)) { \
1053 vapier 1.81 *found_lib = 1; \
1054 vapier 1.226 return (be_wewy_wewy_quiet ? NULL : find_lib); \
1055 vapier 1.81 } \
1056 vapier 1.72 } \
1057 vapier 1.32 } \
1058     ++dyn; \
1059     } \
1060     } }
1061     SHOW_NEEDED(32)
1062     SHOW_NEEDED(64)
1063 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
1064 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
1065 vapier 1.32 }
1066 vapier 1.72
1067     return NULL;
1068 vapier 1.39 }
1069 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
1070 vapier 1.39 {
1071     void *strtbl_void;
1072    
1073 vapier 1.41 if (!show_interp) return NULL;
1074 vapier 1.32
1075 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
1076 vapier 1.38
1077 vapier 1.39 if (strtbl_void) {
1078 vapier 1.38 #define SHOW_INTERP(B) \
1079     if (elf->elf_class == ELFCLASS ## B) { \
1080 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
1081     *found_interp = 1; \
1082 solar 1.127 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
1083 vapier 1.38 }
1084     SHOW_INTERP(32)
1085     SHOW_INTERP(64)
1086 vapier 1.251 } else {
1087     /* Walk all the program headers to find the PT_INTERP */
1088     #define SHOW_PT_INTERP(B) \
1089     if (elf->elf_class == ELFCLASS ## B) { \
1090     unsigned long i; \
1091     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
1092     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
1093     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
1094     if (EGET(phdr[i].p_type) != PT_INTERP) \
1095     continue; \
1096     *found_interp = 1; \
1097     return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(phdr[i].p_offset)); \
1098     } \
1099     }
1100     SHOW_PT_INTERP(32)
1101     SHOW_PT_INTERP(64)
1102 vapier 1.38 }
1103 vapier 1.251
1104 vapier 1.41 return NULL;
1105 vapier 1.39 }
1106 vapier 1.257 static const char *scanelf_file_bind(elfobj *elf, char *found_bind)
1107 vapier 1.49 {
1108     unsigned long i;
1109     struct stat s;
1110 vapier 1.258 bool dynamic = false;
1111 vapier 1.49
1112     if (!show_bind) return NULL;
1113 vapier 1.51 if (!elf->phdr) return NULL;
1114 vapier 1.49
1115     #define SHOW_BIND(B) \
1116     if (elf->elf_class == ELFCLASS ## B) { \
1117     Elf ## B ## _Dyn *dyn; \
1118     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
1119     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
1120     Elf ## B ## _Off offset; \
1121     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
1122 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
1123 vapier 1.258 dynamic = true; \
1124 vapier 1.49 offset = EGET(phdr[i].p_offset); \
1125     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
1126 vapier 1.217 dyn = DYN ## B (elf->vdata + offset); \
1127 vapier 1.49 while (EGET(dyn->d_tag) != DT_NULL) { \
1128     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
1129     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
1130     { \
1131     if (be_quiet) return NULL; \
1132     *found_bind = 1; \
1133 solar 1.127 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
1134 vapier 1.49 } \
1135     ++dyn; \
1136     } \
1137     } \
1138     }
1139     SHOW_BIND(32)
1140     SHOW_BIND(64)
1141    
1142 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
1143 vapier 1.70
1144 vapier 1.159 /* don't output anything if quiet mode and the ELF is static or not setuid */
1145     if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
1146 vapier 1.49 return NULL;
1147     } else {
1148     *found_bind = 1;
1149 vapier 1.257 return dynamic ? "LAZY" : "STATIC";
1150 vapier 1.49 }
1151     }
1152 vapier 1.84 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
1153     {
1154     unsigned long i;
1155     char *soname;
1156     void *strtbl_void;
1157    
1158     if (!show_soname) return NULL;
1159    
1160     strtbl_void = elf_findsecbyname(elf, ".dynstr");
1161    
1162     if (elf->phdr && strtbl_void) {
1163     #define SHOW_SONAME(B) \
1164     if (elf->elf_class == ELFCLASS ## B) { \
1165     Elf ## B ## _Dyn *dyn; \
1166     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
1167     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
1168     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
1169     Elf ## B ## _Off offset; \
1170     /* only look for soname in shared objects */ \
1171 solar 1.188 if (EGET(ehdr->e_type) != ET_DYN) \
1172 vapier 1.84 return NULL; \
1173     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
1174 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
1175 vapier 1.84 offset = EGET(phdr[i].p_offset); \
1176     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
1177 vapier 1.217 dyn = DYN ## B (elf->vdata + offset); \
1178 vapier 1.84 while (EGET(dyn->d_tag) != DT_NULL) { \
1179     if (EGET(dyn->d_tag) == DT_SONAME) { \
1180     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
1181     if (offset >= (Elf ## B ## _Off)elf->len) { \
1182     ++dyn; \
1183     continue; \
1184     } \
1185 vapier 1.217 soname = elf->data + offset; \
1186 vapier 1.84 *found_soname = 1; \
1187 solar 1.127 return (be_wewy_wewy_quiet ? NULL : soname); \
1188 vapier 1.84 } \
1189     ++dyn; \
1190     } \
1191     } }
1192     SHOW_SONAME(32)
1193     SHOW_SONAME(64)
1194     }
1195    
1196     return NULL;
1197     }
1198 solar 1.177
1199 vapier 1.215 /*
1200     * We support the symbol form:
1201     * [%[modifiers]%][[+-]<symbol name>][,[.....]]
1202     * If the symbol name is empty, then all symbols are matched.
1203     * If the symbol name is a glob ("*"), then all symbols are dumped (debug).
1204     * Do not rely on this output format at all.
1205     * Otherwise the symbol name is used to search (either regex or string compare).
1206     * If the first char of the symbol name is a plus ("+"), then only match
1207     * defined symbols. If it's a minus ("-"), only match undefined symbols.
1208     * Putting modifiers in between the percent signs allows for more in depth
1209     * filters. There are groups of modifiers. If you don't specify a member
1210     * of a group, then all types in that group are matched. The current
1211     * groups and their types are:
1212 vapier 1.238 * STT group: STT_NOTYPE:n STT_OBJECT:o STT_FUNC:f STT_FILE:F
1213 vapier 1.215 * STB group: STB_LOCAL:l STB_GLOBAL:g STB_WEAK:w
1214 vapier 1.266 * STV group: STV_DEFAULT:p STV_INTERNAL:i STV_HIDDEN:h STV_PROTECTED:P
1215 vapier 1.215 * SHN group: SHN_UNDEF:u SHN_ABS:a SHN_COMMON:c {defined}:d
1216     * The "defined" value in the SHN group does not correspond to a SHN_xxx define.
1217     * You can search for multiple symbols at once by seperating with a comma (",").
1218     *
1219     * Some examples:
1220     * ELFs with a weak function "foo":
1221     * scanelf -s %wf%foo <ELFs>
1222     * ELFs that define the symbol "main":
1223     * scanelf -s +main <ELFs>
1224     * scanelf -s %d%main <ELFs>
1225     * ELFs that refer to the undefined symbol "brk":
1226     * scanelf -s -brk <ELFs>
1227     * scanelf -s %u%brk <ELFs>
1228     * All global defined objects in an ELF:
1229     * scanelf -s %ogd% <ELF>
1230     */
1231     static void
1232     scanelf_match_symname(elfobj *elf, char *found_sym, char **ret, size_t *ret_len, const char *symname,
1233 vapier 1.266 unsigned int stt, unsigned int stb, unsigned int stv, unsigned int shn, unsigned long size)
1234 vapier 1.215 {
1235 vapier 1.248 const char *this_sym;
1236     size_t n;
1237 vapier 1.215
1238 vapier 1.248 array_for_each(find_sym_arr, n, this_sym) {
1239 vapier 1.215 bool inc_notype, inc_object, inc_func, inc_file,
1240     inc_local, inc_global, inc_weak,
1241 vapier 1.266 inc_visdef, inc_intern, inc_hidden, inc_prot,
1242 vapier 1.215 inc_def, inc_undef, inc_abs, inc_common;
1243    
1244     /* symbol selection! */
1245 vapier 1.266 inc_notype = inc_object = inc_func = inc_file =
1246     inc_local = inc_global = inc_weak =
1247     inc_visdef = inc_intern = inc_hidden = inc_prot =
1248     inc_def = inc_undef = inc_abs = inc_common =
1249 vapier 1.215 (*this_sym != '%');
1250    
1251     /* parse the contents of %...% */
1252     if (!inc_notype) {
1253     while (*(this_sym++)) {
1254     if (*this_sym == '%') {
1255     ++this_sym;
1256     break;
1257     }
1258     switch (*this_sym) {
1259     case 'n': inc_notype = true; break;
1260     case 'o': inc_object = true; break;
1261     case 'f': inc_func = true; break;
1262     case 'F': inc_file = true; break;
1263     case 'l': inc_local = true; break;
1264     case 'g': inc_global = true; break;
1265     case 'w': inc_weak = true; break;
1266 vapier 1.266 case 'p': inc_visdef = true; break;
1267     case 'i': inc_intern = true; break;
1268     case 'h': inc_hidden = true; break;
1269     case 'P': inc_prot = true; break;
1270 vapier 1.215 case 'd': inc_def = true; break;
1271     case 'u': inc_undef = true; break;
1272     case 'a': inc_abs = true; break;
1273     case 'c': inc_common = true; break;
1274     default: err("invalid symbol selector '%c'", *this_sym);
1275     }
1276     }
1277    
1278     /* If no types are matched, not match all */
1279     if (!inc_notype && !inc_object && !inc_func && !inc_file)
1280     inc_notype = inc_object = inc_func = inc_file = true;
1281     if (!inc_local && !inc_global && !inc_weak)
1282     inc_local = inc_global = inc_weak = true;
1283 vapier 1.266 if (!inc_visdef && !inc_intern && !inc_hidden && !inc_prot)
1284     inc_visdef = inc_intern = inc_hidden = inc_prot = true;
1285 vapier 1.215 if (!inc_def && !inc_undef && !inc_abs && !inc_common)
1286     inc_def = inc_undef = inc_abs = inc_common = true;
1287    
1288     /* backwards compat for defined/undefined short hand */
1289     } else if (*this_sym == '+') {
1290     inc_undef = false;
1291     ++this_sym;
1292     } else if (*this_sym == '-') {
1293     inc_def = inc_abs = inc_common = false;
1294     ++this_sym;
1295     }
1296    
1297     /* filter symbols */
1298 vapier 1.266 if ((!inc_notype && stt == STT_NOTYPE ) || \
1299     (!inc_object && stt == STT_OBJECT ) || \
1300     (!inc_func && stt == STT_FUNC ) || \
1301     (!inc_file && stt == STT_FILE ) || \
1302     (!inc_local && stb == STB_LOCAL ) || \
1303     (!inc_global && stb == STB_GLOBAL ) || \
1304     (!inc_weak && stb == STB_WEAK ) || \
1305     (!inc_visdef && stv == STV_DEFAULT ) || \
1306     (!inc_intern && stv == STV_INTERNAL ) || \
1307     (!inc_hidden && stv == STV_HIDDEN ) || \
1308     (!inc_prot && stv == STV_PROTECTED) || \
1309 vapier 1.215 (!inc_def && shn && shn < SHN_LORESERVE) || \
1310 vapier 1.266 (!inc_undef && shn == SHN_UNDEF ) || \
1311     (!inc_abs && shn == SHN_ABS ) || \
1312     (!inc_common && shn == SHN_COMMON ))
1313 vapier 1.215 continue;
1314    
1315     if (*this_sym == '*') {
1316     /* a "*" symbol gets you debug output */
1317 vapier 1.266 printf("%s(%s) %5lX %-15s %-15s %-15s %-15s %s\n",
1318 vapier 1.215 ((*found_sym == 0) ? "\n\t" : "\t"),
1319     elf->base_filename,
1320     size,
1321     get_elfstttype(stt),
1322     get_elfstbtype(stb),
1323 vapier 1.266 get_elfstvtype(stv),
1324 vapier 1.215 get_elfshntype(shn),
1325     symname);
1326     goto matched;
1327    
1328     } else {
1329     if (g_match) {
1330     /* regex match the symbol */
1331 vapier 1.249 if (regexec(find_sym_regex_arr->eles[n], symname, 0, NULL, 0) == REG_NOMATCH)
1332 vapier 1.215 continue;
1333    
1334     } else if (*this_sym) {
1335     /* give empty symbols a "pass", else do a normal compare */
1336     const size_t len = strlen(this_sym);
1337     if (!(strncmp(this_sym, symname, len) == 0 &&
1338     /* Accept unversioned symbol names */
1339     (symname[len] == '\0' || symname[len] == '@')))
1340     continue;
1341     }
1342    
1343     if (be_semi_verbose) {
1344     char buf[1024];
1345     snprintf(buf, sizeof(buf), "%lX %s %s",
1346     size,
1347     get_elfstttype(stt),
1348     this_sym);
1349     *ret = xstrdup(buf);
1350     } else {
1351     if (*ret) xchrcat(ret, ',', ret_len);
1352     xstrcat(ret, symname, ret_len);
1353     }
1354    
1355     goto matched;
1356     }
1357 vapier 1.248 }
1358 vapier 1.215
1359     return;
1360    
1361     matched:
1362     *found_sym = 1;
1363 flameeyes 1.197 }
1364    
1365 vapier 1.225 static const char *scanelf_file_sym(elfobj *elf, char *found_sym)
1366 vapier 1.39 {
1367 vapier 1.95 char *ret;
1368 vapier 1.39 void *symtab_void, *strtab_void;
1369 vapier 1.38
1370 vapier 1.41 if (!find_sym) return NULL;
1371 vapier 1.214 ret = NULL;
1372 vapier 1.32
1373 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
1374 vapier 1.27
1375 vapier 1.39 if (symtab_void && strtab_void) {
1376 vapier 1.27 #define FIND_SYM(B) \
1377     if (elf->elf_class == ELFCLASS ## B) { \
1378     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
1379     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
1380 vapier 1.217 Elf ## B ## _Sym *sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
1381 vapier 1.234 Elf ## B ## _Word i, cnt = EGET(symtab->sh_entsize); \
1382 vapier 1.27 char *symname; \
1383 vapier 1.214 size_t ret_len = 0; \
1384 vapier 1.115 if (cnt) \
1385     cnt = EGET(symtab->sh_size) / cnt; \
1386 vapier 1.27 for (i = 0; i < cnt; ++i) { \
1387 vapier 1.217 if ((void*)sym > elf->data_end) { \
1388 flameeyes 1.195 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1389     goto break_out; \
1390     } \
1391 vapier 1.27 if (sym->st_name) { \
1392 vapier 1.134 /* make sure the symbol name is in acceptable memory range */ \
1393 vapier 1.217 symname = elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name); \
1394     if ((void*)symname > elf->data_end) { \
1395 vapier 1.115 warnf("%s: corrupt ELF symbols", elf->filename); \
1396 vapier 1.134 ++sym; \
1397 vapier 1.111 continue; \
1398     } \
1399 vapier 1.215 scanelf_match_symname(elf, found_sym, \
1400     &ret, &ret_len, symname, \
1401     ELF##B##_ST_TYPE(EGET(sym->st_info)), \
1402     ELF##B##_ST_BIND(EGET(sym->st_info)), \
1403 vapier 1.266 ELF##B##_ST_VISIBILITY(EGET(sym->st_other)), \
1404 vapier 1.215 EGET(sym->st_shndx), \
1405     /* st_size can be 64bit, but no one is really that big, so screw em */ \
1406     EGET(sym->st_size)); \
1407 vapier 1.27 } \
1408     ++sym; \
1409 vapier 1.234 } \
1410     }
1411 vapier 1.27 FIND_SYM(32)
1412     FIND_SYM(64)
1413 vapier 1.39 }
1414 vapier 1.70
1415 vapier 1.95 break_out:
1416 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
1417 vapier 1.70
1418 vapier 1.41 if (*find_sym != '*' && *found_sym)
1419 vapier 1.95 return ret;
1420 vapier 1.41 if (be_quiet)
1421     return NULL;
1422     else
1423 vapier 1.225 return " - ";
1424 vapier 1.39 }
1425 solar 1.119
1426 vapier 1.225 static const char *scanelf_file_sections(elfobj *elf, char *found_section)
1427 solar 1.124 {
1428     if (!find_section)
1429     return NULL;
1430    
1431     #define FIND_SECTION(B) \
1432     if (elf->elf_class == ELFCLASS ## B) { \
1433 vapier 1.226 size_t matched, n; \
1434 solar 1.136 int invert; \
1435 vapier 1.226 const char *section_name; \
1436 solar 1.124 Elf ## B ## _Shdr *section; \
1437 vapier 1.226 \
1438     matched = 0; \
1439     array_for_each(find_section_arr, n, section_name) { \
1440     invert = (*section_name == '!' ? 1 : 0); \
1441     section = SHDR ## B (elf_findsecbyname(elf, section_name + invert)); \
1442     if ((section == NULL && invert) || (section != NULL && !invert)) \
1443     ++matched; \
1444     } \
1445     \
1446     if (matched == array_cnt(find_section_arr)) \
1447 solar 1.124 *found_section = 1; \
1448     }
1449     FIND_SECTION(32)
1450     FIND_SECTION(64)
1451    
1452 vapier 1.138 if (be_wewy_wewy_quiet)
1453     return NULL;
1454 solar 1.124
1455     if (*found_section)
1456     return find_section;
1457    
1458     if (be_quiet)
1459     return NULL;
1460     else
1461 vapier 1.225 return " - ";
1462 solar 1.124 }
1463    
1464 vapier 1.39 /* scan an elf file and show all the fun stuff */
1465 vapier 1.210 #define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
1466 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
1467 vapier 1.39 {
1468 vapier 1.44 unsigned long i;
1469 vapier 1.162 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1470     found_rpath, found_needed, found_interp, found_bind, found_soname,
1471 solar 1.124 found_sym, found_lib, found_file, found_textrels, found_section;
1472 vapier 1.41 static char *out_buffer = NULL;
1473     static size_t out_len;
1474 vapier 1.39
1475 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1476 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1477 solar 1.124 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1478 vapier 1.39
1479 vapier 1.114 if (be_verbose > 2)
1480 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
1481 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
1482     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1483 vapier 1.114 else if (be_verbose > 1)
1484 vapier 1.106 printf("%s: scanning file\n", elf->filename);
1485 vapier 1.39
1486 vapier 1.41 /* init output buffer */
1487     if (!out_buffer) {
1488     out_len = sizeof(char) * 80;
1489 vapier 1.186 out_buffer = xmalloc(out_len);
1490 vapier 1.41 }
1491     *out_buffer = '\0';
1492    
1493 vapier 1.39 /* show the header */
1494     if (!be_quiet && show_banner) {
1495 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1496 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1497 vapier 1.41
1498     switch (out_format[++i]) {
1499 solar 1.132 case '+': break;
1500 vapier 1.41 case '%': break;
1501 vapier 1.70 case '#': break;
1502 vapier 1.66 case 'F':
1503     case 'p':
1504     case 'f': prints("FILE "); found_file = 1; break;
1505 vapier 1.41 case 'o': prints(" TYPE "); break;
1506     case 'x': prints(" PAX "); break;
1507 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
1508 vapier 1.41 case 't': prints("TEXTREL "); break;
1509     case 'r': prints("RPATH "); break;
1510 vapier 1.171 case 'M': prints("CLASS "); break;
1511 vapier 1.240 case 'l':
1512 vapier 1.41 case 'n': prints("NEEDED "); break;
1513     case 'i': prints("INTERP "); break;
1514 vapier 1.49 case 'b': prints("BIND "); break;
1515 solar 1.190 case 'Z': prints("SIZE "); break;
1516 vapier 1.84 case 'S': prints("SONAME "); break;
1517 vapier 1.41 case 's': prints("SYM "); break;
1518 vapier 1.72 case 'N': prints("LIB "); break;
1519 vapier 1.76 case 'T': prints("TEXTRELS "); break;
1520 vapier 1.126 case 'k': prints("SECTION "); break;
1521 vapier 1.166 case 'a': prints("ARCH "); break;
1522 solar 1.191 case 'I': prints("OSABI "); break;
1523     case 'Y': prints("EABI "); break;
1524 solar 1.180 case 'O': prints("PERM "); break;
1525 solar 1.181 case 'D': prints("ENDIAN "); break;
1526 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
1527 vapier 1.39 }
1528 vapier 1.27 }
1529 vapier 1.49 if (!found_file) prints("FILE ");
1530 vapier 1.41 prints("\n");
1531 vapier 1.49 found_file = 0;
1532 vapier 1.39 show_banner = 0;
1533     }
1534    
1535     /* dump all the good stuff */
1536 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1537 vapier 1.41 const char *out;
1538 vapier 1.66 const char *tmp;
1539 solar 1.190 static char ubuf[sizeof(unsigned long)*2];
1540 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
1541 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
1542     continue;
1543     }
1544 vapier 1.39
1545 vapier 1.41 out = NULL;
1546 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
1547 solar 1.132 be_semi_verbose = (out_format[i] == '+');
1548 vapier 1.41 switch (out_format[++i]) {
1549 solar 1.132 case '+':
1550 vapier 1.70 case '%':
1551     case '#':
1552     xchrcat(&out_buffer, out_format[i], &out_len); break;
1553     case 'F':
1554 vapier 1.76 found_file = 1;
1555 solar 1.127 if (be_wewy_wewy_quiet) break;
1556 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1557 vapier 1.70 break;
1558 vapier 1.66 case 'p':
1559 vapier 1.76 found_file = 1;
1560 solar 1.127 if (be_wewy_wewy_quiet) break;
1561 vapier 1.106 tmp = elf->filename;
1562 vapier 1.66 if (search_path) {
1563     ssize_t len_search = strlen(search_path);
1564 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1565     if (!strncmp(elf->filename, search_path, len_search) && \
1566 vapier 1.66 len_file > len_search)
1567     tmp += len_search;
1568     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1569     }
1570     xstrcat(&out_buffer, tmp, &out_len);
1571     break;
1572     case 'f':
1573 vapier 1.76 found_file = 1;
1574 solar 1.127 if (be_wewy_wewy_quiet) break;
1575 vapier 1.106 tmp = strrchr(elf->filename, '/');
1576     tmp = (tmp == NULL ? elf->filename : tmp+1);
1577 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1578     break;
1579 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1580     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1581 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1582 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1583 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1584 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1585 vapier 1.171 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1586 solar 1.181 case 'D': out = get_endian(elf); break;
1587 vapier 1.206 case 'O': out = strfileperms(elf->filename); break;
1588 vapier 1.72 case 'n':
1589     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1590 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1591 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1592 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1593 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1594 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1595 vapier 1.166 case 'a': out = get_elfemtype(elf); break;
1596 solar 1.191 case 'I': out = get_elfosabi(elf); break;
1597     case 'Y': out = get_elf_eabi(elf); break;
1598 vapier 1.193 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;;
1599 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1600 vapier 1.29 }
1601 vapier 1.214 if (out)
1602     xstrcat(&out_buffer, out, &out_len);
1603 vapier 1.39 }
1604    
1605 vapier 1.54 #define FOUND_SOMETHING() \
1606 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1607 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1608 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1609 vapier 1.54
1610     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1611     xchrcat(&out_buffer, ' ', &out_len);
1612 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1613 vapier 1.27 }
1614 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1615 vapier 1.41 puts(out_buffer);
1616 vapier 1.79 fflush(stdout);
1617     }
1618 vapier 1.10
1619 vapier 1.105 return 0;
1620     }
1621    
1622 vapier 1.106 /* scan a single elf */
1623     static int scanelf_elf(const char *filename, int fd, size_t len)
1624     {
1625 solar 1.120 int ret = 1;
1626 vapier 1.262 size_t n;
1627     const char *match_etype;
1628 vapier 1.106 elfobj *elf;
1629    
1630 vapier 1.263 /* Verify this is a real ELF */
1631 vapier 1.106 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1632     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1633 vapier 1.235 return 2;
1634 solar 1.120 }
1635 vapier 1.263
1636     /* Possibly filter based on ELF bitness */
1637 solar 1.120 switch (match_bits) {
1638 vapier 1.263 case 32:
1639     if (elf->elf_class != ELFCLASS32)
1640     goto done;
1641     break;
1642     case 64:
1643     if (elf->elf_class != ELFCLASS64)
1644     goto done;
1645     break;
1646 vapier 1.106 }
1647 vapier 1.262
1648 vapier 1.263 /* Possibly filter based on the ELF's e_type field */
1649 vapier 1.262 array_for_each(match_etypes, n, match_etype)
1650     if (etype_lookup(match_etype) == get_etype(elf))
1651 vapier 1.263 goto scanit;
1652 vapier 1.262 if (array_cnt(match_etypes))
1653 vapier 1.263 goto done;
1654 solar 1.119
1655 vapier 1.263 scanit:
1656 vapier 1.106 ret = scanelf_elfobj(elf);
1657 solar 1.119
1658 vapier 1.263 done:
1659 vapier 1.106 unreadelf(elf);
1660     return ret;
1661     }
1662 solar 1.119
1663 vapier 1.105 /* scan an archive of elfs */
1664 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1665 vapier 1.105 {
1666 vapier 1.106 archive_handle *ar;
1667 vapier 1.105 archive_member *m;
1668 vapier 1.106 char *ar_buffer;
1669     elfobj *elf;
1670    
1671     ar = ar_open_fd(filename, fd);
1672     if (ar == NULL)
1673     return 1;
1674    
1675 vapier 1.201 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1676 vapier 1.218 while ((m = ar_next(ar)) != NULL) {
1677     off_t cur_pos = lseek(fd, 0, SEEK_CUR);
1678     if (cur_pos == -1)
1679     errp("lseek() failed");
1680     elf = readelf_buffer(m->name, ar_buffer + cur_pos, m->size);
1681 vapier 1.106 if (elf) {
1682     scanelf_elfobj(elf);
1683     unreadelf(elf);
1684     }
1685     }
1686     munmap(ar_buffer, len);
1687    
1688 vapier 1.105 return 0;
1689     }
1690     /* scan a file which may be an elf or an archive or some other magical beast */
1691 vapier 1.232 static int scanelf_fileat(int dir_fd, const char *filename, const struct stat *st_cache)
1692 vapier 1.105 {
1693 vapier 1.161 const struct stat *st = st_cache;
1694     struct stat symlink_st;
1695 vapier 1.106 int fd;
1696 vapier 1.105
1697     /* always handle regular files and handle symlinked files if no -y */
1698 vapier 1.161 if (S_ISLNK(st->st_mode)) {
1699 vapier 1.232 if (!scan_symlink)
1700     return 1;
1701     fstatat(dir_fd, filename, &symlink_st, 0);
1702 vapier 1.161 st = &symlink_st;
1703 vapier 1.105 }
1704 vapier 1.161
1705     if (!S_ISREG(st->st_mode)) {
1706 vapier 1.105 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1707 solar 1.164 return 1;
1708 vapier 1.105 }
1709    
1710 solar 1.180 if (match_perms) {
1711     if ((st->st_mode | match_perms) != st->st_mode)
1712     return 1;
1713     }
1714 vapier 1.232 fd = openat(dir_fd, filename, (fix_elf ? O_RDWR : O_RDONLY) | O_CLOEXEC);
1715 vapier 1.245 if (fd == -1) {
1716     if (fix_elf && errno == ETXTBSY)
1717     warnp("%s: could not fix", filename);
1718     else if (be_verbose > 2)
1719     printf("%s: skipping file: %s\n", filename, strerror(errno));
1720 solar 1.164 return 1;
1721 vapier 1.245 }
1722 vapier 1.106
1723 vapier 1.235 if (scanelf_elf(filename, fd, st->st_size) == 2) {
1724 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1725 vapier 1.235 if (scan_archives)
1726     scanelf_archive(filename, fd, st->st_size);
1727    
1728     /*
1729     * unreadelf() implicitly closes its fd, so only close it
1730     * when we are returning it in the non-ELF case
1731     */
1732     close(fd);
1733     }
1734 vapier 1.106
1735 solar 1.164 return 0;
1736 solar 1.6 }
1737    
1738 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1739 vapier 1.232 static int scanelf_dirat(int dir_fd, const char *path)
1740 solar 1.1 {
1741 vapier 1.10 register DIR *dir;
1742     register struct dirent *dentry;
1743 vapier 1.14 struct stat st_top, st;
1744 vapier 1.232 char buf[__PAX_UTILS_PATH_MAX], *subpath;
1745 vapier 1.32 size_t pathlen = 0, len = 0;
1746 solar 1.164 int ret = 0;
1747 vapier 1.232 int subdir_fd;
1748 solar 1.223
1749 vapier 1.10 /* make sure path exists */
1750 vapier 1.232 if (fstatat(dir_fd, path, &st_top, AT_SYMLINK_NOFOLLOW) == -1) {
1751 vapier 1.39 if (be_verbose > 2) printf("%s: does not exist\n", path);
1752 solar 1.164 return 1;
1753 vapier 1.39 }
1754 solar 1.11
1755 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1756 vapier 1.232 if (!S_ISDIR(st_top.st_mode))
1757     return scanelf_fileat(dir_fd, path, &st_top);
1758 vapier 1.10
1759     /* now scan the dir looking for fun stuff */
1760 vapier 1.232 subdir_fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
1761     if (subdir_fd == -1)
1762     dir = NULL;
1763     else
1764     dir = fdopendir(subdir_fd);
1765     if (dir == NULL) {
1766     if (subdir_fd != -1)
1767     close(subdir_fd);
1768 vapier 1.255 else if (be_verbose > 2)
1769     printf("%s: skipping dir: %s\n", path, strerror(errno));
1770 solar 1.164 return 1;
1771 vapier 1.10 }
1772 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1773 solar 1.11
1774 vapier 1.232 subpath = stpcpy(buf, path);
1775 vapier 1.243 if (subpath[-1] != '/')
1776     *subpath++ = '/';
1777 vapier 1.232 pathlen = subpath - buf;
1778 vapier 1.10 while ((dentry = readdir(dir))) {
1779     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1780     continue;
1781 vapier 1.232
1782     if (fstatat(subdir_fd, dentry->d_name, &st, AT_SYMLINK_NOFOLLOW) == -1)
1783     continue;
1784    
1785     len = strlen(dentry->d_name);
1786     if (len + pathlen + 1 >= sizeof(buf)) {
1787     warnf("Skipping '%s%s': len > sizeof(buf); %zu > %zu\n",
1788     path, dentry->d_name, len + pathlen + 1, sizeof(buf));
1789 vapier 1.32 continue;
1790     }
1791 vapier 1.232 memcpy(subpath, dentry->d_name, len);
1792     subpath[len] = '\0';
1793    
1794     if (S_ISREG(st.st_mode))
1795     ret = scanelf_fileat(dir_fd, buf, &st);
1796     else if (dir_recurse && S_ISDIR(st.st_mode)) {
1797     if (dir_crossmount || (st_top.st_dev == st.st_dev))
1798     ret = scanelf_dirat(dir_fd, buf);
1799 vapier 1.10 }
1800     }
1801     closedir(dir);
1802 vapier 1.232
1803 solar 1.164 return ret;
1804 solar 1.1 }
1805 vapier 1.232 static int scanelf_dir(const char *path)
1806     {
1807     return scanelf_dirat(root_fd, root_rel_path(path));
1808     }
1809 solar 1.1
1810 vapier 1.133 static int scanelf_from_file(const char *filename)
1811 vapier 1.47 {
1812 vapier 1.230 FILE *fp;
1813     char *p, *path;
1814     size_t len;
1815     int ret;
1816 solar 1.45
1817 solar 1.132 if (strcmp(filename, "-") == 0)
1818 solar 1.45 fp = stdin;
1819     else if ((fp = fopen(filename, "r")) == NULL)
1820     return 1;
1821    
1822 vapier 1.230 path = NULL;
1823     len = 0;
1824     ret = 0;
1825     while (getline(&path, &len, fp) != -1) {
1826 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1827     *p = 0;
1828 vapier 1.66 search_path = path;
1829 solar 1.164 ret = scanelf_dir(path);
1830 solar 1.45 }
1831 vapier 1.230 free(path);
1832    
1833 solar 1.45 if (fp != stdin)
1834     fclose(fp);
1835 vapier 1.230
1836 solar 1.164 return ret;
1837 solar 1.45 }
1838    
1839 solar 1.154 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1840 vapier 1.148
1841 vapier 1.240 static int _load_ld_cache_config(const char *fname)
1842 vapier 1.48 {
1843     FILE *fp = NULL;
1844 vapier 1.230 char *p, *path;
1845     size_t len;
1846 vapier 1.232 int curr_fd = -1;
1847 solar 1.223
1848 vapier 1.232 fp = fopenat_r(root_fd, root_rel_path(fname));
1849     if (fp == NULL)
1850 vapier 1.240 return -1;
1851 vapier 1.48
1852 vapier 1.230 path = NULL;
1853     len = 0;
1854     while (getline(&path, &len, fp) != -1) {
1855 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1856     *p = 0;
1857     if ((p = strchr(path, '\n')) != NULL)
1858     *p = 0;
1859 vapier 1.219
1860 vapier 1.186 /* recursive includes of the same file will make this segfault. */
1861 solar 1.129 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1862 vapier 1.219 glob_t gl;
1863 solar 1.123 size_t x;
1864 vapier 1.232 const char *gpath;
1865 solar 1.123
1866 vapier 1.232 /* re-use existing path buffer ... need to be creative */
1867 solar 1.123 if (path[8] != '/')
1868 vapier 1.232 gpath = memcpy(path + 3, "/etc/", 5);
1869 solar 1.123 else
1870 vapier 1.232 gpath = path + 8;
1871     if (root_fd != AT_FDCWD) {
1872     if (curr_fd == -1) {
1873     curr_fd = open(".", O_RDONLY|O_CLOEXEC);
1874     if (fchdir(root_fd))
1875     errp("unable to change to root dir");
1876     }
1877     gpath = root_rel_path(gpath);
1878     }
1879 solar 1.123
1880 vapier 1.219 if (glob(gpath, 0, NULL, &gl) == 0) {
1881 solar 1.123 for (x = 0; x < gl.gl_pathc; ++x) {
1882     /* try to avoid direct loops */
1883     if (strcmp(gl.gl_pathv[x], fname) == 0)
1884     continue;
1885 vapier 1.240 _load_ld_cache_config(gl.gl_pathv[x]);
1886 solar 1.123 }
1887 vapier 1.219 globfree(&gl);
1888 solar 1.160 }
1889 vapier 1.232
1890     /* failed globs are ignored by glibc */
1891     continue;
1892 solar 1.123 }
1893 vapier 1.219
1894 solar 1.123 if (*path != '/')
1895     continue;
1896 vapier 1.48
1897 vapier 1.233 xarraypush_str(ldpaths, path);
1898 vapier 1.48 }
1899 vapier 1.230 free(path);
1900 vapier 1.48
1901     fclose(fp);
1902 vapier 1.230
1903 vapier 1.232 if (curr_fd != -1) {
1904     if (fchdir(curr_fd))
1905 vapier 1.257 {/* don't care */}
1906 vapier 1.232 close(curr_fd);
1907     }
1908    
1909 vapier 1.240 return 0;
1910 vapier 1.48 }
1911 flameeyes 1.141
1912 vapier 1.211 #elif defined(__FreeBSD__) || defined(__DragonFly__)
1913 vapier 1.148
1914 vapier 1.240 static int _load_ld_cache_config(const char *fname)
1915 flameeyes 1.141 {
1916     FILE *fp = NULL;
1917     char *b = NULL, *p;
1918     struct elfhints_hdr hdr;
1919 vapier 1.152
1920 vapier 1.232 fp = fopenat_r(root_fd, root_rel_path(fname));
1921     if (fp == NULL)
1922 vapier 1.240 return -1;
1923 flameeyes 1.141
1924 vapier 1.152 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1925     hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1926     fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1927     {
1928 flameeyes 1.141 fclose(fp);
1929 vapier 1.240 return -1;
1930 flameeyes 1.141 }
1931 vapier 1.152
1932 vapier 1.186 b = xmalloc(hdr.dirlistlen + 1);
1933 vapier 1.152 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1934 flameeyes 1.141 fclose(fp);
1935     free(b);
1936 vapier 1.240 return -1;
1937 flameeyes 1.141 }
1938 vapier 1.152
1939     while ((p = strsep(&b, ":"))) {
1940 vapier 1.227 if (*p == '\0')
1941     continue;
1942 vapier 1.233 xarraypush_str(ldpaths, p);
1943 flameeyes 1.141 }
1944 vapier 1.157
1945 flameeyes 1.141 free(b);
1946     fclose(fp);
1947 vapier 1.240 return 0;
1948 flameeyes 1.141 }
1949 vapier 1.148
1950     #else
1951 vapier 1.192 #ifdef __ELF__
1952 vapier 1.148 #warning Cache config support not implemented for your target
1953 vapier 1.192 #endif
1954 vapier 1.240 static int _load_ld_cache_config(const char *fname)
1955 vapier 1.148 {
1956 vapier 1.192 return 0;
1957 vapier 1.148 }
1958 flameeyes 1.141 #endif
1959 vapier 1.48
1960 vapier 1.240 static void load_ld_cache_config(const char *fname)
1961     {
1962     bool scan_l, scan_ul, scan_ull;
1963     size_t n;
1964     const char *ldpath;
1965    
1966     _load_ld_cache_config(fname);
1967    
1968     scan_l = scan_ul = scan_ull = false;
1969 vapier 1.261 array_for_each(ldpaths, n, ldpath) {
1970     if (!scan_l && !strcmp(ldpath, "/lib")) scan_l = true;
1971     if (!scan_ul && !strcmp(ldpath, "/usr/lib")) scan_ul = true;
1972     if (!scan_ull && !strcmp(ldpath, "/usr/local/lib")) scan_ull = true;
1973 vapier 1.240 }
1974    
1975     if (!scan_l) xarraypush_str(ldpaths, "/lib");
1976     if (!scan_ul) xarraypush_str(ldpaths, "/usr/lib");
1977     if (!scan_ull) xarraypush_str(ldpaths, "/usr/local/lib");
1978     }
1979    
1980 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1981 vapier 1.184 static void scanelf_ldpath(void)
1982 vapier 1.10 {
1983 vapier 1.227 size_t n;
1984     const char *ldpath;
1985 vapier 1.17
1986 vapier 1.240 array_for_each(ldpaths, n, ldpath)
1987 vapier 1.227 scanelf_dir(ldpath);
1988 vapier 1.10 }
1989 solar 1.1
1990 vapier 1.10 /* scan env PATH for paths */
1991 vapier 1.184 static void scanelf_envpath(void)
1992 solar 1.1 {
1993 solar 1.34 char *path, *p;
1994 vapier 1.10
1995     path = getenv("PATH");
1996     if (!path)
1997     err("PATH is not set in your env !");
1998 vapier 1.41 path = xstrdup(path);
1999 vapier 1.10
2000     while ((p = strrchr(path, ':')) != NULL) {
2001     scanelf_dir(p + 1);
2002     *p = 0;
2003     }
2004 vapier 1.17
2005 solar 1.34 free(path);
2006 solar 1.1 }
2007    
2008 vapier 1.221 /* usage / invocation handling functions */ /* Free Flags: c d j u w G H J K P Q U W */
2009     #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZCBhV"
2010 vapier 1.27 #define a_argument required_argument
2011 vapier 1.10 static struct option const long_opts[] = {
2012     {"path", no_argument, NULL, 'p'},
2013     {"ldpath", no_argument, NULL, 'l'},
2014 vapier 1.240 {"use-ldpath",no_argument, NULL, 129},
2015 solar 1.223 {"root", a_argument, NULL, 128},
2016 vapier 1.10 {"recursive", no_argument, NULL, 'R'},
2017 vapier 1.14 {"mount", no_argument, NULL, 'm'},
2018 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
2019 vapier 1.105 {"archives", no_argument, NULL, 'A'},
2020     {"ldcache", no_argument, NULL, 'L'},
2021 vapier 1.101 {"fix", no_argument, NULL, 'X'},
2022 solar 1.127 {"setpax", a_argument, NULL, 'z'},
2023 vapier 1.10 {"pax", no_argument, NULL, 'x'},
2024 solar 1.16 {"header", no_argument, NULL, 'e'},
2025 vapier 1.10 {"textrel", no_argument, NULL, 't'},
2026     {"rpath", no_argument, NULL, 'r'},
2027 vapier 1.32 {"needed", no_argument, NULL, 'n'},
2028 vapier 1.38 {"interp", no_argument, NULL, 'i'},
2029 vapier 1.49 {"bind", no_argument, NULL, 'b'},
2030 vapier 1.84 {"soname", no_argument, NULL, 'S'},
2031 vapier 1.76 {"symbol", a_argument, NULL, 's'},
2032 solar 1.124 {"section", a_argument, NULL, 'k'},
2033 vapier 1.76 {"lib", a_argument, NULL, 'N'},
2034 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
2035 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
2036 solar 1.119 {"etype", a_argument, NULL, 'E'},
2037 solar 1.120 {"bits", a_argument, NULL, 'M'},
2038 solar 1.181 {"endian", no_argument, NULL, 'D'},
2039 solar 1.191 {"osabi", no_argument, NULL, 'I'},
2040     {"eabi", no_argument, NULL, 'Y'},
2041 solar 1.180 {"perms", a_argument, NULL, 'O'},
2042 solar 1.190 {"size", no_argument, NULL, 'Z'},
2043 vapier 1.10 {"all", no_argument, NULL, 'a'},
2044     {"quiet", no_argument, NULL, 'q'},
2045 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
2046 vapier 1.76 {"format", a_argument, NULL, 'F'},
2047     {"from", a_argument, NULL, 'f'},
2048     {"file", a_argument, NULL, 'o'},
2049 vapier 1.221 {"nocolor", no_argument, NULL, 'C'},
2050 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
2051 vapier 1.10 {"help", no_argument, NULL, 'h'},
2052     {"version", no_argument, NULL, 'V'},
2053     {NULL, no_argument, NULL, 0x0}
2054     };
2055 solar 1.57
2056 vapier 1.222 static const char * const opts_help[] = {
2057 vapier 1.10 "Scan all directories in PATH environment",
2058     "Scan all directories in /etc/ld.so.conf",
2059 vapier 1.240 "Use ld.so.conf to show full path (use with -r/-n)",
2060 solar 1.223 "Root directory (use with -l or -p)",
2061 vapier 1.14 "Scan directories recursively",
2062 vapier 1.37 "Don't recursively cross mount points",
2063 vapier 1.101 "Don't scan symlinks",
2064 vapier 1.105 "Scan archives (.a files)",
2065 vapier 1.239 "Utilize ld.so.cache to show full path (use with -r/-n)",
2066 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
2067     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
2068 vapier 1.10 "Print PaX markings",
2069 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
2070 vapier 1.10 "Print TEXTREL information",
2071     "Print RPATH information",
2072 vapier 1.32 "Print NEEDED information",
2073 vapier 1.38 "Print INTERP information",
2074 vapier 1.49 "Print BIND information",
2075 vapier 1.84 "Print SONAME information",
2076 vapier 1.27 "Find a specified symbol",
2077 solar 1.124 "Find a specified section",
2078 vapier 1.72 "Find a specified library",
2079 vapier 1.246 "Use regex rather than string compare (with -s); specify twice for case insensitive",
2080 vapier 1.76 "Locate cause of TEXTREL",
2081 solar 1.129 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
2082 solar 1.120 "Print only ELF files matching numeric bits",
2083 solar 1.181 "Print Endianness",
2084 solar 1.191 "Print OSABI",
2085     "Print EABI (EM_ARM Only)",
2086 solar 1.180 "Print only ELF files matching octal permissions",
2087 solar 1.190 "Print ELF file size",
2088 vapier 1.216 "Print all useful/simple info\n",
2089 vapier 1.14 "Only output 'bad' things",
2090     "Be verbose (can be specified more than once)",
2091 vapier 1.39 "Use specified format for output",
2092 solar 1.45 "Read input stream from a filename",
2093 vapier 1.24 "Write output stream to a filename",
2094 vapier 1.221 "Don't emit color in output",
2095 vapier 1.14 "Don't display the header",
2096 vapier 1.10 "Print this help and exit",
2097     "Print version and exit",
2098     NULL
2099     };
2100    
2101     /* display usage and exit */
2102     static void usage(int status)
2103 solar 1.1 {
2104 vapier 1.256 const char a_arg[] = "<arg>";
2105     size_t a_arg_len = strlen(a_arg) + 2;
2106     size_t i;
2107     int optlen;
2108 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
2109 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
2110 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
2111 vapier 1.256
2112     /* prescan the --long opt length to auto-align */
2113     optlen = 0;
2114     for (i = 0; long_opts[i].name; ++i) {
2115     int l = strlen(long_opts[i].name);
2116     if (long_opts[i].has_arg == a_argument)
2117     l += a_arg_len;
2118     optlen = max(l, optlen);
2119     }
2120    
2121 vapier 1.241 for (i = 0; long_opts[i].name; ++i) {
2122     /* first output the short flag if it has one */
2123     if (long_opts[i].val > '~')
2124     printf(" ");
2125     else
2126     printf(" -%c, ", long_opts[i].val);
2127    
2128     /* then the long flag */
2129 vapier 1.27 if (long_opts[i].has_arg == no_argument)
2130 vapier 1.256 printf("--%-*s", optlen, long_opts[i].name);
2131 vapier 1.27 else
2132 vapier 1.256 printf("--%s %s %*s", long_opts[i].name, a_arg,
2133     (int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
2134 vapier 1.241
2135     /* finally the help text */
2136     printf("* %s\n", opts_help[i]);
2137     }
2138 solar 1.45
2139 vapier 1.173 puts("\nFor more information, see the scanelf(1) manpage");
2140 vapier 1.10 exit(status);
2141 solar 1.1 }
2142    
2143     /* parse command line arguments and preform needed actions */
2144 vapier 1.165 #define do_pax_state(option, flag) \
2145     if (islower(option)) { \
2146     flags &= ~PF_##flag; \
2147     flags |= PF_NO##flag; \
2148     } else { \
2149     flags &= ~PF_NO##flag; \
2150     flags |= PF_##flag; \
2151     }
2152 vapier 1.262 static void parse_delimited(array_t *arr, char *arg, const char *delim)
2153     {
2154     char *ele = strtok(arg, delim);
2155     if (!ele) /* edge case: -s '' */
2156     xarraypush_str(arr, "");
2157     while (ele) {
2158     xarraypush_str(arr, ele);
2159     ele = strtok(NULL, delim);
2160     }
2161     }
2162 solar 1.164 static int parseargs(int argc, char *argv[])
2163 vapier 1.10 {
2164 vapier 1.48 int i;
2165 vapier 1.133 const char *from_file = NULL;
2166 solar 1.164 int ret = 0;
2167 vapier 1.240 char load_cache_config = 0;
2168 vapier 1.10
2169     opterr = 0;
2170 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
2171     switch (i) {
2172 vapier 1.10
2173 vapier 1.39 case 'V':
2174 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
2175     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
2176     VERSION, __FILE__, __DATE__, rcsid, argv0);
2177 vapier 1.10 exit(EXIT_SUCCESS);
2178     break;
2179     case 'h': usage(EXIT_SUCCESS); break;
2180 solar 1.45 case 'f':
2181 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
2182     from_file = optarg;
2183 solar 1.45 break;
2184 solar 1.119 case 'E':
2185 vapier 1.262 /* historically, this was comma delimited */
2186     parse_delimited(match_etypes, optarg, ",");
2187 solar 1.119 break;
2188 solar 1.120 case 'M':
2189     match_bits = atoi(optarg);
2190 solar 1.182 if (match_bits == 0) {
2191     if (strcmp(optarg, "ELFCLASS32") == 0)
2192     match_bits = 32;
2193     if (strcmp(optarg, "ELFCLASS64") == 0)
2194     match_bits = 64;
2195     }
2196 solar 1.120 break;
2197 solar 1.180 case 'O':
2198 vapier 1.205 if (sscanf(optarg, "%o", &match_perms) == -1)
2199 solar 1.180 match_bits = 0;
2200     break;
2201 vapier 1.24 case 'o': {
2202 vapier 1.146 if (freopen(optarg, "w", stdout) == NULL)
2203 vapier 1.237 errp("Could not freopen(%s)", optarg);
2204 solar 1.21 break;
2205     }
2206 solar 1.124 case 'k':
2207 vapier 1.233 xarraypush_str(find_section_arr, optarg);
2208 solar 1.124 break;
2209 vapier 1.262 case 's':
2210 vapier 1.248 /* historically, this was comma delimited */
2211 vapier 1.262 parse_delimited(find_sym_arr, optarg, ",");
2212 vapier 1.39 break;
2213 vapier 1.226 case 'N':
2214 vapier 1.233 xarraypush_str(find_lib_arr, optarg);
2215 vapier 1.72 break;
2216 vapier 1.39 case 'F': {
2217 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
2218     out_format = optarg;
2219 vapier 1.39 break;
2220     }
2221 solar 1.127 case 'z': {
2222 solar 1.129 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
2223 solar 1.127 size_t x;
2224 vapier 1.27
2225 vapier 1.186 for (x = 0; x < strlen(optarg); x++) {
2226     switch (optarg[x]) {
2227 solar 1.127 case 'p':
2228     case 'P':
2229 vapier 1.165 do_pax_state(optarg[x], PAGEEXEC);
2230 solar 1.127 break;
2231     case 's':
2232     case 'S':
2233 vapier 1.165 do_pax_state(optarg[x], SEGMEXEC);
2234 solar 1.127 break;
2235     case 'm':
2236     case 'M':
2237 vapier 1.165 do_pax_state(optarg[x], MPROTECT);
2238 solar 1.127 break;
2239     case 'e':
2240     case 'E':
2241 vapier 1.165 do_pax_state(optarg[x], EMUTRAMP);
2242 solar 1.127 break;
2243     case 'r':
2244     case 'R':
2245 vapier 1.165 do_pax_state(optarg[x], RANDMMAP);
2246 solar 1.127 break;
2247     case 'x':
2248     case 'X':
2249 vapier 1.165 do_pax_state(optarg[x], RANDEXEC);
2250 solar 1.127 break;
2251     default:
2252     break;
2253     }
2254     }
2255     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
2256     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
2257     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
2258     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
2259     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
2260     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
2261     setpax = flags;
2262     break;
2263     }
2264 solar 1.190 case 'Z': show_size = 1; break;
2265 vapier 1.246 case 'g': ++g_match; break;
2266 vapier 1.240 case 'L': load_cache_config = use_ldcache = 1; break;
2267 vapier 1.37 case 'y': scan_symlink = 0; break;
2268 vapier 1.105 case 'A': scan_archives = 1; break;
2269 vapier 1.221 case 'C': color_init(true); break;
2270 solar 1.16 case 'B': show_banner = 0; break;
2271 vapier 1.240 case 'l': load_cache_config = scan_ldpath = 1; break;
2272 vapier 1.10 case 'p': scan_envpath = 1; break;
2273     case 'R': dir_recurse = 1; break;
2274 vapier 1.14 case 'm': dir_crossmount = 0; break;
2275 vapier 1.101 case 'X': ++fix_elf; break;
2276 vapier 1.10 case 'x': show_pax = 1; break;
2277 solar 1.73 case 'e': show_phdr = 1; break;
2278 vapier 1.10 case 't': show_textrel = 1; break;
2279     case 'r': show_rpath = 1; break;
2280 vapier 1.32 case 'n': show_needed = 1; break;
2281 vapier 1.38 case 'i': show_interp = 1; break;
2282 vapier 1.49 case 'b': show_bind = 1; break;
2283 vapier 1.84 case 'S': show_soname = 1; break;
2284 vapier 1.76 case 'T': show_textrels = 1; break;
2285 vapier 1.254 case 'q': be_quiet = min(be_quiet, 20) + 1; break;
2286     case 'v': be_verbose = min(be_verbose, 20) + 1; break;
2287 solar 1.183 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
2288 solar 1.181 case 'D': show_endian = 1; break;
2289 solar 1.191 case 'I': show_osabi = 1; break;
2290     case 'Y': show_eabi = 1; break;
2291 solar 1.223 case 128:
2292 vapier 1.232 root_fd = open(optarg, O_RDONLY|O_CLOEXEC);
2293     if (root_fd == -1)
2294     err("Could not open root: %s", optarg);
2295 solar 1.223 break;
2296 vapier 1.240 case 129: load_cache_config = use_ldpath = 1; break;
2297 vapier 1.10 case ':':
2298 vapier 1.113 err("Option '%c' is missing parameter", optopt);
2299 vapier 1.10 case '?':
2300 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
2301 vapier 1.10 default:
2302 vapier 1.113 err("Unhandled option '%c'; please report this", i);
2303 vapier 1.10 }
2304     }
2305 vapier 1.230 if (show_textrels && be_verbose)
2306 vapier 1.264 objdump = which("objdump", "OBJDUMP");
2307 vapier 1.249 /* precompile all the regexes */
2308     if (g_match) {
2309     regex_t preg;
2310     const char *this_sym;
2311     size_t n;
2312     int flags = REG_EXTENDED | REG_NOSUB | (g_match > 1 ? REG_ICASE : 0);
2313    
2314     array_for_each(find_sym_arr, n, this_sym) {
2315     /* see scanelf_match_symname for logic info */
2316     switch (this_sym[0]) {
2317     case '%':
2318     while (*(this_sym++))
2319     if (*this_sym == '%') {
2320     ++this_sym;
2321     break;
2322     }
2323     break;
2324     case '+':
2325     case '-':
2326     ++this_sym;
2327     break;
2328     }
2329     if (*this_sym == '*')
2330     ++this_sym;
2331    
2332     ret = regcomp(&preg, this_sym, flags);
2333     if (ret) {
2334     char err[256];
2335     regerror(ret, &preg, err, sizeof(err));
2336     err("regcomp of %s failed: %s", this_sym, err);
2337     }
2338     xarraypush(find_sym_regex_arr, &preg, sizeof(preg));
2339     }
2340     }
2341 vapier 1.226 /* flatten arrays for display */
2342 vapier 1.261 find_sym = array_flatten_str(find_sym_arr);
2343     find_lib = array_flatten_str(find_lib_arr);
2344     find_section = array_flatten_str(find_section_arr);
2345 vapier 1.39 /* let the format option override all other options */
2346     if (out_format) {
2347 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
2348 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
2349 solar 1.191 show_textrels = show_perms = show_endian = show_size = \
2350     show_osabi = show_eabi = 0;
2351 vapier 1.48 for (i = 0; out_format[i]; ++i) {
2352 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
2353 vapier 1.39
2354 vapier 1.48 switch (out_format[++i]) {
2355 solar 1.132 case '+': break;
2356 vapier 1.39 case '%': break;
2357 vapier 1.70 case '#': break;
2358 vapier 1.39 case 'F': break;
2359 vapier 1.66 case 'p': break;
2360     case 'f': break;
2361 solar 1.124 case 'k': break;
2362 vapier 1.39 case 's': break;
2363 vapier 1.72 case 'N': break;
2364 vapier 1.41 case 'o': break;
2365 vapier 1.166 case 'a': break;
2366 vapier 1.171 case 'M': break;
2367 solar 1.190 case 'Z': show_size = 1; break;
2368 solar 1.181 case 'D': show_endian = 1; break;
2369 solar 1.191 case 'I': show_osabi = 1; break;
2370     case 'Y': show_eabi = 1; break;
2371 solar 1.180 case 'O': show_perms = 1; break;
2372 vapier 1.39 case 'x': show_pax = 1; break;
2373 solar 1.73 case 'e': show_phdr = 1; break;
2374 vapier 1.39 case 't': show_textrel = 1; break;
2375     case 'r': show_rpath = 1; break;
2376     case 'n': show_needed = 1; break;
2377     case 'i': show_interp = 1; break;
2378 vapier 1.49 case 'b': show_bind = 1; break;
2379 vapier 1.84 case 'S': show_soname = 1; break;
2380 vapier 1.76 case 'T': show_textrels = 1; break;
2381 vapier 1.39 default:
2382 vapier 1.240 err("invalid format specifier '%c' (byte %i)",
2383 vapier 1.48 out_format[i], i+1);
2384 vapier 1.39 }
2385     }
2386 vapier 1.41
2387     /* construct our default format */
2388     } else {
2389     size_t fmt_len = 30;
2390 vapier 1.186 out_format = xmalloc(sizeof(char) * fmt_len);
2391 vapier 1.194 *out_format = '\0';
2392 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
2393     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
2394 solar 1.180 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
2395 solar 1.190 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
2396 solar 1.181 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
2397 solar 1.191 if (show_osabi) xstrcat(&out_format, "%I ", &fmt_len);
2398     if (show_eabi) xstrcat(&out_format, "%Y ", &fmt_len);
2399 vapier 1.76 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
2400     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
2401     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
2402     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
2403     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
2404     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
2405 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
2406 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
2407     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
2408 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
2409 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
2410     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
2411 vapier 1.39 }
2412 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
2413 vapier 1.39
2414     /* now lets actually do the scanning */
2415 vapier 1.240 if (load_cache_config)
2416     load_ld_cache_config(__PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
2417 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
2418     if (scan_envpath) scanelf_envpath();
2419 solar 1.153 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
2420 vapier 1.133 from_file = "-";
2421 solar 1.45 if (from_file) {
2422     scanelf_from_file(from_file);
2423     from_file = *argv;
2424     }
2425     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
2426 vapier 1.25 err("Nothing to scan !?");
2427 vapier 1.66 while (optind < argc) {
2428     search_path = argv[optind++];
2429 solar 1.164 ret = scanelf_dir(search_path);
2430 vapier 1.66 }
2431 vapier 1.27
2432 vapier 1.250 #ifdef __PAX_UTILS_CLEANUP
2433 vapier 1.39 /* clean up */
2434 vapier 1.227 xarrayfree(ldpaths);
2435 vapier 1.248 xarrayfree(find_sym_arr);
2436 vapier 1.227 xarrayfree(find_lib_arr);
2437     xarrayfree(find_section_arr);
2438 vapier 1.248 free(find_sym);
2439 vapier 1.226 free(find_lib);
2440     free(find_section);
2441 vapier 1.249 {
2442     size_t n;
2443     regex_t *preg;
2444     array_for_each(find_sym_regex_arr, n, preg)
2445     regfree(preg);
2446     xarrayfree(find_sym_regex_arr);
2447     }
2448 solar 1.96
2449     if (ldcache != 0)
2450     munmap(ldcache, ldcache_size);
2451 vapier 1.250 #endif
2452    
2453 solar 1.164 return ret;
2454 vapier 1.10 }
2455    
2456 vapier 1.150 static char **get_split_env(const char *envvar)
2457     {
2458 vapier 1.152 const char *delims = " \t\n";
2459 solar 1.143 char **envvals = NULL;
2460 vapier 1.152 char *env, *s;
2461 kevquinn 1.142 int nentry;
2462    
2463 solar 1.143 if ((env = getenv(envvar)) == NULL)
2464     return NULL;
2465 kevquinn 1.142
2466 solar 1.143 env = xstrdup(env);
2467     if (env == NULL)
2468     return NULL;
2469 kevquinn 1.142
2470 vapier 1.152 s = strtok(env, delims);
2471     if (s == NULL) {
2472     free(env);
2473     return NULL;
2474     }
2475    
2476 solar 1.143 nentry = 0;
2477 vapier 1.152 while (s != NULL) {
2478     ++nentry;
2479     envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
2480     envvals[nentry-1] = s;
2481     s = strtok(NULL, delims);
2482 kevquinn 1.142 }
2483 vapier 1.152 envvals[nentry] = NULL;
2484 kevquinn 1.142
2485 vapier 1.152 /* don't want to free(env) as it contains the memory that backs
2486     * the envvals array of strings */
2487 kevquinn 1.142 return envvals;
2488     }
2489 solar 1.181
2490 vapier 1.184 static void parseenv(void)
2491 vapier 1.150 {
2492 vapier 1.221 color_init(false);
2493 vapier 1.150 qa_textrels = get_split_env("QA_TEXTRELS");
2494     qa_execstack = get_split_env("QA_EXECSTACK");
2495     qa_wx_load = get_split_env("QA_WX_LOAD");
2496 vapier 1.41 }
2497 solar 1.163
2498 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
2499 vapier 1.184 static void cleanup(void)
2500 vapier 1.152 {
2501     free(out_format);
2502     free(qa_textrels);
2503     free(qa_execstack);
2504     free(qa_wx_load);
2505     }
2506     #endif
2507 vapier 1.41
2508 vapier 1.10 int main(int argc, char *argv[])
2509 solar 1.1 {
2510 solar 1.164 int ret;
2511 vapier 1.10 if (argc < 2)
2512     usage(EXIT_FAILURE);
2513 kevquinn 1.142 parseenv();
2514 solar 1.164 ret = parseargs(argc, argv);
2515 solar 1.21 fclose(stdout);
2516 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
2517     cleanup();
2518     warn("The calls to add/delete heap should be off:\n"
2519 vapier 1.232 "\t- 1 due to the out_buffer not being freed in scanelf_fileat()\n"
2520 vapier 1.152 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
2521 solar 1.61 #endif
2522 solar 1.164 return ret;
2523 solar 1.1 }
2524 vapier 1.155
2525     /* Match filename against entries in matchlist, return TRUE
2526     * if the file is listed */
2527     static int file_matches_list(const char *filename, char **matchlist)
2528     {
2529     char **file;
2530     char *match;
2531     char buf[__PAX_UTILS_PATH_MAX];
2532    
2533     if (matchlist == NULL)
2534     return 0;
2535    
2536     for (file = matchlist; *file != NULL; file++) {
2537     if (search_path) {
2538     snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2539     match = buf;
2540     } else {
2541     match = *file;
2542     }
2543     if (fnmatch(match, filename, 0) == 0)
2544     return 1;
2545     }
2546     return 0;
2547     }

  ViewVC Help
Powered by ViewVC 1.1.20