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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.232 - (hide annotations) (download) (as text)
Tue Sep 27 22:20:07 2011 UTC (3 years, 1 month ago) by vapier
Branch: MAIN
Changes since 1.231: +111 -64 lines
File MIME type: text/x-csrc
redo root support to use *at funcs and avoid memory operations where possible

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

  ViewVC Help
Powered by ViewVC 1.1.20