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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.148 - (hide annotations) (download) (as text)
Sun May 14 21:18:38 2006 UTC (8 years, 6 months ago) by vapier
Branch: MAIN
Changes since 1.147: +22 -13 lines
File MIME type: text/x-csrc
cut down on the arch-specific ifdef cruft

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

  ViewVC Help
Powered by ViewVC 1.1.20