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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.108 - (hide annotations) (download) (as text)
Thu Jan 19 23:53:34 2006 UTC (8 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.107: +10 -3 lines
File MIME type: text/x-csrc
add some sanity checks to program header scanning

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

  ViewVC Help
Powered by ViewVC 1.1.20