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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.122 - (hide annotations) (download) (as text)
Sat Feb 11 04:11:44 2006 UTC (8 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.121: +3 -7 lines
File MIME type: text/x-csrc
dont bother eating spaces anymore as our format string should cover that

1 solar 1.1 /*
2 vapier 1.98 * Copyright 2003-2006 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 vapier 1.122 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.121 2006/02/05 17:10:52 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 vapier 1.122 static const char *rcsid = "$Id: scanelf.c,v 1.121 2006/02/05 17:10:52 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 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
942 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
943     continue;
944     }
945 vapier 1.39
946 vapier 1.41 out = NULL;
947 vapier 1.70 be_wewy_wewy_quiet = (out_format[i] == '#');
948 vapier 1.41 switch (out_format[++i]) {
949 vapier 1.70 case '%':
950     case '#':
951     xchrcat(&out_buffer, out_format[i], &out_len); break;
952     case 'F':
953 vapier 1.76 found_file = 1;
954 vapier 1.70 if (be_wewy_wewy_quiet) break;
955 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
956 vapier 1.70 break;
957 vapier 1.66 case 'p':
958 vapier 1.76 found_file = 1;
959 vapier 1.70 if (be_wewy_wewy_quiet) break;
960 vapier 1.106 tmp = elf->filename;
961 vapier 1.66 if (search_path) {
962     ssize_t len_search = strlen(search_path);
963 vapier 1.106 ssize_t len_file = strlen(elf->filename);
964     if (!strncmp(elf->filename, search_path, len_search) && \
965 vapier 1.66 len_file > len_search)
966     tmp += len_search;
967     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
968     }
969     xstrcat(&out_buffer, tmp, &out_len);
970     break;
971     case 'f':
972 vapier 1.76 found_file = 1;
973 vapier 1.70 if (be_wewy_wewy_quiet) break;
974 vapier 1.106 tmp = strrchr(elf->filename, '/');
975     tmp = (tmp == NULL ? elf->filename : tmp+1);
976 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
977     break;
978 vapier 1.41 case 'o': out = get_elfetype(elf); break;
979     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
980 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
981 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
982 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
983 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
984 vapier 1.72 case 'n':
985     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
986 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
987 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
988 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
989 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
990 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
991 vapier 1.29 }
992 vapier 1.95 if (out) {
993     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
994     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
995     xstrncat(&out_buffer, out, &out_len, (tmp-out));
996     else
997     xstrcat(&out_buffer, out, &out_len);
998     }
999 vapier 1.39 }
1000    
1001 vapier 1.54 #define FOUND_SOMETHING() \
1002 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1003 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1004 vapier 1.84 found_soname || found_sym || found_lib || found_textrels)
1005 vapier 1.54
1006     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1007     xchrcat(&out_buffer, ' ', &out_len);
1008 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1009 vapier 1.27 }
1010 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1011 vapier 1.41 puts(out_buffer);
1012 vapier 1.79 fflush(stdout);
1013     }
1014 vapier 1.10
1015 vapier 1.105 return 0;
1016     }
1017    
1018 vapier 1.106 /* scan a single elf */
1019     static int scanelf_elf(const char *filename, int fd, size_t len)
1020     {
1021 solar 1.120 int ret = 1;
1022 vapier 1.106 elfobj *elf;
1023    
1024     /* verify this is real ELF */
1025     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1026     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1027 solar 1.120 return ret;
1028     }
1029     switch (match_bits) {
1030     case 32:
1031     if (elf->elf_class != ELFCLASS32)
1032     goto label_done;
1033     break;
1034     case 64:
1035     if (elf->elf_class != ELFCLASS64)
1036     goto label_done;
1037     break;
1038     default: break;
1039 vapier 1.106 }
1040 solar 1.119 if (strlen(match_etypes)) {
1041     char sbuf[126];
1042     strncpy(sbuf, match_etypes, sizeof(sbuf));
1043     if (strchr(match_etypes, ',') != NULL) {
1044     char *p;
1045     while((p = strrchr(sbuf, ',')) != NULL) {
1046     *p = 0;
1047     if (atoi(p+1) == get_etype(elf))
1048     goto label_ret;
1049     }
1050     }
1051 solar 1.120 if (atoi(sbuf) != get_etype(elf))
1052 solar 1.119 goto label_done;
1053     }
1054    
1055     label_ret:
1056 vapier 1.106 ret = scanelf_elfobj(elf);
1057 solar 1.119
1058     label_done:
1059 vapier 1.106 unreadelf(elf);
1060     return ret;
1061     }
1062 solar 1.119
1063 vapier 1.105 /* scan an archive of elfs */
1064 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1065 vapier 1.105 {
1066 vapier 1.106 archive_handle *ar;
1067 vapier 1.105 archive_member *m;
1068 vapier 1.106 char *ar_buffer;
1069     elfobj *elf;
1070    
1071     ar = ar_open_fd(filename, fd);
1072     if (ar == NULL)
1073     return 1;
1074    
1075     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1076     while ((m=ar_next(ar)) != NULL) {
1077     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1078     if (elf) {
1079     scanelf_elfobj(elf);
1080     unreadelf(elf);
1081     }
1082     }
1083     munmap(ar_buffer, len);
1084    
1085 vapier 1.105 return 0;
1086     }
1087     /* scan a file which may be an elf or an archive or some other magical beast */
1088     static void scanelf_file(const char *filename)
1089     {
1090     struct stat st;
1091 vapier 1.106 int fd;
1092 vapier 1.105
1093     /* make sure 'filename' exists */
1094     if (lstat(filename, &st) == -1) {
1095     if (be_verbose > 2) printf("%s: does not exist\n", filename);
1096     return;
1097     }
1098    
1099     /* always handle regular files and handle symlinked files if no -y */
1100     if (S_ISLNK(st.st_mode)) {
1101     if (!scan_symlink) return;
1102     stat(filename, &st);
1103     }
1104     if (!S_ISREG(st.st_mode)) {
1105     if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1106     return;
1107     }
1108    
1109 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1110     return;
1111    
1112     if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1113 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1114 vapier 1.106 scanelf_archive(filename, fd, st.st_size);
1115    
1116     close(fd);
1117 solar 1.6 }
1118    
1119 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1120 vapier 1.10 static void scanelf_dir(const char *path)
1121 solar 1.1 {
1122 vapier 1.10 register DIR *dir;
1123     register struct dirent *dentry;
1124 vapier 1.14 struct stat st_top, st;
1125 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1126 vapier 1.32 size_t pathlen = 0, len = 0;
1127 vapier 1.10
1128     /* make sure path exists */
1129 vapier 1.39 if (lstat(path, &st_top) == -1) {
1130     if (be_verbose > 2) printf("%s: does not exist\n", path);
1131 vapier 1.10 return;
1132 vapier 1.39 }
1133 solar 1.11
1134 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1135 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1136 vapier 1.10 scanelf_file(path);
1137     return;
1138     }
1139    
1140     /* now scan the dir looking for fun stuff */
1141     if ((dir = opendir(path)) == NULL) {
1142     warnf("could not opendir %s: %s", path, strerror(errno));
1143     return;
1144     }
1145 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1146 solar 1.11
1147 vapier 1.32 pathlen = strlen(path);
1148 vapier 1.10 while ((dentry = readdir(dir))) {
1149     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1150     continue;
1151 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1152     if (len >= sizeof(buf)) {
1153 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1154     (unsigned long)len, (unsigned long)sizeof(buf));
1155 vapier 1.32 continue;
1156     }
1157 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
1158 solar 1.20 if (lstat(buf, &st) != -1) {
1159 vapier 1.10 if (S_ISREG(st.st_mode))
1160 solar 1.20 scanelf_file(buf);
1161 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1162 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1163 solar 1.20 scanelf_dir(buf);
1164 vapier 1.10 }
1165     }
1166     }
1167     closedir(dir);
1168 solar 1.1 }
1169    
1170 vapier 1.47 static int scanelf_from_file(char *filename)
1171     {
1172 solar 1.45 FILE *fp = NULL;
1173     char *p;
1174 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1175 solar 1.45
1176     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
1177     fp = stdin;
1178     else if ((fp = fopen(filename, "r")) == NULL)
1179     return 1;
1180    
1181 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1182 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1183     *p = 0;
1184 vapier 1.66 search_path = path;
1185 solar 1.45 scanelf_dir(path);
1186     }
1187     if (fp != stdin)
1188     fclose(fp);
1189     return 0;
1190     }
1191    
1192 vapier 1.48 static void load_ld_so_conf()
1193     {
1194     FILE *fp = NULL;
1195     char *p;
1196 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1197 vapier 1.48 int i = 0;
1198    
1199     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
1200     return;
1201    
1202 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1203 vapier 1.48 if (*path != '/')
1204     continue;
1205    
1206     if ((p = strrchr(path, '\r')) != NULL)
1207     *p = 0;
1208     if ((p = strchr(path, '\n')) != NULL)
1209     *p = 0;
1210    
1211     ldpaths[i++] = xstrdup(path);
1212    
1213     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1214     break;
1215     }
1216     ldpaths[i] = NULL;
1217    
1218     fclose(fp);
1219     }
1220    
1221 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1222     static void scanelf_ldpath()
1223     {
1224 vapier 1.17 char scan_l, scan_ul, scan_ull;
1225 vapier 1.48 int i = 0;
1226 vapier 1.10
1227 vapier 1.48 if (!ldpaths[0])
1228     err("Unable to load any paths from ld.so.conf");
1229 vapier 1.10
1230 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1231    
1232 vapier 1.48 while (ldpaths[i]) {
1233     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1234     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1235     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1236     scanelf_dir(ldpaths[i]);
1237     ++i;
1238     }
1239 vapier 1.10
1240 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1241     if (!scan_ul) scanelf_dir("/usr/lib");
1242     if (!scan_ull) scanelf_dir("/usr/local/lib");
1243 vapier 1.10 }
1244 solar 1.1
1245 vapier 1.10 /* scan env PATH for paths */
1246     static void scanelf_envpath()
1247 solar 1.1 {
1248 solar 1.34 char *path, *p;
1249 vapier 1.10
1250     path = getenv("PATH");
1251     if (!path)
1252     err("PATH is not set in your env !");
1253 vapier 1.41 path = xstrdup(path);
1254 vapier 1.10
1255     while ((p = strrchr(path, ':')) != NULL) {
1256     scanelf_dir(p + 1);
1257     *p = 0;
1258     }
1259 vapier 1.17
1260 solar 1.34 free(path);
1261 solar 1.1 }
1262    
1263    
1264 vapier 1.10 /* usage / invocation handling functions */
1265 solar 1.120 #define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:M:E:BhV"
1266 vapier 1.27 #define a_argument required_argument
1267 vapier 1.10 static struct option const long_opts[] = {
1268     {"path", no_argument, NULL, 'p'},
1269     {"ldpath", no_argument, NULL, 'l'},
1270     {"recursive", no_argument, NULL, 'R'},
1271 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1272 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1273 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1274     {"ldcache", no_argument, NULL, 'L'},
1275 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1276 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1277 solar 1.16 {"header", no_argument, NULL, 'e'},
1278 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1279     {"rpath", no_argument, NULL, 'r'},
1280 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1281 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1282 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1283 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1284 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1285     {"lib", a_argument, NULL, 'N'},
1286 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1287 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1288 solar 1.119 {"etype", a_argument, NULL, 'E'},
1289 solar 1.120 {"bits", a_argument, NULL, 'M'},
1290 vapier 1.10 {"all", no_argument, NULL, 'a'},
1291     {"quiet", no_argument, NULL, 'q'},
1292 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1293 vapier 1.76 {"format", a_argument, NULL, 'F'},
1294     {"from", a_argument, NULL, 'f'},
1295     {"file", a_argument, NULL, 'o'},
1296 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1297 vapier 1.10 {"help", no_argument, NULL, 'h'},
1298     {"version", no_argument, NULL, 'V'},
1299     {NULL, no_argument, NULL, 0x0}
1300     };
1301 solar 1.57
1302 solar 1.68 static const char *opts_help[] = {
1303 vapier 1.10 "Scan all directories in PATH environment",
1304     "Scan all directories in /etc/ld.so.conf",
1305 vapier 1.14 "Scan directories recursively",
1306 vapier 1.37 "Don't recursively cross mount points",
1307 vapier 1.101 "Don't scan symlinks",
1308 vapier 1.105 "Scan archives (.a files)",
1309     "Utilize ld.so.cache information (use with -r/-n)",
1310 vapier 1.101 "Try and 'fix' bad things (use with -r/-e)\n",
1311 vapier 1.10 "Print PaX markings",
1312 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1313 vapier 1.10 "Print TEXTREL information",
1314     "Print RPATH information",
1315 vapier 1.32 "Print NEEDED information",
1316 vapier 1.38 "Print INTERP information",
1317 vapier 1.49 "Print BIND information",
1318 vapier 1.84 "Print SONAME information",
1319 vapier 1.27 "Find a specified symbol",
1320 vapier 1.72 "Find a specified library",
1321 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1322 vapier 1.76 "Locate cause of TEXTREL",
1323 solar 1.120 "Print only ELF files matching numeric constant type",
1324     "Print only ELF files matching numeric bits",
1325 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1326 vapier 1.14 "Only output 'bad' things",
1327     "Be verbose (can be specified more than once)",
1328 vapier 1.39 "Use specified format for output",
1329 solar 1.45 "Read input stream from a filename",
1330 vapier 1.24 "Write output stream to a filename",
1331 vapier 1.14 "Don't display the header",
1332 vapier 1.10 "Print this help and exit",
1333     "Print version and exit",
1334     NULL
1335     };
1336    
1337     /* display usage and exit */
1338     static void usage(int status)
1339 solar 1.1 {
1340 vapier 1.44 unsigned long i;
1341 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1342 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1343 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1344 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1345 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1346 solar 1.52 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
1347 vapier 1.27 long_opts[i].name, opts_help[i]);
1348     else
1349 solar 1.52 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
1350 vapier 1.27 long_opts[i].name, opts_help[i]);
1351 solar 1.45
1352     if (status != EXIT_SUCCESS)
1353     exit(status);
1354    
1355 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
1356 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1357     puts(" t TEXTREL \tr RPATH \tn NEEDED");
1358     puts(" i INTERP \tb BIND \ts symbol");
1359 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
1360 vapier 1.88 puts(" S SONAME");
1361 vapier 1.70 puts(" p filename (with search path removed)");
1362 vapier 1.88 puts(" f filename (short name/basename)");
1363 vapier 1.70 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1364 solar 1.45
1365 solar 1.121 puts("\nELF Etypes:");
1366     print_etypes(stdout);
1367    
1368 vapier 1.10 exit(status);
1369 solar 1.1 }
1370    
1371     /* parse command line arguments and preform needed actions */
1372 vapier 1.10 static void parseargs(int argc, char *argv[])
1373     {
1374 vapier 1.48 int i;
1375 solar 1.45 char *from_file = NULL;
1376 vapier 1.10
1377     opterr = 0;
1378 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1379     switch (i) {
1380 vapier 1.10
1381 vapier 1.39 case 'V':
1382 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1383     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1384     VERSION, __FILE__, __DATE__, rcsid, argv0);
1385 vapier 1.10 exit(EXIT_SUCCESS);
1386     break;
1387     case 'h': usage(EXIT_SUCCESS); break;
1388 solar 1.45 case 'f':
1389 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1390     from_file = optarg;
1391 solar 1.45 break;
1392 solar 1.119 case 'E':
1393     strncpy(match_etypes, optarg, sizeof(match_etypes));
1394     break;
1395 solar 1.120 case 'M':
1396     match_bits = atoi(optarg);
1397     break;
1398 vapier 1.24 case 'o': {
1399 solar 1.21 FILE *fp = NULL;
1400 solar 1.64 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1401 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1402 vapier 1.65 SET_STDOUT(fp);
1403 solar 1.21 break;
1404     }
1405 vapier 1.24
1406 vapier 1.39 case 's': {
1407 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1408     find_sym = optarg;
1409     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1410 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1411     break;
1412     }
1413 vapier 1.72 case 'N': {
1414 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1415     find_lib = optarg;
1416 vapier 1.72 break;
1417     }
1418 vapier 1.39
1419     case 'F': {
1420 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1421     out_format = optarg;
1422 vapier 1.39 break;
1423     }
1424 vapier 1.27
1425 vapier 1.122 case 'g': gmatch = 1; break;
1426 vapier 1.102 case 'L': use_ldcache = 1; break;
1427 vapier 1.37 case 'y': scan_symlink = 0; break;
1428 vapier 1.105 case 'A': scan_archives = 1; break;
1429 solar 1.16 case 'B': show_banner = 0; break;
1430 vapier 1.10 case 'l': scan_ldpath = 1; break;
1431     case 'p': scan_envpath = 1; break;
1432     case 'R': dir_recurse = 1; break;
1433 vapier 1.14 case 'm': dir_crossmount = 0; break;
1434 vapier 1.101 case 'X': ++fix_elf; break;
1435 vapier 1.10 case 'x': show_pax = 1; break;
1436 solar 1.73 case 'e': show_phdr = 1; break;
1437 vapier 1.10 case 't': show_textrel = 1; break;
1438     case 'r': show_rpath = 1; break;
1439 vapier 1.32 case 'n': show_needed = 1; break;
1440 vapier 1.38 case 'i': show_interp = 1; break;
1441 vapier 1.49 case 'b': show_bind = 1; break;
1442 vapier 1.84 case 'S': show_soname = 1; break;
1443 vapier 1.76 case 'T': show_textrels = 1; break;
1444 vapier 1.10 case 'q': be_quiet = 1; break;
1445 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1446 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1447 vapier 1.10
1448     case ':':
1449 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1450 vapier 1.10 case '?':
1451 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1452 vapier 1.10 default:
1453 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1454 vapier 1.10 }
1455     }
1456    
1457 vapier 1.39 /* let the format option override all other options */
1458     if (out_format) {
1459 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1460 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1461     show_textrels = 0;
1462 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1463 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1464 vapier 1.39
1465 vapier 1.48 switch (out_format[++i]) {
1466 vapier 1.39 case '%': break;
1467 vapier 1.70 case '#': break;
1468 vapier 1.39 case 'F': break;
1469 vapier 1.66 case 'p': break;
1470     case 'f': break;
1471 vapier 1.39 case 's': break;
1472 vapier 1.72 case 'N': break;
1473 vapier 1.41 case 'o': break;
1474 vapier 1.39 case 'x': show_pax = 1; break;
1475 solar 1.73 case 'e': show_phdr = 1; break;
1476 vapier 1.39 case 't': show_textrel = 1; break;
1477     case 'r': show_rpath = 1; break;
1478     case 'n': show_needed = 1; break;
1479     case 'i': show_interp = 1; break;
1480 vapier 1.49 case 'b': show_bind = 1; break;
1481 vapier 1.84 case 'S': show_soname = 1; break;
1482 vapier 1.76 case 'T': show_textrels = 1; break;
1483 vapier 1.39 default:
1484     err("Invalid format specifier '%c' (byte %i)",
1485 vapier 1.48 out_format[i], i+1);
1486 vapier 1.39 }
1487     }
1488 vapier 1.41
1489     /* construct our default format */
1490     } else {
1491     size_t fmt_len = 30;
1492     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1493 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1494     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1495     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1496     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1497     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1498     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1499     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1500     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1501 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1502 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1503     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1504     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1505     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1506 vapier 1.39 }
1507 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1508 vapier 1.39
1509     /* now lets actually do the scanning */
1510 vapier 1.102 if (scan_ldpath || use_ldcache)
1511 vapier 1.48 load_ld_so_conf();
1512 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1513     if (scan_envpath) scanelf_envpath();
1514 solar 1.45 if (from_file) {
1515     scanelf_from_file(from_file);
1516     from_file = *argv;
1517     }
1518     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1519 vapier 1.25 err("Nothing to scan !?");
1520 vapier 1.66 while (optind < argc) {
1521     search_path = argv[optind++];
1522     scanelf_dir(search_path);
1523     }
1524 vapier 1.27
1525 vapier 1.39 /* clean up */
1526 vapier 1.93 if (versioned_symname) free(versioned_symname);
1527 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1528     free(ldpaths[i]);
1529 solar 1.96
1530     if (ldcache != 0)
1531     munmap(ldcache, ldcache_size);
1532 vapier 1.10 }
1533    
1534    
1535    
1536 vapier 1.41 /* utility funcs */
1537 vapier 1.60 static char *xstrdup(const char *s)
1538 vapier 1.41 {
1539     char *ret = strdup(s);
1540     if (!ret) err("Could not strdup(): %s", strerror(errno));
1541     return ret;
1542     }
1543     static void *xmalloc(size_t size)
1544     {
1545     void *ret = malloc(size);
1546     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1547     return ret;
1548     }
1549 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1550 vapier 1.41 {
1551 vapier 1.69 size_t new_len;
1552 vapier 1.41
1553     new_len = strlen(*dst) + strlen(src);
1554     if (*curr_len <= new_len) {
1555     *curr_len = new_len + (*curr_len / 2);
1556     *dst = realloc(*dst, *curr_len);
1557     if (!*dst)
1558 vapier 1.95 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1559 vapier 1.41 }
1560    
1561 vapier 1.95 if (n)
1562     strncat(*dst, src, n);
1563     else
1564     strcat(*dst, src);
1565 vapier 1.41 }
1566     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1567     {
1568     static char my_app[2];
1569     my_app[0] = append;
1570     my_app[1] = '\0';
1571     xstrcat(dst, my_app, curr_len);
1572     }
1573    
1574    
1575 vapier 1.72
1576 vapier 1.10 int main(int argc, char *argv[])
1577 solar 1.1 {
1578 vapier 1.10 if (argc < 2)
1579     usage(EXIT_FAILURE);
1580     parseargs(argc, argv);
1581 solar 1.21 fclose(stdout);
1582 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1583 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()");
1584 solar 1.61 #endif
1585 vapier 1.10 return EXIT_SUCCESS;
1586 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20