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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.92 - (hide annotations) (download) (as text)
Fri Dec 9 01:41:32 2005 UTC (8 years, 9 months ago) by vapier
Branch: MAIN
Changes since 1.91: +2 -3 lines
File MIME type: text/x-csrc
remove __USE_GNU

1 solar 1.1 /*
2 solar 1.63 * Copyright 2003-2005 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 vapier 1.92 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.91 2005/12/07 01:04:52 vapier Exp $
5 solar 1.1 *
6 vapier 1.87 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10     #include <stdio.h>
11     #include <stdlib.h>
12     #include <sys/types.h>
13 vapier 1.60 #include <libgen.h>
14     #include <limits.h>
15 solar 1.1 #include <string.h>
16 vapier 1.10 #include <errno.h>
17 solar 1.1 #include <unistd.h>
18     #include <sys/stat.h>
19     #include <dirent.h>
20     #include <getopt.h>
21 solar 1.20 #include <assert.h>
22 vapier 1.89 #include "paxinc.h"
23 solar 1.1
24 vapier 1.92 static const char *rcsid = "$Id: scanelf.c,v 1.91 2005/12/07 01:04:52 vapier Exp $";
25 vapier 1.36 #define argv0 "scanelf"
26 vapier 1.10
27 vapier 1.70 #define IS_MODIFIER(c) (c == '%' || c == '#')
28    
29 vapier 1.10
30    
31     /* prototypes */
32     static void scanelf_file(const char *filename);
33     static void scanelf_dir(const char *path);
34     static void scanelf_ldpath();
35     static void scanelf_envpath();
36     static void usage(int status);
37     static void parseargs(int argc, char *argv[]);
38 vapier 1.60 static char *xstrdup(const char *s);
39 vapier 1.41 static void *xmalloc(size_t size);
40     static void xstrcat(char **dst, const char *src, size_t *curr_len);
41     static inline void xchrcat(char **dst, const char append, size_t *curr_len);
42 vapier 1.10
43     /* variables to control behavior */
44 vapier 1.48 static char *ldpaths[256];
45 vapier 1.10 static char scan_ldpath = 0;
46     static char scan_envpath = 0;
47 vapier 1.37 static char scan_symlink = 1;
48 vapier 1.10 static char dir_recurse = 0;
49 vapier 1.14 static char dir_crossmount = 1;
50 vapier 1.10 static char show_pax = 0;
51 solar 1.73 static char show_phdr = 0;
52 vapier 1.10 static char show_textrel = 0;
53     static char show_rpath = 0;
54 vapier 1.32 static char show_needed = 0;
55 vapier 1.38 static char show_interp = 0;
56 vapier 1.49 static char show_bind = 0;
57 vapier 1.84 static char show_soname = 0;
58 vapier 1.76 static char show_textrels = 0;
59 solar 1.16 static char show_banner = 1;
60 vapier 1.10 static char be_quiet = 0;
61 vapier 1.14 static char be_verbose = 0;
62 vapier 1.70 static char be_wewy_wewy_quiet = 0;
63 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
64 vapier 1.72 static char *find_lib = NULL;
65 vapier 1.39 static char *out_format = NULL;
66 vapier 1.66 static char *search_path = NULL;
67 solar 1.86 static char gmatch = 0;
68 solar 1.1
69 vapier 1.70
70 vapier 1.39 /* sub-funcs for scanelf_file() */
71 vapier 1.77 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
72     {
73     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
74     #define GET_SYMTABS(B) \
75     if (elf->elf_class == ELFCLASS ## B) { \
76     Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
77     /* debug sections */ \
78     symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
79     strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
80     /* runtime sections */ \
81     dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
82     dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
83     if (symtab && dynsym) { \
84     *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
85     } else { \
86     *sym = (void*)(symtab ? symtab : dynsym); \
87     } \
88     if (strtab && dynstr) { \
89     *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
90     } else { \
91     *tab = (void*)(strtab ? strtab : dynstr); \
92     } \
93     }
94     GET_SYMTABS(32)
95     GET_SYMTABS(64)
96     }
97 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
98 solar 1.6 {
99 solar 1.61 static char ret[7];
100     unsigned long i, shown;
101    
102 vapier 1.41 if (!show_pax) return NULL;
103 vapier 1.10
104 solar 1.61 shown = 0;
105     memset(&ret, 0, sizeof(ret));
106    
107     if (elf->phdr) {
108     #define SHOW_PAX(B) \
109     if (elf->elf_class == ELFCLASS ## B) { \
110     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
111     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
112     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
113     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
114     continue; \
115     if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
116     continue; \
117     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
118     *found_pax = 1; \
119     ++shown; \
120     break; \
121     } \
122     }
123     SHOW_PAX(32)
124     SHOW_PAX(64)
125     }
126    
127     /* fall back to EI_PAX if no PT_PAX was found */
128     if (!*ret) {
129 vapier 1.90 static char *paxflags;
130 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
131     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
132     *found_pax = 1;
133 vapier 1.90 return (be_wewy_wewy_quiet ? NULL : paxflags);
134 solar 1.61 }
135     strncpy(ret, paxflags, sizeof(ret));
136 vapier 1.14 }
137 vapier 1.41
138 vapier 1.90 if (be_wewy_wewy_quiet || (be_quiet && !shown))
139 solar 1.61 return NULL;
140 vapier 1.90 else
141     return ret;
142     }
143 solar 1.61
144 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
145 vapier 1.39 {
146 vapier 1.71 static char ret[12];
147 vapier 1.41 char *found;
148 vapier 1.91 unsigned long i, shown;
149 vapier 1.71 unsigned char multi_stack, multi_relro, multi_load;
150 vapier 1.41
151 solar 1.73 if (!show_phdr) return NULL;
152 vapier 1.41
153 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
154    
155 vapier 1.41 shown = 0;
156 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
157 vapier 1.44
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     if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
178     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     memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
187     *found = 1; \
188     ++shown; \
189     } \
190     } else if (elf->shdr != NULL) { \
191     /* no program headers which means this is prob an object file */ \
192     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
193     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
194     check_flags = SHF_WRITE|SHF_EXECINSTR; \
195     for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
196     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
197     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
198     if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \
199     if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
200     flags = EGET(shdr[i].sh_flags); \
201     if (be_quiet && ((flags & check_flags) != check_flags)) \
202     continue; \
203     ++*found_phdr; \
204     shown = 1; \
205     if (flags & SHF_WRITE) ret[0] = 'W'; \
206     if (flags & SHF_ALLOC) ret[1] = 'A'; \
207     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
208     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
209     break; \
210     } \
211     } \
212     if (!multi_stack) { \
213     *found_phdr = 1; \
214     shown = 1; \
215     memcpy(ret, "!WX", 3); \
216     } \
217 vapier 1.39 } \
218     }
219 solar 1.73 SHOW_PHDR(32)
220     SHOW_PHDR(64)
221 vapier 1.44
222 vapier 1.90 if (be_wewy_wewy_quiet || (be_quiet && !shown))
223 vapier 1.41 return NULL;
224     else
225     return ret;
226 vapier 1.39 }
227 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
228 vapier 1.39 {
229 vapier 1.90 static const char *ret = "TEXTREL";
230 vapier 1.44 unsigned long i;
231 vapier 1.41
232 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
233 vapier 1.41
234 vapier 1.44 if (elf->phdr) {
235 vapier 1.39 #define SHOW_TEXTREL(B) \
236     if (elf->elf_class == ELFCLASS ## B) { \
237     Elf ## B ## _Dyn *dyn; \
238     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
239     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
240 vapier 1.44 Elf ## B ## _Off offset; \
241 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
242 vapier 1.59 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
243 vapier 1.44 offset = EGET(phdr[i].p_offset); \
244     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
245     dyn = DYN ## B (elf->data + offset); \
246 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
247     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
248     *found_textrel = 1; \
249     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
250 vapier 1.70 return (be_wewy_wewy_quiet ? NULL : ret); \
251 vapier 1.39 } \
252     ++dyn; \
253 vapier 1.26 } \
254 vapier 1.39 } }
255     SHOW_TEXTREL(32)
256     SHOW_TEXTREL(64)
257 vapier 1.44 }
258    
259 vapier 1.70 if (be_quiet || be_wewy_wewy_quiet)
260 vapier 1.41 return NULL;
261     else
262 vapier 1.90 return " - ";
263 vapier 1.39 }
264 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
265 vapier 1.76 {
266 vapier 1.82 unsigned long s, r, rmax;
267     void *symtab_void, *strtab_void, *text_void;
268 vapier 1.76
269     if (!show_textrels) return NULL;
270    
271 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
272     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
273     if (!*found_textrel) return NULL;
274    
275 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
277 vapier 1.76
278 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
279 vapier 1.76 #define SHOW_TEXTRELS(B) \
280     if (elf->elf_class == ELFCLASS ## B) { \
281     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
282     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
283     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
284     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
285 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
286     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
287     uint ## B ## _t memsz = EGET(text->sh_size); \
288 vapier 1.76 Elf ## B ## _Rel *rel; \
289     Elf ## B ## _Rela *rela; \
290     /* search the section headers for relocations */ \
291     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
292     uint32_t sh_type = EGET(shdr[s].sh_type); \
293     if (sh_type == SHT_REL) { \
294     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
295     rela = NULL; \
296     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
297     } else if (sh_type == SHT_RELA) { \
298     rel = NULL; \
299     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
300     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
301     } else \
302     continue; \
303 vapier 1.82 /* now see if any of the relocs are in the .text */ \
304     for (r = 0; r < rmax; ++r) { \
305     unsigned long sym_max; \
306     Elf ## B ## _Addr offset_tmp; \
307     Elf ## B ## _Sym *func; \
308     Elf ## B ## _Sym *sym; \
309     Elf ## B ## _Addr r_offset; \
310     uint ## B ## _t r_info; \
311     if (sh_type == SHT_REL) { \
312     r_offset = EGET(rel[r].r_offset); \
313     r_info = EGET(rel[r].r_info); \
314     } else { \
315     r_offset = EGET(rela[r].r_offset); \
316     r_info = EGET(rela[r].r_info); \
317     } \
318     /* make sure this relocation is inside of the .text */ \
319     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
320     if (be_verbose <= 2) continue; \
321     } else \
322 vapier 1.78 *found_textrels = 1; \
323 vapier 1.82 /* locate this relocation symbol name */ \
324     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
325     sym_max = ELF ## B ## _R_SYM(r_info); \
326     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
327     sym += sym_max; \
328     else \
329     sym = NULL; \
330     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
331     /* show the raw details about this reloc */ \
332 vapier 1.88 printf(" %s: ", elf->base_filename); \
333 vapier 1.82 if (sym && sym->st_name) \
334     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
335     else \
336 vapier 1.88 printf("(memory/fake?)"); \
337 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
338     /* now try to find the closest symbol that this rel is probably in */ \
339     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
340     func = NULL; \
341     offset_tmp = 0; \
342     while (sym_max--) { \
343     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
344     func = sym; \
345     offset_tmp = EGET(sym->st_value); \
346 vapier 1.76 } \
347 vapier 1.82 ++sym; \
348 vapier 1.76 } \
349 vapier 1.82 printf(" in "); \
350     if (func && func->st_name) \
351     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
352     else \
353     printf("(NULL: fake?)"); \
354     printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
355 vapier 1.76 } \
356     } }
357     SHOW_TEXTRELS(32)
358     SHOW_TEXTRELS(64)
359     }
360 vapier 1.82 if (!*found_textrels)
361     warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
362 vapier 1.76
363     return NULL;
364     }
365 solar 1.83
366     static void rpath_security_checks(elfobj *, char *);
367     static void rpath_security_checks(elfobj *elf, char *item) {
368     struct stat st;
369 vapier 1.84 switch (*item) {
370 vapier 1.89 case '/': break;
371     case '.':
372     warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename);
373     break;
374     case '\0':
375 solar 1.83 warnf("Security problem NULL RPATH in %s", elf->filename);
376     break;
377     case '$':
378 vapier 1.84 if (fstat(elf->fd, &st) != -1)
379 solar 1.83 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
380     warnf("Security problem with RPATH='%s' in %s with mode set of %o",
381     item, elf->filename, st.st_mode & 07777);
382     break;
383     default:
384     warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename);
385     break;
386     }
387     }
388 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
389 vapier 1.39 {
390 vapier 1.48 unsigned long i, s;
391     char *rpath, *runpath, **r;
392 vapier 1.39 void *strtbl_void;
393 vapier 1.10
394 vapier 1.39 if (!show_rpath) return;
395 vapier 1.10
396 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
397     rpath = runpath = NULL;
398 vapier 1.10
399 vapier 1.44 if (elf->phdr && strtbl_void) {
400 vapier 1.26 #define SHOW_RPATH(B) \
401     if (elf->elf_class == ELFCLASS ## B) { \
402     Elf ## B ## _Dyn *dyn; \
403     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
404     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
405     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
406 vapier 1.44 Elf ## B ## _Off offset; \
407 vapier 1.60 Elf ## B ## _Xword word; \
408 vapier 1.48 /* Scan all the program headers */ \
409 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
410 vapier 1.48 /* Just scan dynamic headers */ \
411 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
412 vapier 1.44 offset = EGET(phdr[i].p_offset); \
413     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
414 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
415 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
416 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
417     if (word == DT_RPATH) { \
418     r = &rpath; \
419     } else if (word == DT_RUNPATH) { \
420     r = &runpath; \
421     } else { \
422     ++dyn; \
423     continue; \
424     } \
425     /* Verify the memory is somewhat sane */ \
426     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
427 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
428 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
429     *r = (char*)(elf->data + offset); \
430     /* If quiet, don't output paths in ld.so.conf */ \
431 vapier 1.69 if (be_quiet) { \
432     size_t len; \
433     char *start, *end; \
434 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
435     /* since *r is read-only memory, we can only move the ptr forward. */ \
436     start = *r; \
437     /* scan each path in : delimited list */ \
438     while (start) { \
439 solar 1.83 rpath_security_checks(elf, start); \
440 vapier 1.69 end = strchr(start, ':'); \
441 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
442     for (s = 0; ldpaths[s]; ++s) { \
443 vapier 1.69 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
444     *r = (end ? end + 1 : NULL); \
445     break; \
446     } \
447 vapier 1.48 } \
448 vapier 1.75 if (!*r || !ldpaths[s] || !end) \
449     start = NULL; \
450     else \
451     start = start + len + 1; \
452 vapier 1.69 } \
453     } \
454 vapier 1.48 if (*r) *found_rpath = 1; \
455 vapier 1.26 } \
456     ++dyn; \
457     } \
458     } }
459     SHOW_RPATH(32)
460     SHOW_RPATH(64)
461 vapier 1.10 }
462 vapier 1.41
463 vapier 1.70 if (be_wewy_wewy_quiet) return;
464    
465 vapier 1.39 if (rpath && runpath) {
466 vapier 1.41 if (!strcmp(rpath, runpath)) {
467     xstrcat(ret, runpath, ret_len);
468     } else {
469 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
470 vapier 1.41 xchrcat(ret, '{', ret_len);
471     xstrcat(ret, rpath, ret_len);
472     xchrcat(ret, ',', ret_len);
473     xstrcat(ret, runpath, ret_len);
474     xchrcat(ret, '}', ret_len);
475 vapier 1.39 }
476     } else if (rpath || runpath)
477 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
478     else if (!be_quiet)
479     xstrcat(ret, " - ", ret_len);
480 vapier 1.39 }
481 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)
482 vapier 1.39 {
483 vapier 1.44 unsigned long i;
484 vapier 1.39 char *needed;
485     void *strtbl_void;
486    
487 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
488 vapier 1.10
489 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
490 vapier 1.32
491 vapier 1.44 if (elf->phdr && strtbl_void) {
492 vapier 1.32 #define SHOW_NEEDED(B) \
493     if (elf->elf_class == ELFCLASS ## B) { \
494     Elf ## B ## _Dyn *dyn; \
495     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
496     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
497     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
498 vapier 1.44 Elf ## B ## _Off offset; \
499 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
500     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
501 vapier 1.44 offset = EGET(phdr[i].p_offset); \
502     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
503     dyn = DYN ## B (elf->data + offset); \
504 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
505     if (EGET(dyn->d_tag) == DT_NEEDED) { \
506 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
507 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
508 vapier 1.49 ++dyn; \
509     continue; \
510     } \
511 vapier 1.44 needed = (char*)(elf->data + offset); \
512 vapier 1.72 if (op == 0) { \
513     if (!be_wewy_wewy_quiet) { \
514     if (*found_needed) xchrcat(ret, ',', ret_len); \
515     xstrcat(ret, needed, ret_len); \
516     } \
517     *found_needed = 1; \
518     } else { \
519 solar 1.86 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
520 vapier 1.81 *found_lib = 1; \
521 solar 1.86 return (be_wewy_wewy_quiet ? NULL : needed); \
522 vapier 1.81 } \
523 vapier 1.72 } \
524 vapier 1.32 } \
525     ++dyn; \
526     } \
527     } }
528     SHOW_NEEDED(32)
529     SHOW_NEEDED(64)
530 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
531 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
532 vapier 1.32 }
533 vapier 1.72
534     return NULL;
535 vapier 1.39 }
536 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
537 vapier 1.39 {
538     void *strtbl_void;
539    
540 vapier 1.41 if (!show_interp) return NULL;
541 vapier 1.32
542 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
543 vapier 1.38
544 vapier 1.39 if (strtbl_void) {
545 vapier 1.38 #define SHOW_INTERP(B) \
546     if (elf->elf_class == ELFCLASS ## B) { \
547 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
548     *found_interp = 1; \
549 vapier 1.70 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
550 vapier 1.38 }
551     SHOW_INTERP(32)
552     SHOW_INTERP(64)
553     }
554 vapier 1.41 return NULL;
555 vapier 1.39 }
556 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
557     {
558     unsigned long i;
559     struct stat s;
560    
561     if (!show_bind) return NULL;
562 vapier 1.51 if (!elf->phdr) return NULL;
563 vapier 1.49
564     #define SHOW_BIND(B) \
565     if (elf->elf_class == ELFCLASS ## B) { \
566     Elf ## B ## _Dyn *dyn; \
567     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
568     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
569     Elf ## B ## _Off offset; \
570     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
571     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
572     offset = EGET(phdr[i].p_offset); \
573     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
574     dyn = DYN ## B (elf->data + offset); \
575     while (EGET(dyn->d_tag) != DT_NULL) { \
576     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
577     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
578     { \
579     if (be_quiet) return NULL; \
580     *found_bind = 1; \
581 vapier 1.70 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
582 vapier 1.49 } \
583     ++dyn; \
584     } \
585     } \
586     }
587     SHOW_BIND(32)
588     SHOW_BIND(64)
589    
590 vapier 1.70 if (be_wewy_wewy_quiet) return NULL;
591    
592 vapier 1.56 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
593 vapier 1.49 return NULL;
594     } else {
595     *found_bind = 1;
596 solar 1.68 return (char *) "LAZY";
597 vapier 1.49 }
598     }
599 vapier 1.84 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
600     {
601     unsigned long i;
602     char *soname;
603     void *strtbl_void;
604    
605     if (!show_soname) return NULL;
606    
607     strtbl_void = elf_findsecbyname(elf, ".dynstr");
608    
609     if (elf->phdr && strtbl_void) {
610     #define SHOW_SONAME(B) \
611     if (elf->elf_class == ELFCLASS ## B) { \
612     Elf ## B ## _Dyn *dyn; \
613     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
614     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
615     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
616     Elf ## B ## _Off offset; \
617     /* only look for soname in shared objects */ \
618     if (ehdr->e_type != ET_DYN) \
619     return NULL; \
620     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
621     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
622     offset = EGET(phdr[i].p_offset); \
623     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
624     dyn = DYN ## B (elf->data + offset); \
625     while (EGET(dyn->d_tag) != DT_NULL) { \
626     if (EGET(dyn->d_tag) == DT_SONAME) { \
627     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
628     if (offset >= (Elf ## B ## _Off)elf->len) { \
629     ++dyn; \
630     continue; \
631     } \
632     soname = (char*)(elf->data + offset); \
633     *found_soname = 1; \
634     return (be_wewy_wewy_quiet ? NULL : soname); \
635     } \
636     ++dyn; \
637     } \
638     } }
639     SHOW_SONAME(32)
640     SHOW_SONAME(64)
641     }
642    
643     return NULL;
644     }
645 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
646 vapier 1.39 {
647 vapier 1.44 unsigned long i;
648 vapier 1.39 void *symtab_void, *strtab_void;
649 vapier 1.38
650 vapier 1.41 if (!find_sym) return NULL;
651 vapier 1.32
652 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
653 vapier 1.27
654 vapier 1.39 if (symtab_void && strtab_void) {
655 vapier 1.27 #define FIND_SYM(B) \
656     if (elf->elf_class == ELFCLASS ## B) { \
657     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
658     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
659     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
660 vapier 1.44 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
661 vapier 1.27 char *symname; \
662     for (i = 0; i < cnt; ++i) { \
663     if (sym->st_name) { \
664     symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
665 solar 1.28 if (*find_sym == '*') { \
666 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
667 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
668 vapier 1.76 elf->base_filename, \
669 vapier 1.32 (long)sym->st_size, \
670     (char *)get_elfstttype(sym->st_info), \
671     symname); \
672 vapier 1.39 *found_sym = 1; \
673 vapier 1.32 } else if ((strcmp(find_sym, symname) == 0) || \
674 vapier 1.39 (strcmp(symname, versioned_symname) == 0)) \
675     (*found_sym)++; \
676 vapier 1.27 } \
677     ++sym; \
678     } }
679     FIND_SYM(32)
680     FIND_SYM(64)
681 vapier 1.39 }
682 vapier 1.70
683     if (be_wewy_wewy_quiet) return NULL;
684    
685 vapier 1.41 if (*find_sym != '*' && *found_sym)
686     return find_sym;
687     if (be_quiet)
688     return NULL;
689     else
690 solar 1.68 return (char *)" - ";
691 vapier 1.39 }
692     /* scan an elf file and show all the fun stuff */
693 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
694 vapier 1.39 static void scanelf_file(const char *filename)
695     {
696 vapier 1.44 unsigned long i;
697 solar 1.73 char found_pax, found_phdr, found_relro, found_load, found_textrel,
698 vapier 1.84 found_rpath, found_needed, found_interp, found_bind, found_soname,
699 vapier 1.76 found_sym, found_lib, found_file, found_textrels;
700 vapier 1.39 elfobj *elf;
701     struct stat st;
702 vapier 1.41 static char *out_buffer = NULL;
703     static size_t out_len;
704 vapier 1.39
705     /* make sure 'filename' exists */
706     if (lstat(filename, &st) == -1) {
707     if (be_verbose > 2) printf("%s: does not exist\n", filename);
708     return;
709     }
710     /* always handle regular files and handle symlinked files if no -y */
711 vapier 1.55 if (S_ISLNK(st.st_mode)) {
712     if (!scan_symlink) return;
713     stat(filename, &st);
714     }
715     if (!S_ISREG(st.st_mode)) {
716 vapier 1.39 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
717     return;
718     }
719    
720 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
721 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
722 vapier 1.76 found_sym = found_lib = found_file = found_textrels = 0;
723 vapier 1.39
724     /* verify this is real ELF */
725     if ((elf = readelf(filename)) == NULL) {
726     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
727     return;
728     }
729    
730     if (be_verbose > 1)
731 vapier 1.41 printf("%s: scanning file {%s,%s}\n", filename,
732 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
733     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
734 vapier 1.39 else if (be_verbose)
735     printf("%s: scanning file\n", filename);
736    
737 vapier 1.41 /* init output buffer */
738     if (!out_buffer) {
739     out_len = sizeof(char) * 80;
740     out_buffer = (char*)xmalloc(out_len);
741     }
742     *out_buffer = '\0';
743    
744 vapier 1.39 /* show the header */
745     if (!be_quiet && show_banner) {
746 vapier 1.49 for (i = 0; out_format[i]; ++i) {
747 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
748 vapier 1.41
749     switch (out_format[++i]) {
750     case '%': break;
751 vapier 1.70 case '#': break;
752 vapier 1.66 case 'F':
753     case 'p':
754     case 'f': prints("FILE "); found_file = 1; break;
755 vapier 1.41 case 'o': prints(" TYPE "); break;
756     case 'x': prints(" PAX "); break;
757 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
758 vapier 1.41 case 't': prints("TEXTREL "); break;
759     case 'r': prints("RPATH "); break;
760     case 'n': prints("NEEDED "); break;
761     case 'i': prints("INTERP "); break;
762 vapier 1.49 case 'b': prints("BIND "); break;
763 vapier 1.84 case 'S': prints("SONAME "); break;
764 vapier 1.41 case 's': prints("SYM "); break;
765 vapier 1.72 case 'N': prints("LIB "); break;
766 vapier 1.76 case 'T': prints("TEXTRELS "); break;
767     default: warnf("'%c' has no title ?", out_format[i]);
768 vapier 1.39 }
769 vapier 1.27 }
770 vapier 1.49 if (!found_file) prints("FILE ");
771 vapier 1.41 prints("\n");
772 vapier 1.49 found_file = 0;
773 vapier 1.39 show_banner = 0;
774     }
775    
776     /* dump all the good stuff */
777 vapier 1.49 for (i = 0; out_format[i]; ++i) {
778 vapier 1.41 const char *out;
779 vapier 1.66 const char *tmp;
780 vapier 1.41
781     /* make sure we trim leading spaces in quiet mode */
782     if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
783     *out_buffer = '\0';
784 vapier 1.39
785 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
786 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
787     continue;
788     }
789 vapier 1.39
790 vapier 1.41 out = NULL;
791 vapier 1.70 be_wewy_wewy_quiet = (out_format[i] == '#');
792 vapier 1.41 switch (out_format[++i]) {
793 vapier 1.70 case '%':
794     case '#':
795     xchrcat(&out_buffer, out_format[i], &out_len); break;
796     case 'F':
797 vapier 1.76 found_file = 1;
798 vapier 1.70 if (be_wewy_wewy_quiet) break;
799     xstrcat(&out_buffer, filename, &out_len);
800     break;
801 vapier 1.66 case 'p':
802 vapier 1.76 found_file = 1;
803 vapier 1.70 if (be_wewy_wewy_quiet) break;
804 vapier 1.66 tmp = filename;
805     if (search_path) {
806     ssize_t len_search = strlen(search_path);
807     ssize_t len_file = strlen(filename);
808     if (!strncmp(filename, search_path, len_search) && \
809     len_file > len_search)
810     tmp += len_search;
811     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
812     }
813     xstrcat(&out_buffer, tmp, &out_len);
814     break;
815     case 'f':
816 vapier 1.76 found_file = 1;
817 vapier 1.70 if (be_wewy_wewy_quiet) break;
818 vapier 1.66 tmp = strrchr(filename, '/');
819     tmp = (tmp == NULL ? filename : tmp+1);
820     xstrcat(&out_buffer, tmp, &out_len);
821     break;
822 vapier 1.41 case 'o': out = get_elfetype(elf); break;
823     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
824 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
825 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
826 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
827 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
828 vapier 1.72 case 'n':
829     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
830 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
831 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
832 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
833 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
834 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
835 vapier 1.29 }
836 vapier 1.41 if (out) xstrcat(&out_buffer, out, &out_len);
837 vapier 1.39 }
838    
839 vapier 1.54 #define FOUND_SOMETHING() \
840 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
841 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
842 vapier 1.84 found_soname || found_sym || found_lib || found_textrels)
843 vapier 1.54
844     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
845     xchrcat(&out_buffer, ' ', &out_len);
846     xstrcat(&out_buffer, filename, &out_len);
847 vapier 1.27 }
848 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
849 vapier 1.41 puts(out_buffer);
850 vapier 1.79 fflush(stdout);
851     }
852 vapier 1.10
853     unreadelf(elf);
854 solar 1.6 }
855    
856 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
857 vapier 1.10 static void scanelf_dir(const char *path)
858 solar 1.1 {
859 vapier 1.10 register DIR *dir;
860     register struct dirent *dentry;
861 vapier 1.14 struct stat st_top, st;
862 solar 1.21 char buf[_POSIX_PATH_MAX];
863 vapier 1.32 size_t pathlen = 0, len = 0;
864 vapier 1.10
865     /* make sure path exists */
866 vapier 1.39 if (lstat(path, &st_top) == -1) {
867     if (be_verbose > 2) printf("%s: does not exist\n", path);
868 vapier 1.10 return;
869 vapier 1.39 }
870 solar 1.11
871 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
872 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
873 vapier 1.10 scanelf_file(path);
874     return;
875     }
876    
877     /* now scan the dir looking for fun stuff */
878     if ((dir = opendir(path)) == NULL) {
879     warnf("could not opendir %s: %s", path, strerror(errno));
880     return;
881     }
882 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
883 solar 1.11
884 vapier 1.32 pathlen = strlen(path);
885 vapier 1.10 while ((dentry = readdir(dir))) {
886     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
887     continue;
888 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
889     if (len >= sizeof(buf)) {
890 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
891     (unsigned long)len, (unsigned long)sizeof(buf));
892 vapier 1.32 continue;
893     }
894 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
895 solar 1.20 if (lstat(buf, &st) != -1) {
896 vapier 1.10 if (S_ISREG(st.st_mode))
897 solar 1.20 scanelf_file(buf);
898 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
899 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
900 solar 1.20 scanelf_dir(buf);
901 vapier 1.10 }
902     }
903     }
904     closedir(dir);
905 solar 1.1 }
906    
907 vapier 1.47 static int scanelf_from_file(char *filename)
908     {
909 solar 1.45 FILE *fp = NULL;
910     char *p;
911     char path[_POSIX_PATH_MAX];
912    
913     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
914     fp = stdin;
915     else if ((fp = fopen(filename, "r")) == NULL)
916     return 1;
917    
918     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
919     if ((p = strchr(path, '\n')) != NULL)
920     *p = 0;
921 vapier 1.66 search_path = path;
922 solar 1.45 scanelf_dir(path);
923     }
924     if (fp != stdin)
925     fclose(fp);
926     return 0;
927     }
928    
929 vapier 1.48 static void load_ld_so_conf()
930     {
931     FILE *fp = NULL;
932     char *p;
933     char path[_POSIX_PATH_MAX];
934     int i = 0;
935    
936     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
937     return;
938    
939     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
940     if (*path != '/')
941     continue;
942    
943     if ((p = strrchr(path, '\r')) != NULL)
944     *p = 0;
945     if ((p = strchr(path, '\n')) != NULL)
946     *p = 0;
947    
948     ldpaths[i++] = xstrdup(path);
949    
950     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
951     break;
952     }
953     ldpaths[i] = NULL;
954    
955     fclose(fp);
956     }
957    
958 vapier 1.10 /* scan /etc/ld.so.conf for paths */
959     static void scanelf_ldpath()
960     {
961 vapier 1.17 char scan_l, scan_ul, scan_ull;
962 vapier 1.48 int i = 0;
963 vapier 1.10
964 vapier 1.48 if (!ldpaths[0])
965     err("Unable to load any paths from ld.so.conf");
966 vapier 1.10
967 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
968    
969 vapier 1.48 while (ldpaths[i]) {
970     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
971     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
972     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
973     scanelf_dir(ldpaths[i]);
974     ++i;
975     }
976 vapier 1.10
977 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
978     if (!scan_ul) scanelf_dir("/usr/lib");
979     if (!scan_ull) scanelf_dir("/usr/local/lib");
980 vapier 1.10 }
981 solar 1.1
982 vapier 1.10 /* scan env PATH for paths */
983     static void scanelf_envpath()
984 solar 1.1 {
985 solar 1.34 char *path, *p;
986 vapier 1.10
987     path = getenv("PATH");
988     if (!path)
989     err("PATH is not set in your env !");
990 vapier 1.41 path = xstrdup(path);
991 vapier 1.10
992     while ((p = strrchr(path, ':')) != NULL) {
993     scanelf_dir(p + 1);
994     *p = 0;
995     }
996 vapier 1.17
997 solar 1.34 free(path);
998 solar 1.1 }
999    
1000    
1001 vapier 1.10
1002     /* usage / invocation handling functions */
1003 solar 1.86 #define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV"
1004 vapier 1.27 #define a_argument required_argument
1005 vapier 1.10 static struct option const long_opts[] = {
1006     {"path", no_argument, NULL, 'p'},
1007     {"ldpath", no_argument, NULL, 'l'},
1008     {"recursive", no_argument, NULL, 'R'},
1009 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1010 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1011 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1012 solar 1.16 {"header", no_argument, NULL, 'e'},
1013 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1014     {"rpath", no_argument, NULL, 'r'},
1015 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1016 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1017 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1018 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1019 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1020     {"lib", a_argument, NULL, 'N'},
1021 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1022 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1023 vapier 1.10 {"all", no_argument, NULL, 'a'},
1024     {"quiet", no_argument, NULL, 'q'},
1025 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1026 vapier 1.76 {"format", a_argument, NULL, 'F'},
1027     {"from", a_argument, NULL, 'f'},
1028     {"file", a_argument, NULL, 'o'},
1029 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1030 vapier 1.10 {"help", no_argument, NULL, 'h'},
1031     {"version", no_argument, NULL, 'V'},
1032     {NULL, no_argument, NULL, 0x0}
1033     };
1034 solar 1.57
1035 solar 1.68 static const char *opts_help[] = {
1036 vapier 1.10 "Scan all directories in PATH environment",
1037     "Scan all directories in /etc/ld.so.conf",
1038 vapier 1.14 "Scan directories recursively",
1039 vapier 1.37 "Don't recursively cross mount points",
1040     "Don't scan symlinks\n",
1041 vapier 1.10 "Print PaX markings",
1042 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1043 vapier 1.10 "Print TEXTREL information",
1044     "Print RPATH information",
1045 vapier 1.32 "Print NEEDED information",
1046 vapier 1.38 "Print INTERP information",
1047 vapier 1.49 "Print BIND information",
1048 vapier 1.84 "Print SONAME information",
1049 vapier 1.27 "Find a specified symbol",
1050 vapier 1.72 "Find a specified library",
1051 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1052 vapier 1.76 "Locate cause of TEXTREL",
1053 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1054 vapier 1.14 "Only output 'bad' things",
1055     "Be verbose (can be specified more than once)",
1056 vapier 1.39 "Use specified format for output",
1057 solar 1.45 "Read input stream from a filename",
1058 vapier 1.24 "Write output stream to a filename",
1059 vapier 1.14 "Don't display the header",
1060 vapier 1.10 "Print this help and exit",
1061     "Print version and exit",
1062     NULL
1063     };
1064    
1065     /* display usage and exit */
1066     static void usage(int status)
1067 solar 1.1 {
1068 vapier 1.44 unsigned long i;
1069 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1070 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
1071     printf("Options: -[%s]\n", PARSE_FLAGS);
1072 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1073 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1074 solar 1.52 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
1075 vapier 1.27 long_opts[i].name, opts_help[i]);
1076     else
1077 solar 1.52 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
1078 vapier 1.27 long_opts[i].name, opts_help[i]);
1079 solar 1.45
1080     if (status != EXIT_SUCCESS)
1081     exit(status);
1082    
1083 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
1084 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1085     puts(" t TEXTREL \tr RPATH \tn NEEDED");
1086     puts(" i INTERP \tb BIND \ts symbol");
1087 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
1088 vapier 1.88 puts(" S SONAME");
1089 vapier 1.70 puts(" p filename (with search path removed)");
1090 vapier 1.88 puts(" f filename (short name/basename)");
1091 vapier 1.70 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1092 solar 1.45
1093 vapier 1.10 exit(status);
1094 solar 1.1 }
1095    
1096     /* parse command line arguments and preform needed actions */
1097 vapier 1.10 static void parseargs(int argc, char *argv[])
1098     {
1099 vapier 1.48 int i;
1100 solar 1.45 char *from_file = NULL;
1101 vapier 1.10
1102     opterr = 0;
1103 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1104     switch (i) {
1105 vapier 1.10
1106 vapier 1.39 case 'V':
1107 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1108     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1109     VERSION, __FILE__, __DATE__, rcsid, argv0);
1110 vapier 1.10 exit(EXIT_SUCCESS);
1111     break;
1112     case 'h': usage(EXIT_SUCCESS); break;
1113 solar 1.45 case 'f':
1114 solar 1.64 if (from_file) err("Don't specify -f twice");
1115     from_file = xstrdup(optarg);
1116 solar 1.45 break;
1117 vapier 1.24 case 'o': {
1118 solar 1.21 FILE *fp = NULL;
1119 solar 1.64 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1120 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1121 vapier 1.65 SET_STDOUT(fp);
1122 solar 1.21 break;
1123     }
1124 vapier 1.24
1125 vapier 1.39 case 's': {
1126     size_t len;
1127 solar 1.64 if (find_sym) err("Don't specify -s twice");
1128 vapier 1.41 find_sym = xstrdup(optarg);
1129 vapier 1.39 len = strlen(find_sym) + 1;
1130 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
1131 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1132     break;
1133     }
1134 vapier 1.72 case 'N': {
1135     if (find_lib) err("Don't specify -N twice");
1136     find_lib = xstrdup(optarg);
1137     break;
1138     }
1139 vapier 1.39
1140     case 'F': {
1141 solar 1.64 if (out_format) err("Don't specify -F twice");
1142     out_format = xstrdup(optarg);
1143 vapier 1.39 break;
1144     }
1145 vapier 1.27
1146 solar 1.86 case 'g': gmatch = 1;
1147 vapier 1.37 case 'y': scan_symlink = 0; break;
1148 solar 1.16 case 'B': show_banner = 0; break;
1149 vapier 1.10 case 'l': scan_ldpath = 1; break;
1150     case 'p': scan_envpath = 1; break;
1151     case 'R': dir_recurse = 1; break;
1152 vapier 1.14 case 'm': dir_crossmount = 0; break;
1153 vapier 1.10 case 'x': show_pax = 1; break;
1154 solar 1.73 case 'e': show_phdr = 1; break;
1155 vapier 1.10 case 't': show_textrel = 1; break;
1156     case 'r': show_rpath = 1; break;
1157 vapier 1.32 case 'n': show_needed = 1; break;
1158 vapier 1.38 case 'i': show_interp = 1; break;
1159 vapier 1.49 case 'b': show_bind = 1; break;
1160 vapier 1.84 case 'S': show_soname = 1; break;
1161 vapier 1.76 case 'T': show_textrels = 1; break;
1162 vapier 1.10 case 'q': be_quiet = 1; break;
1163 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1164 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1165 vapier 1.10
1166     case ':':
1167 vapier 1.49 err("Option missing parameter\n");
1168 vapier 1.10 case '?':
1169 vapier 1.49 err("Unknown option\n");
1170 vapier 1.10 default:
1171 vapier 1.48 err("Unhandled option '%c'", i);
1172 vapier 1.10 }
1173     }
1174    
1175 vapier 1.39 /* let the format option override all other options */
1176     if (out_format) {
1177 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1178 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1179     show_textrels = 0;
1180 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1181 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1182 vapier 1.39
1183 vapier 1.48 switch (out_format[++i]) {
1184 vapier 1.39 case '%': break;
1185 vapier 1.70 case '#': break;
1186 vapier 1.39 case 'F': break;
1187 vapier 1.66 case 'p': break;
1188     case 'f': break;
1189 vapier 1.39 case 's': break;
1190 vapier 1.72 case 'N': break;
1191 vapier 1.41 case 'o': break;
1192 vapier 1.39 case 'x': show_pax = 1; break;
1193 solar 1.73 case 'e': show_phdr = 1; break;
1194 vapier 1.39 case 't': show_textrel = 1; break;
1195     case 'r': show_rpath = 1; break;
1196     case 'n': show_needed = 1; break;
1197     case 'i': show_interp = 1; break;
1198 vapier 1.49 case 'b': show_bind = 1; break;
1199 vapier 1.84 case 'S': show_soname = 1; break;
1200 vapier 1.76 case 'T': show_textrels = 1; break;
1201 vapier 1.39 default:
1202     err("Invalid format specifier '%c' (byte %i)",
1203 vapier 1.48 out_format[i], i+1);
1204 vapier 1.39 }
1205     }
1206 vapier 1.41
1207     /* construct our default format */
1208     } else {
1209     size_t fmt_len = 30;
1210     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1211 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1212     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1213     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1214     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1215     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1216     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1217     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1218     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1219 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1220 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1221     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1222     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1223     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1224 vapier 1.39 }
1225 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1226 vapier 1.39
1227     /* now lets actually do the scanning */
1228 vapier 1.48 if (scan_ldpath || (show_rpath && be_quiet))
1229     load_ld_so_conf();
1230 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1231     if (scan_envpath) scanelf_envpath();
1232 solar 1.45 if (from_file) {
1233     scanelf_from_file(from_file);
1234     free(from_file);
1235     from_file = *argv;
1236     }
1237     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1238 vapier 1.25 err("Nothing to scan !?");
1239 vapier 1.66 while (optind < argc) {
1240     search_path = argv[optind++];
1241     scanelf_dir(search_path);
1242     }
1243 vapier 1.27
1244 vapier 1.39 /* clean up */
1245     if (find_sym) {
1246     free(find_sym);
1247     free(versioned_symname);
1248     }
1249 vapier 1.72 if (find_lib) free(find_lib);
1250 vapier 1.39 if (out_format) free(out_format);
1251 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1252     free(ldpaths[i]);
1253 vapier 1.10 }
1254    
1255    
1256    
1257 vapier 1.41 /* utility funcs */
1258 vapier 1.60 static char *xstrdup(const char *s)
1259 vapier 1.41 {
1260     char *ret = strdup(s);
1261     if (!ret) err("Could not strdup(): %s", strerror(errno));
1262     return ret;
1263     }
1264 solar 1.57
1265 vapier 1.41 static void *xmalloc(size_t size)
1266     {
1267     void *ret = malloc(size);
1268     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1269     return ret;
1270     }
1271 solar 1.57
1272 vapier 1.41 static void xstrcat(char **dst, const char *src, size_t *curr_len)
1273     {
1274 vapier 1.69 size_t new_len;
1275 vapier 1.41
1276     new_len = strlen(*dst) + strlen(src);
1277     if (*curr_len <= new_len) {
1278     *curr_len = new_len + (*curr_len / 2);
1279     *dst = realloc(*dst, *curr_len);
1280     if (!*dst)
1281     err("could not realloc %li bytes", (unsigned long)*curr_len);
1282     }
1283    
1284     strcat(*dst, src);
1285     }
1286 solar 1.57
1287 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1288     {
1289     static char my_app[2];
1290     my_app[0] = append;
1291     my_app[1] = '\0';
1292     xstrcat(dst, my_app, curr_len);
1293     }
1294    
1295    
1296 vapier 1.72
1297 vapier 1.10 int main(int argc, char *argv[])
1298 solar 1.1 {
1299 vapier 1.10 if (argc < 2)
1300     usage(EXIT_FAILURE);
1301     parseargs(argc, argv);
1302 solar 1.21 fclose(stdout);
1303 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1304 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()");
1305 solar 1.61 #endif
1306 vapier 1.10 return EXIT_SUCCESS;
1307 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20