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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.121 - (hide annotations) (download) (as text)
Sun Feb 5 17:10:52 2006 UTC (8 years, 7 months ago) by solar
Branch: MAIN
Changes since 1.120: +5 -2 lines
File MIME type: text/x-csrc
- print ELF e_types when -h flag is given. Add missing PT_NUM to paxelf.c. Document new -M feature.

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

  ViewVC Help
Powered by ViewVC 1.1.20