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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.86 - (hide annotations) (download) (as text)
Sat Sep 24 16:17:53 2005 UTC (8 years, 6 months ago) by solar
Branch: MAIN
Changes since 1.85: +9 -6 lines
File MIME type: text/x-csrc
- add gmatching option to scanelf so that matching libz.so works with the -N option

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 solar 1.86 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.85 2005/07/25 23:31:32 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 solar 1.86 static const char *rcsid = "$Id: scanelf.c,v 1.85 2005/07/25 23:31:32 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 solar 1.86 static char gmatch = 0;
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 solar 1.86 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
502 vapier 1.81 *found_lib = 1; \
503 solar 1.86 return (be_wewy_wewy_quiet ? NULL : needed); \
504 vapier 1.81 } \
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 solar 1.86 #define PARSE_FLAGS "plRmyxetrnibSs:gN: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 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1004 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1005 vapier 1.10 {"all", no_argument, NULL, 'a'},
1006     {"quiet", no_argument, NULL, 'q'},
1007 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1008 vapier 1.76 {"format", a_argument, NULL, 'F'},
1009     {"from", a_argument, NULL, 'f'},
1010     {"file", a_argument, NULL, 'o'},
1011 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1012 vapier 1.10 {"help", no_argument, NULL, 'h'},
1013     {"version", no_argument, NULL, 'V'},
1014     {NULL, no_argument, NULL, 0x0}
1015     };
1016 solar 1.57
1017 solar 1.68 static const char *opts_help[] = {
1018 vapier 1.10 "Scan all directories in PATH environment",
1019     "Scan all directories in /etc/ld.so.conf",
1020 vapier 1.14 "Scan directories recursively",
1021 vapier 1.37 "Don't recursively cross mount points",
1022     "Don't scan symlinks\n",
1023 vapier 1.10 "Print PaX markings",
1024 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1025 vapier 1.10 "Print TEXTREL information",
1026     "Print RPATH information",
1027 vapier 1.32 "Print NEEDED information",
1028 vapier 1.38 "Print INTERP information",
1029 vapier 1.49 "Print BIND information",
1030 vapier 1.84 "Print SONAME information",
1031 vapier 1.27 "Find a specified symbol",
1032 vapier 1.72 "Find a specified library",
1033 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1034 vapier 1.76 "Locate cause of TEXTREL",
1035 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1036 vapier 1.14 "Only output 'bad' things",
1037     "Be verbose (can be specified more than once)",
1038 vapier 1.39 "Use specified format for output",
1039 solar 1.45 "Read input stream from a filename",
1040 vapier 1.24 "Write output stream to a filename",
1041 vapier 1.14 "Don't display the header",
1042 vapier 1.10 "Print this help and exit",
1043     "Print version and exit",
1044     NULL
1045     };
1046    
1047     /* display usage and exit */
1048     static void usage(int status)
1049 solar 1.1 {
1050 vapier 1.44 unsigned long i;
1051 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1052 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
1053     printf("Options: -[%s]\n", PARSE_FLAGS);
1054 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1055 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1056 solar 1.52 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
1057 vapier 1.27 long_opts[i].name, opts_help[i]);
1058     else
1059 solar 1.52 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
1060 vapier 1.27 long_opts[i].name, opts_help[i]);
1061 solar 1.45
1062     if (status != EXIT_SUCCESS)
1063     exit(status);
1064    
1065 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
1066 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1067     puts(" t TEXTREL \tr RPATH \tn NEEDED");
1068     puts(" i INTERP \tb BIND \ts symbol");
1069 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
1070 vapier 1.70 puts(" p filename (with search path removed)");
1071     puts(" f base filename");
1072     puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1073 solar 1.45
1074 vapier 1.10 exit(status);
1075 solar 1.1 }
1076    
1077     /* parse command line arguments and preform needed actions */
1078 vapier 1.10 static void parseargs(int argc, char *argv[])
1079     {
1080 vapier 1.48 int i;
1081 solar 1.45 char *from_file = NULL;
1082 vapier 1.10
1083     opterr = 0;
1084 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1085     switch (i) {
1086 vapier 1.10
1087 vapier 1.39 case 'V':
1088 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1089     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1090     VERSION, __FILE__, __DATE__, rcsid, argv0);
1091 vapier 1.10 exit(EXIT_SUCCESS);
1092     break;
1093     case 'h': usage(EXIT_SUCCESS); break;
1094 solar 1.45 case 'f':
1095 solar 1.64 if (from_file) err("Don't specify -f twice");
1096     from_file = xstrdup(optarg);
1097 solar 1.45 break;
1098 vapier 1.24 case 'o': {
1099 solar 1.21 FILE *fp = NULL;
1100 solar 1.64 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1101 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1102 vapier 1.65 SET_STDOUT(fp);
1103 solar 1.21 break;
1104     }
1105 vapier 1.24
1106 vapier 1.39 case 's': {
1107     size_t len;
1108 solar 1.64 if (find_sym) err("Don't specify -s twice");
1109 vapier 1.41 find_sym = xstrdup(optarg);
1110 vapier 1.39 len = strlen(find_sym) + 1;
1111 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
1112 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1113     break;
1114     }
1115 vapier 1.72 case 'N': {
1116     if (find_lib) err("Don't specify -N twice");
1117     find_lib = xstrdup(optarg);
1118     break;
1119     }
1120 vapier 1.39
1121     case 'F': {
1122 solar 1.64 if (out_format) err("Don't specify -F twice");
1123     out_format = xstrdup(optarg);
1124 vapier 1.39 break;
1125     }
1126 vapier 1.27
1127 solar 1.86 case 'g': gmatch = 1;
1128 vapier 1.37 case 'y': scan_symlink = 0; break;
1129 solar 1.16 case 'B': show_banner = 0; break;
1130 vapier 1.10 case 'l': scan_ldpath = 1; break;
1131     case 'p': scan_envpath = 1; break;
1132     case 'R': dir_recurse = 1; break;
1133 vapier 1.14 case 'm': dir_crossmount = 0; break;
1134 vapier 1.10 case 'x': show_pax = 1; break;
1135 solar 1.73 case 'e': show_phdr = 1; break;
1136 vapier 1.10 case 't': show_textrel = 1; break;
1137     case 'r': show_rpath = 1; break;
1138 vapier 1.32 case 'n': show_needed = 1; break;
1139 vapier 1.38 case 'i': show_interp = 1; break;
1140 vapier 1.49 case 'b': show_bind = 1; break;
1141 vapier 1.84 case 'S': show_soname = 1; break;
1142 vapier 1.76 case 'T': show_textrels = 1; break;
1143 vapier 1.10 case 'q': be_quiet = 1; break;
1144 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1145 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1146 vapier 1.10
1147     case ':':
1148 vapier 1.49 err("Option missing parameter\n");
1149 vapier 1.10 case '?':
1150 vapier 1.49 err("Unknown option\n");
1151 vapier 1.10 default:
1152 vapier 1.48 err("Unhandled option '%c'", i);
1153 vapier 1.10 }
1154     }
1155    
1156 vapier 1.39 /* let the format option override all other options */
1157     if (out_format) {
1158 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1159 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1160     show_textrels = 0;
1161 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1162 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1163 vapier 1.39
1164 vapier 1.48 switch (out_format[++i]) {
1165 vapier 1.39 case '%': break;
1166 vapier 1.70 case '#': break;
1167 vapier 1.39 case 'F': break;
1168 vapier 1.66 case 'p': break;
1169     case 'f': break;
1170 vapier 1.39 case 's': break;
1171 vapier 1.72 case 'N': break;
1172 vapier 1.41 case 'o': break;
1173 vapier 1.39 case 'x': show_pax = 1; break;
1174 solar 1.73 case 'e': show_phdr = 1; break;
1175 vapier 1.39 case 't': show_textrel = 1; break;
1176     case 'r': show_rpath = 1; break;
1177     case 'n': show_needed = 1; break;
1178     case 'i': show_interp = 1; break;
1179 vapier 1.49 case 'b': show_bind = 1; break;
1180 vapier 1.84 case 'S': show_soname = 1; break;
1181 vapier 1.76 case 'T': show_textrels = 1; break;
1182 vapier 1.39 default:
1183     err("Invalid format specifier '%c' (byte %i)",
1184 vapier 1.48 out_format[i], i+1);
1185 vapier 1.39 }
1186     }
1187 vapier 1.41
1188     /* construct our default format */
1189     } else {
1190     size_t fmt_len = 30;
1191     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1192 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1193     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1194     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1195     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1196     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1197     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1198     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1199     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1200 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1201 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1202     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1203     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1204     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1205 vapier 1.39 }
1206 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1207 vapier 1.39
1208     /* now lets actually do the scanning */
1209 vapier 1.48 if (scan_ldpath || (show_rpath && be_quiet))
1210     load_ld_so_conf();
1211 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1212     if (scan_envpath) scanelf_envpath();
1213 solar 1.45 if (from_file) {
1214     scanelf_from_file(from_file);
1215     free(from_file);
1216     from_file = *argv;
1217     }
1218     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1219 vapier 1.25 err("Nothing to scan !?");
1220 vapier 1.66 while (optind < argc) {
1221     search_path = argv[optind++];
1222     scanelf_dir(search_path);
1223     }
1224 vapier 1.27
1225 vapier 1.39 /* clean up */
1226     if (find_sym) {
1227     free(find_sym);
1228     free(versioned_symname);
1229     }
1230 vapier 1.72 if (find_lib) free(find_lib);
1231 vapier 1.39 if (out_format) free(out_format);
1232 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1233     free(ldpaths[i]);
1234 vapier 1.10 }
1235    
1236    
1237    
1238 vapier 1.41 /* utility funcs */
1239 vapier 1.60 static char *xstrdup(const char *s)
1240 vapier 1.41 {
1241     char *ret = strdup(s);
1242     if (!ret) err("Could not strdup(): %s", strerror(errno));
1243     return ret;
1244     }
1245 solar 1.57
1246 vapier 1.41 static void *xmalloc(size_t size)
1247     {
1248     void *ret = malloc(size);
1249     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1250     return ret;
1251     }
1252 solar 1.57
1253 vapier 1.41 static void xstrcat(char **dst, const char *src, size_t *curr_len)
1254     {
1255 vapier 1.69 size_t new_len;
1256 vapier 1.41
1257     new_len = strlen(*dst) + strlen(src);
1258     if (*curr_len <= new_len) {
1259     *curr_len = new_len + (*curr_len / 2);
1260     *dst = realloc(*dst, *curr_len);
1261     if (!*dst)
1262     err("could not realloc %li bytes", (unsigned long)*curr_len);
1263     }
1264    
1265     strcat(*dst, src);
1266     }
1267 solar 1.57
1268 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1269     {
1270     static char my_app[2];
1271     my_app[0] = append;
1272     my_app[1] = '\0';
1273     xstrcat(dst, my_app, curr_len);
1274     }
1275    
1276    
1277 vapier 1.72
1278 vapier 1.10 int main(int argc, char *argv[])
1279 solar 1.1 {
1280 vapier 1.10 if (argc < 2)
1281     usage(EXIT_FAILURE);
1282     parseargs(argc, argv);
1283 solar 1.21 fclose(stdout);
1284 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1285 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()");
1286 solar 1.61 #endif
1287 vapier 1.10 return EXIT_SUCCESS;
1288 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20