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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.214 - (hide annotations) (download) (as text)
Tue Dec 1 10:19:42 2009 UTC (4 years, 10 months ago) by vapier
Branch: MAIN
Changes since 1.213: +118 -52 lines
File MIME type: text/x-csrc
extend symbol lookup syntax to allow matching of symbols based on more fields

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

  ViewVC Help
Powered by ViewVC 1.1.20