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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.115 - (hide annotations) (download) (as text)
Tue Jan 24 00:34:00 2006 UTC (8 years, 11 months ago) by vapier
Branch: MAIN
Changes since 1.114: +7 -5 lines
File MIME type: text/x-csrc
fix up handling of corrupt symbol tables

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

  ViewVC Help
Powered by ViewVC 1.1.20