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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.146 - (hide annotations) (download) (as text)
Sun May 14 21:04:25 2006 UTC (8 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.145: +3 -5 lines
File MIME type: text/x-csrc
SET_STDOUT isnt needed

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

  ViewVC Help
Powered by ViewVC 1.1.20