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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.208 - (hide annotations) (download) (as text)
Sat Jan 31 17:58:37 2009 UTC (5 years, 5 months ago) by grobian
Branch: MAIN
Changes since 1.207: +3 -3 lines
File MIME type: text/x-csrc
For bug #249731, add an xstrndup wrapper, and implement strndup on hosts that don't have it, based on the strndup implementation of sandbox, with a little change to make it C90 compliant.

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

  ViewVC Help
Powered by ViewVC 1.1.20