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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.226 - (hide annotations) (download) (as text)
Tue Sep 27 18:37:22 2011 UTC (3 years, 1 month ago) by vapier
Branch: MAIN
Changes since 1.225: +51 -18 lines
File MIME type: text/x-csrc
allow people to search for multiple libraries (-N) or data sections (-k)

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

  ViewVC Help
Powered by ViewVC 1.1.20