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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.144 - (hide annotations) (download) (as text)
Sun May 14 03:40:33 2006 UTC (8 years, 4 months ago) by solar
Branch: MAIN
Changes since 1.143: +3 -3 lines
File MIME type: text/x-csrc
- make sure we scan versioned symbols correctly on unstripped ELF files

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

  ViewVC Help
Powered by ViewVC 1.1.20