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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.123 - (hide annotations) (download) (as text)
Sun Feb 12 16:51:21 2006 UTC (10 years, 9 months ago) by solar
Branch: MAIN
Changes since 1.122: +43 -10 lines
File MIME type: text/x-csrc
- add include globbing support for ld.so.conf handling. mainly only useful on distros other than gentoo

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

  ViewVC Help
Powered by ViewVC 1.1.20