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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.85 - (hide annotations) (download) (as text)
Mon Jul 25 23:31:32 2005 UTC (9 years, 4 months ago) by vapier
Branch: MAIN
Changes since 1.84: +3 -5 lines
File MIME type: text/x-csrc
complain if a shared object is missing DT_NEEDED and if we are in verbose mode

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

  ViewVC Help
Powered by ViewVC 1.1.20