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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.94 - (hide annotations) (download) (as text)
Sat Dec 10 04:10:26 2005 UTC (8 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.93: +3 -3 lines
File MIME type: text/x-csrc
st_size is unsigned, so dont cast it to signed

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.94 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.93 2005/12/10 04:07:55 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.94 static const char *rcsid = "$Id: scanelf.c,v 1.93 2005/12/10 04:07:55 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.94 (unsigned long)sym->st_size, \
670 vapier 1.32 (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 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1127     find_sym = optarg;
1128     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1129 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1130     break;
1131     }
1132 vapier 1.72 case 'N': {
1133 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1134     find_lib = optarg;
1135 vapier 1.72 break;
1136     }
1137 vapier 1.39
1138     case 'F': {
1139 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1140     out_format = optarg;
1141 vapier 1.39 break;
1142     }
1143 vapier 1.27
1144 solar 1.86 case 'g': gmatch = 1;
1145 vapier 1.37 case 'y': scan_symlink = 0; break;
1146 solar 1.16 case 'B': show_banner = 0; break;
1147 vapier 1.10 case 'l': scan_ldpath = 1; break;
1148     case 'p': scan_envpath = 1; break;
1149     case 'R': dir_recurse = 1; break;
1150 vapier 1.14 case 'm': dir_crossmount = 0; break;
1151 vapier 1.10 case 'x': show_pax = 1; break;
1152 solar 1.73 case 'e': show_phdr = 1; break;
1153 vapier 1.10 case 't': show_textrel = 1; break;
1154     case 'r': show_rpath = 1; break;
1155 vapier 1.32 case 'n': show_needed = 1; break;
1156 vapier 1.38 case 'i': show_interp = 1; break;
1157 vapier 1.49 case 'b': show_bind = 1; break;
1158 vapier 1.84 case 'S': show_soname = 1; break;
1159 vapier 1.76 case 'T': show_textrels = 1; break;
1160 vapier 1.10 case 'q': be_quiet = 1; break;
1161 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1162 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1163 vapier 1.10
1164     case ':':
1165 vapier 1.49 err("Option missing parameter\n");
1166 vapier 1.10 case '?':
1167 vapier 1.49 err("Unknown option\n");
1168 vapier 1.10 default:
1169 vapier 1.48 err("Unhandled option '%c'", i);
1170 vapier 1.10 }
1171     }
1172    
1173 vapier 1.39 /* let the format option override all other options */
1174     if (out_format) {
1175 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1176 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1177     show_textrels = 0;
1178 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1179 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1180 vapier 1.39
1181 vapier 1.48 switch (out_format[++i]) {
1182 vapier 1.39 case '%': break;
1183 vapier 1.70 case '#': break;
1184 vapier 1.39 case 'F': break;
1185 vapier 1.66 case 'p': break;
1186     case 'f': break;
1187 vapier 1.39 case 's': break;
1188 vapier 1.72 case 'N': break;
1189 vapier 1.41 case 'o': break;
1190 vapier 1.39 case 'x': show_pax = 1; break;
1191 solar 1.73 case 'e': show_phdr = 1; break;
1192 vapier 1.39 case 't': show_textrel = 1; break;
1193     case 'r': show_rpath = 1; break;
1194     case 'n': show_needed = 1; break;
1195     case 'i': show_interp = 1; break;
1196 vapier 1.49 case 'b': show_bind = 1; break;
1197 vapier 1.84 case 'S': show_soname = 1; break;
1198 vapier 1.76 case 'T': show_textrels = 1; break;
1199 vapier 1.39 default:
1200     err("Invalid format specifier '%c' (byte %i)",
1201 vapier 1.48 out_format[i], i+1);
1202 vapier 1.39 }
1203     }
1204 vapier 1.41
1205     /* construct our default format */
1206     } else {
1207     size_t fmt_len = 30;
1208     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1209 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1210     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1211     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1212     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1213     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1214     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1215     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1216     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1217 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1218 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1219     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1220     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1221     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1222 vapier 1.39 }
1223 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1224 vapier 1.39
1225     /* now lets actually do the scanning */
1226 vapier 1.48 if (scan_ldpath || (show_rpath && be_quiet))
1227     load_ld_so_conf();
1228 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1229     if (scan_envpath) scanelf_envpath();
1230 solar 1.45 if (from_file) {
1231     scanelf_from_file(from_file);
1232     free(from_file);
1233     from_file = *argv;
1234     }
1235     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1236 vapier 1.25 err("Nothing to scan !?");
1237 vapier 1.66 while (optind < argc) {
1238     search_path = argv[optind++];
1239     scanelf_dir(search_path);
1240     }
1241 vapier 1.27
1242 vapier 1.39 /* clean up */
1243 vapier 1.93 if (versioned_symname) free(versioned_symname);
1244 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1245     free(ldpaths[i]);
1246 vapier 1.10 }
1247    
1248    
1249    
1250 vapier 1.41 /* utility funcs */
1251 vapier 1.60 static char *xstrdup(const char *s)
1252 vapier 1.41 {
1253     char *ret = strdup(s);
1254     if (!ret) err("Could not strdup(): %s", strerror(errno));
1255     return ret;
1256     }
1257 solar 1.57
1258 vapier 1.41 static void *xmalloc(size_t size)
1259     {
1260     void *ret = malloc(size);
1261     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1262     return ret;
1263     }
1264 solar 1.57
1265 vapier 1.41 static void xstrcat(char **dst, const char *src, size_t *curr_len)
1266     {
1267 vapier 1.69 size_t new_len;
1268 vapier 1.41
1269     new_len = strlen(*dst) + strlen(src);
1270     if (*curr_len <= new_len) {
1271     *curr_len = new_len + (*curr_len / 2);
1272     *dst = realloc(*dst, *curr_len);
1273     if (!*dst)
1274     err("could not realloc %li bytes", (unsigned long)*curr_len);
1275     }
1276    
1277     strcat(*dst, src);
1278     }
1279 solar 1.57
1280 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1281     {
1282     static char my_app[2];
1283     my_app[0] = append;
1284     my_app[1] = '\0';
1285     xstrcat(dst, my_app, curr_len);
1286     }
1287    
1288    
1289 vapier 1.72
1290 vapier 1.10 int main(int argc, char *argv[])
1291 solar 1.1 {
1292 vapier 1.10 if (argc < 2)
1293     usage(EXIT_FAILURE);
1294     parseargs(argc, argv);
1295 solar 1.21 fclose(stdout);
1296 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1297 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()");
1298 solar 1.61 #endif
1299 vapier 1.10 return EXIT_SUCCESS;
1300 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20