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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.218 - (hide annotations) (download) (as text)
Fri Jan 15 11:56:15 2010 UTC (4 years, 11 months ago) by vapier
Branch: MAIN
Changes since 1.217: +7 -4 lines
File MIME type: text/x-csrc
check return value of lseek for errors

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

  ViewVC Help
Powered by ViewVC 1.1.20