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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.212 - (hide annotations) (download) (as text)
Sun Mar 15 09:13:20 2009 UTC (5 years, 1 month ago) by vapier
Branch: MAIN
Changes since 1.211: +32 -20 lines
File MIME type: text/x-csrc
cleanup lookup_cache_lib() and return first match, not last #258090

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

  ViewVC Help
Powered by ViewVC 1.1.20