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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.88 - (hide annotations) (download) (as text)
Fri Sep 30 03:30:54 2005 UTC (8 years, 10 months ago) by vapier
Branch: MAIN
Changes since 1.87: +5 -4 lines
File MIME type: text/x-csrc
touchup output of TEXTREL matches and update the format help output

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

  ViewVC Help
Powered by ViewVC 1.1.20