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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.125 - (hide annotations) (download) (as text)
Thu Feb 16 05:06:14 2006 UTC (8 years, 10 months ago) by solar
Branch: MAIN
Changes since 1.124: +4 -4 lines
File MIME type: text/x-csrc
- add -k option to manpage and -vh output

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

  ViewVC Help
Powered by ViewVC 1.1.20