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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.150 - (hide annotations) (download) (as text)
Sun May 14 21:37:55 2006 UTC (8 years, 3 months ago) by vapier
Branch: MAIN
Changes since 1.149: +13 -10 lines
File MIME type: text/x-csrc
touchup style

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

  ViewVC Help
Powered by ViewVC 1.1.20