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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.127 - (hide annotations) (download) (as text)
Fri Feb 17 07:13:54 2006 UTC (8 years, 8 months ago) by solar
Branch: MAIN
Changes since 1.126: +88 -24 lines
File MIME type: text/x-csrc
- added the -z/--setpax flags. PT_PAX_FLAGS flags start off with with ---xe- ; EI_PAX is not done yet. Renamed the reference to elmer fudd back.

1 solar 1.1 /*
2 vapier 1.98 * Copyright 2003-2006 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 solar 1.127 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.126 2006/02/16 05:47:23 vapier Exp $
5 solar 1.1 *
6 vapier 1.98 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.89 #include "paxinc.h"
11 solar 1.1
12 solar 1.127 static const char *rcsid = "$Id: scanelf.c,v 1.126 2006/02/16 05:47:23 vapier Exp $";
13 vapier 1.36 #define argv0 "scanelf"
14 vapier 1.10
15 vapier 1.70 #define IS_MODIFIER(c) (c == '%' || c == '#')
16    
17 vapier 1.10
18    
19     /* prototypes */
20 vapier 1.106 static int scanelf_elfobj(elfobj *elf);
21     static int scanelf_elf(const char *filename, int fd, size_t len);
22     static int scanelf_archive(const char *filename, int fd, size_t len);
23 vapier 1.10 static void scanelf_file(const char *filename);
24     static void scanelf_dir(const char *path);
25 vapier 1.106 static void scanelf_ldpath(void);
26     static void scanelf_envpath(void);
27 vapier 1.10 static void usage(int status);
28     static void parseargs(int argc, char *argv[]);
29 vapier 1.60 static char *xstrdup(const char *s);
30 vapier 1.41 static void *xmalloc(size_t size);
31 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32     #define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
33 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len);
34 vapier 1.10
35     /* variables to control behavior */
36 solar 1.119 static char match_etypes[126] = "";
37 vapier 1.48 static char *ldpaths[256];
38 vapier 1.10 static char scan_ldpath = 0;
39     static char scan_envpath = 0;
40 vapier 1.37 static char scan_symlink = 1;
41 vapier 1.105 static char scan_archives = 0;
42 vapier 1.10 static char dir_recurse = 0;
43 vapier 1.14 static char dir_crossmount = 1;
44 vapier 1.10 static char show_pax = 0;
45 solar 1.73 static char show_phdr = 0;
46 vapier 1.10 static char show_textrel = 0;
47     static char show_rpath = 0;
48 vapier 1.32 static char show_needed = 0;
49 vapier 1.38 static char show_interp = 0;
50 vapier 1.49 static char show_bind = 0;
51 vapier 1.84 static char show_soname = 0;
52 vapier 1.76 static char show_textrels = 0;
53 solar 1.16 static char show_banner = 1;
54 vapier 1.10 static char be_quiet = 0;
55 vapier 1.14 static char be_verbose = 0;
56 solar 1.127 static char be_wewy_wewy_quiet = 0;
57 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
58 vapier 1.72 static char *find_lib = NULL;
59 solar 1.124 static char *find_section = NULL;
60 vapier 1.39 static char *out_format = NULL;
61 vapier 1.66 static char *search_path = NULL;
62 vapier 1.101 static char fix_elf = 0;
63 solar 1.86 static char gmatch = 0;
64 vapier 1.102 static char use_ldcache = 0;
65 solar 1.1
66 solar 1.120 int match_bits = 0;
67 solar 1.96 caddr_t ldcache = 0;
68     size_t ldcache_size = 0;
69 solar 1.127 unsigned long setpax = 0UL;
70 solar 1.96
71 vapier 1.39 /* sub-funcs for scanelf_file() */
72 vapier 1.77 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73     {
74     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
75     #define GET_SYMTABS(B) \
76     if (elf->elf_class == ELFCLASS ## B) { \
77     Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
78     /* debug sections */ \
79     symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
80     strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
81     /* runtime sections */ \
82     dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
83     dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
84     if (symtab && dynsym) { \
85     *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
86     } else { \
87     *sym = (void*)(symtab ? symtab : dynsym); \
88     } \
89     if (strtab && dynstr) { \
90     *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
91     } else { \
92     *tab = (void*)(strtab ? strtab : dynstr); \
93     } \
94     }
95     GET_SYMTABS(32)
96     GET_SYMTABS(64)
97     }
98 solar 1.127
99 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
100 solar 1.6 {
101 solar 1.61 static char ret[7];
102     unsigned long i, shown;
103    
104 vapier 1.41 if (!show_pax) return NULL;
105 vapier 1.10
106 solar 1.61 shown = 0;
107     memset(&ret, 0, sizeof(ret));
108    
109     if (elf->phdr) {
110     #define SHOW_PAX(B) \
111     if (elf->elf_class == ELFCLASS ## B) { \
112     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
113     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
114     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
115     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
116     continue; \
117 solar 1.127 if (fix_elf && setpax) { \
118     /* set the paxctl flags */ \
119     ESET(phdr[i].p_flags, setpax); \
120     } \
121 solar 1.61 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
122     continue; \
123     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
124     *found_pax = 1; \
125     ++shown; \
126     break; \
127     } \
128     }
129     SHOW_PAX(32)
130     SHOW_PAX(64)
131     }
132    
133     /* fall back to EI_PAX if no PT_PAX was found */
134     if (!*ret) {
135 vapier 1.90 static char *paxflags;
136 solar 1.127
137     if (fix_elf && setpax) {
138     /* set the chpax settings */
139     // ESET(EHDR ## B (elf->ehdr)->e_ident[EI_PAX]), setpax);
140     }
141    
142 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
143     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
144     *found_pax = 1;
145 solar 1.127 return (be_wewy_wewy_quiet ? NULL : paxflags);
146 solar 1.61 }
147     strncpy(ret, paxflags, sizeof(ret));
148 vapier 1.14 }
149 vapier 1.41
150 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
151 solar 1.61 return NULL;
152 vapier 1.90 else
153     return ret;
154     }
155 solar 1.61
156 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
157 vapier 1.39 {
158 vapier 1.71 static char ret[12];
159 vapier 1.41 char *found;
160 vapier 1.99 unsigned long i, shown, multi_stack, multi_relro, multi_load;
161     int max_pt_load;
162 vapier 1.41
163 solar 1.73 if (!show_phdr) return NULL;
164 vapier 1.41
165 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
166    
167 vapier 1.41 shown = 0;
168 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
169 vapier 1.99 max_pt_load = elf_max_pt_load(elf);
170 vapier 1.44
171 vapier 1.108 #define NOTE_GNU_STACK ".note.GNU-stack"
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 vapier 1.91 Elf ## B ## _Off offset; \
176     uint32_t flags, check_flags; \
177     if (elf->phdr != NULL) { \
178     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
179     for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
180     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
181     if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
182     found = found_phdr; \
183     offset = 0; \
184     check_flags = PF_X; \
185     } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
186     if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
187     found = found_relro; \
188     offset = 4; \
189     check_flags = PF_X; \
190     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
191 solar 1.117 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
192     if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
193 vapier 1.91 found = found_load; \
194     offset = 8; \
195     check_flags = PF_W|PF_X; \
196     } else \
197     continue; \
198     flags = EGET(phdr[i].p_flags); \
199     if (be_quiet && ((flags & check_flags) != check_flags)) \
200     continue; \
201 vapier 1.101 if (fix_elf && ((flags & PF_X) != flags)) { \
202     ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
203     ret[3] = ret[7] = '!'; \
204     flags = EGET(phdr[i].p_flags); \
205     } \
206 vapier 1.91 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
207     *found = 1; \
208     ++shown; \
209     } \
210     } else if (elf->shdr != NULL) { \
211     /* no program headers which means this is prob an object file */ \
212     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
213     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
214 vapier 1.108 char *str; \
215 vapier 1.118 if ((void*)strtbl > (void*)elf->data_end) \
216 vapier 1.108 goto skip_this_shdr##B; \
217 vapier 1.91 check_flags = SHF_WRITE|SHF_EXECINSTR; \
218     for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
219     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
220     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
221 vapier 1.108 str = elf->data + offset; \
222     if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
223     if (!strcmp(str, NOTE_GNU_STACK)) { \
224 vapier 1.91 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
225     flags = EGET(shdr[i].sh_flags); \
226     if (be_quiet && ((flags & check_flags) != check_flags)) \
227     continue; \
228     ++*found_phdr; \
229     shown = 1; \
230     if (flags & SHF_WRITE) ret[0] = 'W'; \
231     if (flags & SHF_ALLOC) ret[1] = 'A'; \
232     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
233     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
234     break; \
235     } \
236     } \
237 vapier 1.108 skip_this_shdr##B: \
238 vapier 1.91 if (!multi_stack) { \
239     *found_phdr = 1; \
240     shown = 1; \
241     memcpy(ret, "!WX", 3); \
242     } \
243 vapier 1.39 } \
244     }
245 solar 1.73 SHOW_PHDR(32)
246     SHOW_PHDR(64)
247 vapier 1.44
248 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
249 vapier 1.41 return NULL;
250     else
251     return ret;
252 vapier 1.39 }
253 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
254 vapier 1.39 {
255 vapier 1.90 static const char *ret = "TEXTREL";
256 vapier 1.44 unsigned long i;
257 vapier 1.41
258 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
259 vapier 1.41
260 vapier 1.44 if (elf->phdr) {
261 vapier 1.39 #define SHOW_TEXTREL(B) \
262     if (elf->elf_class == ELFCLASS ## B) { \
263     Elf ## B ## _Dyn *dyn; \
264     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
265     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
266 vapier 1.44 Elf ## B ## _Off offset; \
267 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
268 vapier 1.59 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
269 vapier 1.44 offset = EGET(phdr[i].p_offset); \
270     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
271     dyn = DYN ## B (elf->data + offset); \
272 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
273     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
274     *found_textrel = 1; \
275     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
276 solar 1.127 return (be_wewy_wewy_quiet ? NULL : ret); \
277 vapier 1.39 } \
278     ++dyn; \
279 vapier 1.26 } \
280 vapier 1.39 } }
281     SHOW_TEXTREL(32)
282     SHOW_TEXTREL(64)
283 vapier 1.44 }
284    
285 solar 1.127 if (be_quiet || be_wewy_wewy_quiet)
286 vapier 1.41 return NULL;
287     else
288 vapier 1.90 return " - ";
289 vapier 1.39 }
290 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
291 vapier 1.76 {
292 vapier 1.82 unsigned long s, r, rmax;
293     void *symtab_void, *strtab_void, *text_void;
294 vapier 1.76
295     if (!show_textrels) return NULL;
296    
297 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
298     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
299     if (!*found_textrel) return NULL;
300    
301 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
302 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
303 vapier 1.76
304 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
305 vapier 1.76 #define SHOW_TEXTRELS(B) \
306     if (elf->elf_class == ELFCLASS ## B) { \
307     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
308     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
309     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
310     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
311 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
312     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
313     uint ## B ## _t memsz = EGET(text->sh_size); \
314 vapier 1.76 Elf ## B ## _Rel *rel; \
315     Elf ## B ## _Rela *rela; \
316     /* search the section headers for relocations */ \
317     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
318     uint32_t sh_type = EGET(shdr[s].sh_type); \
319     if (sh_type == SHT_REL) { \
320     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
321     rela = NULL; \
322     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
323     } else if (sh_type == SHT_RELA) { \
324     rel = NULL; \
325     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
326     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
327     } else \
328     continue; \
329 vapier 1.82 /* now see if any of the relocs are in the .text */ \
330     for (r = 0; r < rmax; ++r) { \
331     unsigned long sym_max; \
332     Elf ## B ## _Addr offset_tmp; \
333     Elf ## B ## _Sym *func; \
334     Elf ## B ## _Sym *sym; \
335     Elf ## B ## _Addr r_offset; \
336     uint ## B ## _t r_info; \
337     if (sh_type == SHT_REL) { \
338     r_offset = EGET(rel[r].r_offset); \
339     r_info = EGET(rel[r].r_info); \
340     } else { \
341     r_offset = EGET(rela[r].r_offset); \
342     r_info = EGET(rela[r].r_info); \
343     } \
344     /* make sure this relocation is inside of the .text */ \
345     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
346     if (be_verbose <= 2) continue; \
347     } else \
348 vapier 1.78 *found_textrels = 1; \
349 vapier 1.82 /* locate this relocation symbol name */ \
350     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
351 vapier 1.112 if ((void*)sym > (void*)elf->data_end) { \
352 vapier 1.111 warn("%s: corrupt ELF symbol", elf->filename); \
353 vapier 1.109 continue; \
354     } \
355 vapier 1.82 sym_max = ELF ## B ## _R_SYM(r_info); \
356     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
357     sym += sym_max; \
358     else \
359     sym = NULL; \
360     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
361     /* show the raw details about this reloc */ \
362 vapier 1.88 printf(" %s: ", elf->base_filename); \
363 vapier 1.82 if (sym && sym->st_name) \
364     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
365     else \
366 vapier 1.88 printf("(memory/fake?)"); \
367 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
368     /* now try to find the closest symbol that this rel is probably in */ \
369     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
370     func = NULL; \
371     offset_tmp = 0; \
372     while (sym_max--) { \
373     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
374     func = sym; \
375     offset_tmp = EGET(sym->st_value); \
376 vapier 1.76 } \
377 vapier 1.82 ++sym; \
378 vapier 1.76 } \
379 vapier 1.82 printf(" in "); \
380     if (func && func->st_name) \
381     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
382     else \
383     printf("(NULL: fake?)"); \
384     printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
385 vapier 1.76 } \
386     } }
387     SHOW_TEXTRELS(32)
388     SHOW_TEXTRELS(64)
389     }
390 vapier 1.82 if (!*found_textrels)
391     warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
392 vapier 1.76
393     return NULL;
394     }
395 solar 1.83
396 vapier 1.102 static void rpath_security_checks(elfobj *, char *, const char *);
397     static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
398 vapier 1.100 {
399 solar 1.83 struct stat st;
400 vapier 1.84 switch (*item) {
401 vapier 1.89 case '/': break;
402     case '.':
403 vapier 1.102 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
404 vapier 1.89 break;
405 vapier 1.100 case ':':
406 vapier 1.89 case '\0':
407 vapier 1.102 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
408 solar 1.83 break;
409     case '$':
410 vapier 1.84 if (fstat(elf->fd, &st) != -1)
411 solar 1.83 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
412 vapier 1.102 warnf("Security problem with %s='%s' in %s with mode set of %o",
413     dt_type, item, elf->filename, st.st_mode & 07777);
414 solar 1.83 break;
415     default:
416 vapier 1.102 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
417 solar 1.83 break;
418     }
419     }
420 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
421 vapier 1.39 {
422 vapier 1.48 unsigned long i, s;
423     char *rpath, *runpath, **r;
424 vapier 1.39 void *strtbl_void;
425 vapier 1.10
426 vapier 1.39 if (!show_rpath) return;
427 vapier 1.10
428 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
429     rpath = runpath = NULL;
430 vapier 1.10
431 vapier 1.44 if (elf->phdr && strtbl_void) {
432 vapier 1.26 #define SHOW_RPATH(B) \
433     if (elf->elf_class == ELFCLASS ## B) { \
434     Elf ## B ## _Dyn *dyn; \
435     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
436     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
437     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
438 vapier 1.44 Elf ## B ## _Off offset; \
439 vapier 1.60 Elf ## B ## _Xword word; \
440 vapier 1.48 /* Scan all the program headers */ \
441 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
442 vapier 1.48 /* Just scan dynamic headers */ \
443 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
444 vapier 1.44 offset = EGET(phdr[i].p_offset); \
445     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
446 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
447 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
448 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
449     if (word == DT_RPATH) { \
450     r = &rpath; \
451     } else if (word == DT_RUNPATH) { \
452     r = &runpath; \
453     } else { \
454     ++dyn; \
455     continue; \
456     } \
457     /* Verify the memory is somewhat sane */ \
458     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
459 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
460 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
461     *r = (char*)(elf->data + offset); \
462 vapier 1.103 /* cache the length in case we need to nuke this section later on */ \
463     if (fix_elf) \
464     offset = strlen(*r); \
465 vapier 1.48 /* If quiet, don't output paths in ld.so.conf */ \
466 vapier 1.69 if (be_quiet) { \
467     size_t len; \
468     char *start, *end; \
469 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
470     /* since *r is read-only memory, we can only move the ptr forward. */ \
471     start = *r; \
472     /* scan each path in : delimited list */ \
473     while (start) { \
474 vapier 1.102 rpath_security_checks(elf, start, get_elfdtype(word)); \
475 vapier 1.69 end = strchr(start, ':'); \
476 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
477 vapier 1.102 if (use_ldcache) \
478     for (s = 0; ldpaths[s]; ++s) \
479     if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
480     *r = end; \
481     /* corner case ... if RPATH reads "/usr/lib:", we want \
482     * to show ':' rather than '' */ \
483     if (end && end[1] != '\0') \
484     (*r)++; \
485     break; \
486     } \
487 vapier 1.100 if (!*r || !end) \
488     break; \
489 vapier 1.75 else \
490     start = start + len + 1; \
491 vapier 1.69 } \
492     } \
493 vapier 1.101 if (*r) { \
494 solar 1.107 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
495 vapier 1.101 /* just nuke it */ \
496     nuke_it##B: \
497 vapier 1.103 memset(*r, 0x00, offset); \
498 vapier 1.102 *r = NULL; \
499 vapier 1.101 ESET(dyn->d_tag, DT_DEBUG); \
500 vapier 1.103 ESET(dyn->d_un.d_ptr, 0); \
501 vapier 1.101 } else if (fix_elf) { \
502     /* try to clean "bad" paths */ \
503     size_t len, tmpdir_len; \
504     char *start, *end; \
505     const char *tmpdir; \
506     start = *r; \
507     tmpdir = (getenv("TMPDIR") ? : "."); \
508     tmpdir_len = strlen(tmpdir); \
509     while (1) { \
510     end = strchr(start, ':'); \
511     if (start == end) { \
512     eat_this_path##B: \
513     len = strlen(end); \
514     memmove(start, end+1, len); \
515     start[len-1] = '\0'; \
516     end = start - 1; \
517     } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
518     if (!end) { \
519     if (start == *r) \
520     goto nuke_it##B; \
521     *--start = '\0'; \
522     } else \
523     goto eat_this_path##B; \
524     } \
525     if (!end) \
526     break; \
527     start = end + 1; \
528     } \
529 vapier 1.102 if (**r == '\0') \
530     goto nuke_it##B; \
531 vapier 1.101 } \
532 vapier 1.102 if (*r) \
533     *found_rpath = 1; \
534 vapier 1.101 } \
535 vapier 1.26 } \
536     ++dyn; \
537     } \
538     } }
539     SHOW_RPATH(32)
540     SHOW_RPATH(64)
541 vapier 1.10 }
542 vapier 1.41
543 solar 1.127 if (be_wewy_wewy_quiet) return;
544 vapier 1.70
545 vapier 1.39 if (rpath && runpath) {
546 vapier 1.41 if (!strcmp(rpath, runpath)) {
547     xstrcat(ret, runpath, ret_len);
548     } else {
549 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
550 vapier 1.41 xchrcat(ret, '{', ret_len);
551     xstrcat(ret, rpath, ret_len);
552     xchrcat(ret, ',', ret_len);
553     xstrcat(ret, runpath, ret_len);
554     xchrcat(ret, '}', ret_len);
555 vapier 1.39 }
556     } else if (rpath || runpath)
557 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
558     else if (!be_quiet)
559     xstrcat(ret, " - ", ret_len);
560 vapier 1.39 }
561 solar 1.96
562     #define LDSO_CACHE_MAGIC "ld.so-"
563     #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
564     #define LDSO_CACHE_VER "1.7.0"
565     #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
566 vapier 1.97 #define FLAG_ANY -1
567     #define FLAG_TYPE_MASK 0x00ff
568     #define FLAG_LIBC4 0x0000
569     #define FLAG_ELF 0x0001
570     #define FLAG_ELF_LIBC5 0x0002
571     #define FLAG_ELF_LIBC6 0x0003
572     #define FLAG_REQUIRED_MASK 0xff00
573     #define FLAG_SPARC_LIB64 0x0100
574     #define FLAG_IA64_LIB64 0x0200
575     #define FLAG_X8664_LIB64 0x0300
576     #define FLAG_S390_LIB64 0x0400
577     #define FLAG_POWERPC_LIB64 0x0500
578     #define FLAG_MIPS64_LIBN32 0x0600
579     #define FLAG_MIPS64_LIBN64 0x0700
580 solar 1.96
581 vapier 1.97 static char *lookup_cache_lib(elfobj *, char *);
582     static char *lookup_cache_lib(elfobj *elf, char *fname)
583 solar 1.96 {
584     int fd = 0;
585     char *strs;
586 vapier 1.104 static char buf[__PAX_UTILS_PATH_MAX] = "";
587 solar 1.96 const char *cachefile = "/etc/ld.so.cache";
588     struct stat st;
589    
590     typedef struct {
591     char magic[LDSO_CACHE_MAGIC_LEN];
592     char version[LDSO_CACHE_VER_LEN];
593     int nlibs;
594     } header_t;
595 vapier 1.97 header_t *header;
596 solar 1.96
597     typedef struct {
598     int flags;
599     int sooffset;
600     int liboffset;
601     } libentry_t;
602     libentry_t *libent;
603    
604     if (fname == NULL)
605     return NULL;
606    
607     if (ldcache == 0) {
608 vapier 1.97 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
609 solar 1.96 return NULL;
610 vapier 1.97
611     /* cache these values so we only map/unmap the cache file once */
612 solar 1.96 ldcache_size = st.st_size;
613 vapier 1.97 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
614    
615     close(fd);
616 solar 1.96
617 solar 1.116 if (ldcache == (caddr_t)-1) {
618     ldcache = 0;
619 solar 1.96 return NULL;
620 solar 1.116 }
621 solar 1.96
622     if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
623     return NULL;
624     if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
625     return NULL;
626     }
627    
628     header = (header_t *) ldcache;
629     libent = (libentry_t *) (ldcache + sizeof(header_t));
630     strs = (char *) &libent[header->nlibs];
631    
632     for (fd = 0; fd < header->nlibs; fd++) {
633 vapier 1.97 /* this should be more fine grained, but for now we assume that
634     * diff arches will not be cached together. and we ignore the
635     * the different multilib mips cases. */
636     if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
637     continue;
638     if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
639     continue;
640    
641 solar 1.96 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
642     continue;
643     strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
644     }
645     return buf;
646     }
647    
648    
649 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)
650 vapier 1.39 {
651 vapier 1.44 unsigned long i;
652 vapier 1.39 char *needed;
653     void *strtbl_void;
654 solar 1.96 char *p;
655 vapier 1.39
656 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
657 vapier 1.10
658 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
659 vapier 1.32
660 vapier 1.44 if (elf->phdr && strtbl_void) {
661 vapier 1.32 #define SHOW_NEEDED(B) \
662     if (elf->elf_class == ELFCLASS ## B) { \
663     Elf ## B ## _Dyn *dyn; \
664     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
665     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
666     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
667 vapier 1.44 Elf ## B ## _Off offset; \
668 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
669     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
670 vapier 1.44 offset = EGET(phdr[i].p_offset); \
671     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
672     dyn = DYN ## B (elf->data + offset); \
673 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
674     if (EGET(dyn->d_tag) == DT_NEEDED) { \
675 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
676 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
677 vapier 1.49 ++dyn; \
678     continue; \
679     } \
680 vapier 1.44 needed = (char*)(elf->data + offset); \
681 vapier 1.72 if (op == 0) { \
682 solar 1.127 if (!be_wewy_wewy_quiet) { \
683 vapier 1.72 if (*found_needed) xchrcat(ret, ',', ret_len); \
684 vapier 1.102 if (use_ldcache) \
685 vapier 1.97 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
686 solar 1.96 needed = p; \
687 vapier 1.72 xstrcat(ret, needed, ret_len); \
688     } \
689     *found_needed = 1; \
690     } else { \
691 solar 1.86 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
692 vapier 1.81 *found_lib = 1; \
693 solar 1.127 return (be_wewy_wewy_quiet ? NULL : needed); \
694 vapier 1.81 } \
695 vapier 1.72 } \
696 vapier 1.32 } \
697     ++dyn; \
698     } \
699     } }
700     SHOW_NEEDED(32)
701     SHOW_NEEDED(64)
702 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
703 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
704 vapier 1.32 }
705 vapier 1.72
706     return NULL;
707 vapier 1.39 }
708 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
709 vapier 1.39 {
710     void *strtbl_void;
711    
712 vapier 1.41 if (!show_interp) return NULL;
713 vapier 1.32
714 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
715 vapier 1.38
716 vapier 1.39 if (strtbl_void) {
717 vapier 1.38 #define SHOW_INTERP(B) \
718     if (elf->elf_class == ELFCLASS ## B) { \
719 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
720     *found_interp = 1; \
721 solar 1.127 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
722 vapier 1.38 }
723     SHOW_INTERP(32)
724     SHOW_INTERP(64)
725     }
726 vapier 1.41 return NULL;
727 vapier 1.39 }
728 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
729     {
730     unsigned long i;
731     struct stat s;
732    
733     if (!show_bind) return NULL;
734 vapier 1.51 if (!elf->phdr) return NULL;
735 vapier 1.49
736     #define SHOW_BIND(B) \
737     if (elf->elf_class == ELFCLASS ## B) { \
738     Elf ## B ## _Dyn *dyn; \
739     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
740     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
741     Elf ## B ## _Off offset; \
742     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
743     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
744     offset = EGET(phdr[i].p_offset); \
745     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
746     dyn = DYN ## B (elf->data + offset); \
747     while (EGET(dyn->d_tag) != DT_NULL) { \
748     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
749     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
750     { \
751     if (be_quiet) return NULL; \
752     *found_bind = 1; \
753 solar 1.127 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
754 vapier 1.49 } \
755     ++dyn; \
756     } \
757     } \
758     }
759     SHOW_BIND(32)
760     SHOW_BIND(64)
761    
762 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
763 vapier 1.70
764 vapier 1.56 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
765 vapier 1.49 return NULL;
766     } else {
767     *found_bind = 1;
768 solar 1.68 return (char *) "LAZY";
769 vapier 1.49 }
770     }
771 vapier 1.84 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
772     {
773     unsigned long i;
774     char *soname;
775     void *strtbl_void;
776    
777     if (!show_soname) return NULL;
778    
779     strtbl_void = elf_findsecbyname(elf, ".dynstr");
780    
781     if (elf->phdr && strtbl_void) {
782     #define SHOW_SONAME(B) \
783     if (elf->elf_class == ELFCLASS ## B) { \
784     Elf ## B ## _Dyn *dyn; \
785     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
786     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
787     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
788     Elf ## B ## _Off offset; \
789     /* only look for soname in shared objects */ \
790     if (ehdr->e_type != ET_DYN) \
791     return NULL; \
792     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
793     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
794     offset = EGET(phdr[i].p_offset); \
795     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
796     dyn = DYN ## B (elf->data + offset); \
797     while (EGET(dyn->d_tag) != DT_NULL) { \
798     if (EGET(dyn->d_tag) == DT_SONAME) { \
799     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
800     if (offset >= (Elf ## B ## _Off)elf->len) { \
801     ++dyn; \
802     continue; \
803     } \
804     soname = (char*)(elf->data + offset); \
805     *found_soname = 1; \
806 solar 1.127 return (be_wewy_wewy_quiet ? NULL : soname); \
807 vapier 1.84 } \
808     ++dyn; \
809     } \
810     } }
811     SHOW_SONAME(32)
812     SHOW_SONAME(64)
813     }
814    
815     return NULL;
816     }
817 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
818 vapier 1.39 {
819 vapier 1.44 unsigned long i;
820 vapier 1.95 char *ret;
821 vapier 1.39 void *symtab_void, *strtab_void;
822 vapier 1.38
823 vapier 1.41 if (!find_sym) return NULL;
824 vapier 1.95 ret = find_sym;
825 vapier 1.32
826 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
827 vapier 1.27
828 vapier 1.39 if (symtab_void && strtab_void) {
829 vapier 1.27 #define FIND_SYM(B) \
830     if (elf->elf_class == ELFCLASS ## B) { \
831     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
832     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
833     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
834 vapier 1.115 unsigned long cnt = EGET(symtab->sh_entsize); \
835 vapier 1.27 char *symname; \
836 vapier 1.115 if (cnt) \
837     cnt = EGET(symtab->sh_size) / cnt; \
838 vapier 1.27 for (i = 0; i < cnt; ++i) { \
839     if (sym->st_name) { \
840     symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
841 vapier 1.115 if ((void*)symname > (void*)elf->data_end) { \
842     warnf("%s: corrupt ELF symbols", elf->filename); \
843 vapier 1.111 continue; \
844     } \
845 solar 1.28 if (*find_sym == '*') { \
846 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
847 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
848 vapier 1.76 elf->base_filename, \
849 vapier 1.94 (unsigned long)sym->st_size, \
850 vapier 1.95 get_elfstttype(sym->st_info), \
851 vapier 1.32 symname); \
852 vapier 1.39 *found_sym = 1; \
853 vapier 1.95 } else { \
854     char *this_sym, *next_sym; \
855     this_sym = find_sym; \
856     do { \
857     next_sym = strchr(this_sym, ','); \
858     if (next_sym == NULL) \
859     next_sym = this_sym + strlen(this_sym); \
860     if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
861     (strcmp(symname, versioned_symname) == 0)) { \
862     ret = this_sym; \
863     (*found_sym)++; \
864     goto break_out; \
865     } \
866     this_sym = next_sym + 1; \
867     } while (*next_sym != '\0'); \
868     } \
869 vapier 1.27 } \
870     ++sym; \
871     } }
872     FIND_SYM(32)
873     FIND_SYM(64)
874 vapier 1.39 }
875 vapier 1.70
876 vapier 1.95 break_out:
877 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
878 vapier 1.70
879 vapier 1.41 if (*find_sym != '*' && *found_sym)
880 vapier 1.95 return ret;
881 vapier 1.41 if (be_quiet)
882     return NULL;
883     else
884 solar 1.68 return (char *)" - ";
885 vapier 1.39 }
886 solar 1.119
887    
888 solar 1.124 static char *scanelf_file_sections(elfobj *elf, char *found_section)
889     {
890     if (!find_section)
891     return NULL;
892    
893     #define FIND_SECTION(B) \
894     if (elf->elf_class == ELFCLASS ## B) { \
895     Elf ## B ## _Shdr *section; \
896     section = SHDR ## B (elf_findsecbyname(elf, find_section)); \
897     if (section != NULL) \
898     *found_section = 1; \
899     }
900     FIND_SECTION(32)
901     FIND_SECTION(64)
902    
903    
904 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
905 solar 1.124
906     if (*found_section)
907     return find_section;
908    
909     if (be_quiet)
910     return NULL;
911     else
912     return (char *)" - ";
913     }
914    
915 vapier 1.39 /* scan an elf file and show all the fun stuff */
916 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
917 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
918 vapier 1.39 {
919 vapier 1.44 unsigned long i;
920 solar 1.73 char found_pax, found_phdr, found_relro, found_load, found_textrel,
921 vapier 1.84 found_rpath, found_needed, found_interp, found_bind, found_soname,
922 solar 1.124 found_sym, found_lib, found_file, found_textrels, found_section;
923 vapier 1.41 static char *out_buffer = NULL;
924     static size_t out_len;
925 vapier 1.39
926 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
927 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
928 solar 1.124 found_sym = found_lib = found_file = found_textrels = found_section = 0;
929 vapier 1.39
930 vapier 1.114 if (be_verbose > 2)
931 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
932 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
933     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
934 vapier 1.114 else if (be_verbose > 1)
935 vapier 1.106 printf("%s: scanning file\n", elf->filename);
936 vapier 1.39
937 vapier 1.41 /* init output buffer */
938     if (!out_buffer) {
939     out_len = sizeof(char) * 80;
940     out_buffer = (char*)xmalloc(out_len);
941     }
942     *out_buffer = '\0';
943    
944 vapier 1.39 /* show the header */
945     if (!be_quiet && show_banner) {
946 vapier 1.49 for (i = 0; out_format[i]; ++i) {
947 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
948 vapier 1.41
949     switch (out_format[++i]) {
950     case '%': break;
951 vapier 1.70 case '#': break;
952 vapier 1.66 case 'F':
953     case 'p':
954     case 'f': prints("FILE "); found_file = 1; break;
955 vapier 1.41 case 'o': prints(" TYPE "); break;
956     case 'x': prints(" PAX "); break;
957 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
958 vapier 1.41 case 't': prints("TEXTREL "); break;
959     case 'r': prints("RPATH "); break;
960     case 'n': prints("NEEDED "); break;
961     case 'i': prints("INTERP "); break;
962 vapier 1.49 case 'b': prints("BIND "); break;
963 vapier 1.84 case 'S': prints("SONAME "); break;
964 vapier 1.41 case 's': prints("SYM "); break;
965 vapier 1.72 case 'N': prints("LIB "); break;
966 vapier 1.76 case 'T': prints("TEXTRELS "); break;
967 vapier 1.126 case 'k': prints("SECTION "); break;
968 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
969 vapier 1.39 }
970 vapier 1.27 }
971 vapier 1.49 if (!found_file) prints("FILE ");
972 vapier 1.41 prints("\n");
973 vapier 1.49 found_file = 0;
974 vapier 1.39 show_banner = 0;
975     }
976    
977     /* dump all the good stuff */
978 vapier 1.49 for (i = 0; out_format[i]; ++i) {
979 vapier 1.41 const char *out;
980 vapier 1.66 const char *tmp;
981 vapier 1.41
982 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
983 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
984     continue;
985     }
986 vapier 1.39
987 vapier 1.41 out = NULL;
988 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
989 vapier 1.41 switch (out_format[++i]) {
990 vapier 1.70 case '%':
991     case '#':
992     xchrcat(&out_buffer, out_format[i], &out_len); break;
993     case 'F':
994 vapier 1.76 found_file = 1;
995 solar 1.127 if (be_wewy_wewy_quiet) break;
996 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
997 vapier 1.70 break;
998 vapier 1.66 case 'p':
999 vapier 1.76 found_file = 1;
1000 solar 1.127 if (be_wewy_wewy_quiet) break;
1001 vapier 1.106 tmp = elf->filename;
1002 vapier 1.66 if (search_path) {
1003     ssize_t len_search = strlen(search_path);
1004 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1005     if (!strncmp(elf->filename, search_path, len_search) && \
1006 vapier 1.66 len_file > len_search)
1007     tmp += len_search;
1008     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1009     }
1010     xstrcat(&out_buffer, tmp, &out_len);
1011     break;
1012     case 'f':
1013 vapier 1.76 found_file = 1;
1014 solar 1.127 if (be_wewy_wewy_quiet) break;
1015 vapier 1.106 tmp = strrchr(elf->filename, '/');
1016     tmp = (tmp == NULL ? elf->filename : tmp+1);
1017 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1018     break;
1019 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1020     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1021 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1022 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1023 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1024 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1025 vapier 1.72 case 'n':
1026     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1027 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1028 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1029 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1030 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1031 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1032 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1033 vapier 1.29 }
1034 vapier 1.95 if (out) {
1035     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1036     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1037     xstrncat(&out_buffer, out, &out_len, (tmp-out));
1038     else
1039     xstrcat(&out_buffer, out, &out_len);
1040     }
1041 vapier 1.39 }
1042    
1043 vapier 1.54 #define FOUND_SOMETHING() \
1044 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1045 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1046 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1047 vapier 1.54
1048     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1049     xchrcat(&out_buffer, ' ', &out_len);
1050 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1051 vapier 1.27 }
1052 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1053 vapier 1.41 puts(out_buffer);
1054 vapier 1.79 fflush(stdout);
1055     }
1056 vapier 1.10
1057 vapier 1.105 return 0;
1058     }
1059    
1060 vapier 1.106 /* scan a single elf */
1061     static int scanelf_elf(const char *filename, int fd, size_t len)
1062     {
1063 solar 1.120 int ret = 1;
1064 vapier 1.106 elfobj *elf;
1065    
1066     /* verify this is real ELF */
1067     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1068     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1069 solar 1.120 return ret;
1070     }
1071     switch (match_bits) {
1072     case 32:
1073     if (elf->elf_class != ELFCLASS32)
1074     goto label_done;
1075     break;
1076     case 64:
1077     if (elf->elf_class != ELFCLASS64)
1078     goto label_done;
1079     break;
1080     default: break;
1081 vapier 1.106 }
1082 solar 1.119 if (strlen(match_etypes)) {
1083     char sbuf[126];
1084     strncpy(sbuf, match_etypes, sizeof(sbuf));
1085     if (strchr(match_etypes, ',') != NULL) {
1086     char *p;
1087     while((p = strrchr(sbuf, ',')) != NULL) {
1088     *p = 0;
1089     if (atoi(p+1) == get_etype(elf))
1090     goto label_ret;
1091     }
1092     }
1093 solar 1.120 if (atoi(sbuf) != get_etype(elf))
1094 solar 1.119 goto label_done;
1095     }
1096    
1097     label_ret:
1098 vapier 1.106 ret = scanelf_elfobj(elf);
1099 solar 1.119
1100     label_done:
1101 vapier 1.106 unreadelf(elf);
1102     return ret;
1103     }
1104 solar 1.119
1105 vapier 1.105 /* scan an archive of elfs */
1106 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1107 vapier 1.105 {
1108 vapier 1.106 archive_handle *ar;
1109 vapier 1.105 archive_member *m;
1110 vapier 1.106 char *ar_buffer;
1111     elfobj *elf;
1112    
1113     ar = ar_open_fd(filename, fd);
1114     if (ar == NULL)
1115     return 1;
1116    
1117     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1118     while ((m=ar_next(ar)) != NULL) {
1119     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1120     if (elf) {
1121     scanelf_elfobj(elf);
1122     unreadelf(elf);
1123     }
1124     }
1125     munmap(ar_buffer, len);
1126    
1127 vapier 1.105 return 0;
1128     }
1129     /* scan a file which may be an elf or an archive or some other magical beast */
1130     static void scanelf_file(const char *filename)
1131     {
1132     struct stat st;
1133 vapier 1.106 int fd;
1134 vapier 1.105
1135     /* make sure 'filename' exists */
1136     if (lstat(filename, &st) == -1) {
1137     if (be_verbose > 2) printf("%s: does not exist\n", filename);
1138     return;
1139     }
1140    
1141     /* always handle regular files and handle symlinked files if no -y */
1142     if (S_ISLNK(st.st_mode)) {
1143     if (!scan_symlink) return;
1144     stat(filename, &st);
1145     }
1146     if (!S_ISREG(st.st_mode)) {
1147     if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1148     return;
1149     }
1150    
1151 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1152     return;
1153    
1154     if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1155 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1156 vapier 1.106 scanelf_archive(filename, fd, st.st_size);
1157    
1158     close(fd);
1159 solar 1.6 }
1160    
1161 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1162 vapier 1.10 static void scanelf_dir(const char *path)
1163 solar 1.1 {
1164 vapier 1.10 register DIR *dir;
1165     register struct dirent *dentry;
1166 vapier 1.14 struct stat st_top, st;
1167 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1168 vapier 1.32 size_t pathlen = 0, len = 0;
1169 vapier 1.10
1170     /* make sure path exists */
1171 vapier 1.39 if (lstat(path, &st_top) == -1) {
1172     if (be_verbose > 2) printf("%s: does not exist\n", path);
1173 vapier 1.10 return;
1174 vapier 1.39 }
1175 solar 1.11
1176 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1177 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1178 vapier 1.10 scanelf_file(path);
1179     return;
1180     }
1181    
1182     /* now scan the dir looking for fun stuff */
1183     if ((dir = opendir(path)) == NULL) {
1184     warnf("could not opendir %s: %s", path, strerror(errno));
1185     return;
1186     }
1187 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1188 solar 1.11
1189 vapier 1.32 pathlen = strlen(path);
1190 vapier 1.10 while ((dentry = readdir(dir))) {
1191     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1192     continue;
1193 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1194     if (len >= sizeof(buf)) {
1195 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1196     (unsigned long)len, (unsigned long)sizeof(buf));
1197 vapier 1.32 continue;
1198     }
1199 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
1200 solar 1.20 if (lstat(buf, &st) != -1) {
1201 vapier 1.10 if (S_ISREG(st.st_mode))
1202 solar 1.20 scanelf_file(buf);
1203 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1204 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1205 solar 1.20 scanelf_dir(buf);
1206 vapier 1.10 }
1207     }
1208     }
1209     closedir(dir);
1210 solar 1.1 }
1211    
1212 vapier 1.47 static int scanelf_from_file(char *filename)
1213     {
1214 solar 1.45 FILE *fp = NULL;
1215     char *p;
1216 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1217 solar 1.45
1218     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
1219     fp = stdin;
1220     else if ((fp = fopen(filename, "r")) == NULL)
1221     return 1;
1222    
1223 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1224 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1225     *p = 0;
1226 vapier 1.66 search_path = path;
1227 solar 1.45 scanelf_dir(path);
1228     }
1229     if (fp != stdin)
1230     fclose(fp);
1231     return 0;
1232     }
1233    
1234 solar 1.123 static int load_ld_so_conf(int i, const char *fname)
1235 vapier 1.48 {
1236     FILE *fp = NULL;
1237     char *p;
1238 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1239 vapier 1.48
1240 solar 1.123 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1241     return i;
1242    
1243     if ((fp = fopen(fname, "r")) == NULL)
1244     return i;
1245 vapier 1.48
1246 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1247 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1248     *p = 0;
1249     if ((p = strchr(path, '\n')) != NULL)
1250     *p = 0;
1251 solar 1.123 #ifdef HAVE_GLOB
1252     // recursive includes of the same file will make this segfault.
1253     if ((*path == 'i') && (strncmp(path, "include", 7) == 0) && isblank(path[7])) {
1254     glob64_t gl;
1255     size_t x;
1256     char gpath[__PAX_UTILS_PATH_MAX];
1257    
1258     gpath[sizeof(gpath)] = 0;
1259    
1260     if (path[8] != '/')
1261     snprintf(gpath, sizeof(gpath)-1, "/etc/%s", &path[8]);
1262     else
1263     strncpy(gpath, &path[8], sizeof(gpath)-1);
1264    
1265     if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1266     for (x = 0; x < gl.gl_pathc; ++x) {
1267     /* try to avoid direct loops */
1268     if (strcmp(gl.gl_pathv[x], fname) == 0)
1269     continue;
1270     i = load_ld_so_conf(i, gl.gl_pathv[x]);
1271     if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) {
1272     globfree64(&gl);
1273     return i;
1274     }
1275     }
1276     globfree64 (&gl);
1277     continue;
1278     } else
1279     abort();
1280     }
1281     #endif
1282     if (*path != '/')
1283     continue;
1284 vapier 1.48
1285     ldpaths[i++] = xstrdup(path);
1286    
1287     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1288     break;
1289     }
1290     ldpaths[i] = NULL;
1291    
1292     fclose(fp);
1293 solar 1.123 return i;
1294 vapier 1.48 }
1295    
1296 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1297     static void scanelf_ldpath()
1298     {
1299 vapier 1.17 char scan_l, scan_ul, scan_ull;
1300 vapier 1.48 int i = 0;
1301 vapier 1.10
1302 vapier 1.48 if (!ldpaths[0])
1303     err("Unable to load any paths from ld.so.conf");
1304 vapier 1.10
1305 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1306    
1307 vapier 1.48 while (ldpaths[i]) {
1308     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1309     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1310     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1311     scanelf_dir(ldpaths[i]);
1312     ++i;
1313     }
1314 vapier 1.10
1315 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1316     if (!scan_ul) scanelf_dir("/usr/lib");
1317     if (!scan_ull) scanelf_dir("/usr/local/lib");
1318 vapier 1.10 }
1319 solar 1.1
1320 vapier 1.10 /* scan env PATH for paths */
1321     static void scanelf_envpath()
1322 solar 1.1 {
1323 solar 1.34 char *path, *p;
1324 vapier 1.10
1325     path = getenv("PATH");
1326     if (!path)
1327     err("PATH is not set in your env !");
1328 vapier 1.41 path = xstrdup(path);
1329 vapier 1.10
1330     while ((p = strrchr(path, ':')) != NULL) {
1331     scanelf_dir(p + 1);
1332     *p = 0;
1333     }
1334 vapier 1.17
1335 solar 1.34 free(path);
1336 solar 1.1 }
1337    
1338 vapier 1.10 /* usage / invocation handling functions */
1339 solar 1.127 #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1340 vapier 1.27 #define a_argument required_argument
1341 vapier 1.10 static struct option const long_opts[] = {
1342     {"path", no_argument, NULL, 'p'},
1343     {"ldpath", no_argument, NULL, 'l'},
1344     {"recursive", no_argument, NULL, 'R'},
1345 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1346 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1347 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1348     {"ldcache", no_argument, NULL, 'L'},
1349 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1350 solar 1.127 {"setpax", a_argument, NULL, 'z'},
1351 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1352 solar 1.16 {"header", no_argument, NULL, 'e'},
1353 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1354     {"rpath", no_argument, NULL, 'r'},
1355 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1356 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1357 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1358 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1359 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1360 solar 1.124 {"section", a_argument, NULL, 'k'},
1361 vapier 1.76 {"lib", a_argument, NULL, 'N'},
1362 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1363 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1364 solar 1.119 {"etype", a_argument, NULL, 'E'},
1365 solar 1.120 {"bits", a_argument, NULL, 'M'},
1366 vapier 1.10 {"all", no_argument, NULL, 'a'},
1367     {"quiet", no_argument, NULL, 'q'},
1368 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1369 vapier 1.76 {"format", a_argument, NULL, 'F'},
1370     {"from", a_argument, NULL, 'f'},
1371     {"file", a_argument, NULL, 'o'},
1372 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1373 vapier 1.10 {"help", no_argument, NULL, 'h'},
1374     {"version", no_argument, NULL, 'V'},
1375     {NULL, no_argument, NULL, 0x0}
1376     };
1377 solar 1.57
1378 solar 1.68 static const char *opts_help[] = {
1379 vapier 1.10 "Scan all directories in PATH environment",
1380     "Scan all directories in /etc/ld.so.conf",
1381 vapier 1.14 "Scan directories recursively",
1382 vapier 1.37 "Don't recursively cross mount points",
1383 vapier 1.101 "Don't scan symlinks",
1384 vapier 1.105 "Scan archives (.a files)",
1385     "Utilize ld.so.cache information (use with -r/-n)",
1386 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
1387     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1388 vapier 1.10 "Print PaX markings",
1389 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1390 vapier 1.10 "Print TEXTREL information",
1391     "Print RPATH information",
1392 vapier 1.32 "Print NEEDED information",
1393 vapier 1.38 "Print INTERP information",
1394 vapier 1.49 "Print BIND information",
1395 vapier 1.84 "Print SONAME information",
1396 vapier 1.27 "Find a specified symbol",
1397 solar 1.124 "Find a specified section",
1398 vapier 1.72 "Find a specified library",
1399 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1400 vapier 1.76 "Locate cause of TEXTREL",
1401 solar 1.120 "Print only ELF files matching numeric constant type",
1402     "Print only ELF files matching numeric bits",
1403 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1404 vapier 1.14 "Only output 'bad' things",
1405     "Be verbose (can be specified more than once)",
1406 vapier 1.39 "Use specified format for output",
1407 solar 1.45 "Read input stream from a filename",
1408 vapier 1.24 "Write output stream to a filename",
1409 vapier 1.14 "Don't display the header",
1410 vapier 1.10 "Print this help and exit",
1411     "Print version and exit",
1412     NULL
1413     };
1414    
1415     /* display usage and exit */
1416     static void usage(int status)
1417 solar 1.1 {
1418 vapier 1.44 unsigned long i;
1419 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1420 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1421 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1422 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1423 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1424 solar 1.124 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1425 vapier 1.27 long_opts[i].name, opts_help[i]);
1426     else
1427 solar 1.124 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1428 vapier 1.27 long_opts[i].name, opts_help[i]);
1429 solar 1.45
1430     if (status != EXIT_SUCCESS)
1431     exit(status);
1432 solar 1.125
1433 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
1434 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1435     puts(" t TEXTREL \tr RPATH \tn NEEDED");
1436     puts(" i INTERP \tb BIND \ts symbol");
1437 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
1438 solar 1.125 puts(" S SONAME \tk section");
1439 vapier 1.70 puts(" p filename (with search path removed)");
1440 vapier 1.88 puts(" f filename (short name/basename)");
1441 vapier 1.70 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1442 solar 1.45
1443 solar 1.121 puts("\nELF Etypes:");
1444     print_etypes(stdout);
1445    
1446 vapier 1.10 exit(status);
1447 solar 1.1 }
1448    
1449     /* parse command line arguments and preform needed actions */
1450 vapier 1.10 static void parseargs(int argc, char *argv[])
1451     {
1452 vapier 1.48 int i;
1453 solar 1.45 char *from_file = NULL;
1454 vapier 1.10
1455     opterr = 0;
1456 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1457     switch (i) {
1458 vapier 1.10
1459 vapier 1.39 case 'V':
1460 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1461     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1462     VERSION, __FILE__, __DATE__, rcsid, argv0);
1463 vapier 1.10 exit(EXIT_SUCCESS);
1464     break;
1465     case 'h': usage(EXIT_SUCCESS); break;
1466 solar 1.45 case 'f':
1467 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1468     from_file = optarg;
1469 solar 1.45 break;
1470 solar 1.119 case 'E':
1471     strncpy(match_etypes, optarg, sizeof(match_etypes));
1472     break;
1473 solar 1.120 case 'M':
1474     match_bits = atoi(optarg);
1475     break;
1476 vapier 1.24 case 'o': {
1477 solar 1.21 FILE *fp = NULL;
1478 solar 1.64 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1479 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1480 vapier 1.65 SET_STDOUT(fp);
1481 solar 1.21 break;
1482     }
1483 solar 1.124 case 'k':
1484 vapier 1.126 if (find_section) warn("You prob don't want to specify -k twice");
1485 solar 1.124 find_section = optarg;
1486     break;
1487 vapier 1.39 case 's': {
1488 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1489     find_sym = optarg;
1490     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1491 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1492     break;
1493     }
1494 vapier 1.72 case 'N': {
1495 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1496     find_lib = optarg;
1497 vapier 1.72 break;
1498     }
1499 vapier 1.39
1500     case 'F': {
1501 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1502     out_format = optarg;
1503 vapier 1.39 break;
1504     }
1505 solar 1.127 case 'z': {
1506     unsigned long flags = 10240;
1507     size_t x;
1508 vapier 1.27
1509 solar 1.127 #define do_state(option, flag) \
1510     if (islower(option)) { \
1511     flags &= ~PF_##flag; \
1512     flags |= PF_NO##flag; \
1513     } else { \
1514     flags &= ~PF_NO##flag; \
1515     flags |= PF_##flag; \
1516     }
1517    
1518     for (x = 0 ; x < strlen(optarg); x++) {
1519     switch(optarg[x]) {
1520     case 'p':
1521     case 'P':
1522     do_state(optarg[x], PAGEEXEC);
1523     break;
1524     case 's':
1525     case 'S':
1526     do_state(optarg[x], SEGMEXEC);
1527     break;
1528     case 'm':
1529     case 'M':
1530     do_state(optarg[x], MPROTECT);
1531     break;
1532     case 'e':
1533     case 'E':
1534     do_state(optarg[x], EMUTRAMP);
1535     break;
1536     case 'r':
1537     case 'R':
1538     do_state(optarg[x], RANDMMAP);
1539     break;
1540     case 'x':
1541     case 'X':
1542     do_state(optarg[x], RANDEXEC);
1543     break;
1544     default:
1545     break;
1546     }
1547     }
1548     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1549     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1550     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1551     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1552     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1553     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1554     setpax = flags;
1555     break;
1556     }
1557 vapier 1.122 case 'g': gmatch = 1; break;
1558 vapier 1.102 case 'L': use_ldcache = 1; break;
1559 vapier 1.37 case 'y': scan_symlink = 0; break;
1560 vapier 1.105 case 'A': scan_archives = 1; break;
1561 solar 1.16 case 'B': show_banner = 0; break;
1562 vapier 1.10 case 'l': scan_ldpath = 1; break;
1563     case 'p': scan_envpath = 1; break;
1564     case 'R': dir_recurse = 1; break;
1565 vapier 1.14 case 'm': dir_crossmount = 0; break;
1566 vapier 1.101 case 'X': ++fix_elf; break;
1567 vapier 1.10 case 'x': show_pax = 1; break;
1568 solar 1.73 case 'e': show_phdr = 1; break;
1569 vapier 1.10 case 't': show_textrel = 1; break;
1570     case 'r': show_rpath = 1; break;
1571 vapier 1.32 case 'n': show_needed = 1; break;
1572 vapier 1.38 case 'i': show_interp = 1; break;
1573 vapier 1.49 case 'b': show_bind = 1; break;
1574 vapier 1.84 case 'S': show_soname = 1; break;
1575 vapier 1.76 case 'T': show_textrels = 1; break;
1576 vapier 1.10 case 'q': be_quiet = 1; break;
1577 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1578 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1579 vapier 1.10
1580     case ':':
1581 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1582 vapier 1.10 case '?':
1583 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1584 vapier 1.10 default:
1585 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1586 vapier 1.10 }
1587     }
1588    
1589 vapier 1.39 /* let the format option override all other options */
1590     if (out_format) {
1591 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1592 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1593     show_textrels = 0;
1594 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1595 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1596 vapier 1.39
1597 vapier 1.48 switch (out_format[++i]) {
1598 vapier 1.39 case '%': break;
1599 vapier 1.70 case '#': break;
1600 vapier 1.39 case 'F': break;
1601 vapier 1.66 case 'p': break;
1602     case 'f': break;
1603 solar 1.124 case 'k': break;
1604 vapier 1.39 case 's': break;
1605 vapier 1.72 case 'N': break;
1606 vapier 1.41 case 'o': break;
1607 vapier 1.39 case 'x': show_pax = 1; break;
1608 solar 1.73 case 'e': show_phdr = 1; break;
1609 vapier 1.39 case 't': show_textrel = 1; break;
1610     case 'r': show_rpath = 1; break;
1611     case 'n': show_needed = 1; break;
1612     case 'i': show_interp = 1; break;
1613 vapier 1.49 case 'b': show_bind = 1; break;
1614 vapier 1.84 case 'S': show_soname = 1; break;
1615 vapier 1.76 case 'T': show_textrels = 1; break;
1616 vapier 1.39 default:
1617     err("Invalid format specifier '%c' (byte %i)",
1618 vapier 1.48 out_format[i], i+1);
1619 vapier 1.39 }
1620     }
1621 vapier 1.41
1622     /* construct our default format */
1623     } else {
1624     size_t fmt_len = 30;
1625     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1626 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1627     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1628     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1629     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1630     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1631     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1632     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1633     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1634 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1635 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1636     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1637 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1638 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1639     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1640 vapier 1.39 }
1641 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1642 vapier 1.39
1643     /* now lets actually do the scanning */
1644 vapier 1.102 if (scan_ldpath || use_ldcache)
1645 solar 1.123 load_ld_so_conf(0, "/etc/ld.so.conf");
1646 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1647     if (scan_envpath) scanelf_envpath();
1648 solar 1.45 if (from_file) {
1649     scanelf_from_file(from_file);
1650     from_file = *argv;
1651     }
1652     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1653 vapier 1.25 err("Nothing to scan !?");
1654 vapier 1.66 while (optind < argc) {
1655     search_path = argv[optind++];
1656     scanelf_dir(search_path);
1657     }
1658 vapier 1.27
1659 vapier 1.39 /* clean up */
1660 vapier 1.93 if (versioned_symname) free(versioned_symname);
1661 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1662     free(ldpaths[i]);
1663 solar 1.96
1664     if (ldcache != 0)
1665     munmap(ldcache, ldcache_size);
1666 vapier 1.10 }
1667    
1668    
1669    
1670 vapier 1.41 /* utility funcs */
1671 vapier 1.60 static char *xstrdup(const char *s)
1672 vapier 1.41 {
1673     char *ret = strdup(s);
1674     if (!ret) err("Could not strdup(): %s", strerror(errno));
1675     return ret;
1676     }
1677     static void *xmalloc(size_t size)
1678     {
1679     void *ret = malloc(size);
1680     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1681     return ret;
1682     }
1683 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1684 vapier 1.41 {
1685 vapier 1.69 size_t new_len;
1686 vapier 1.41
1687     new_len = strlen(*dst) + strlen(src);
1688     if (*curr_len <= new_len) {
1689     *curr_len = new_len + (*curr_len / 2);
1690     *dst = realloc(*dst, *curr_len);
1691     if (!*dst)
1692 vapier 1.95 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1693 vapier 1.41 }
1694    
1695 vapier 1.95 if (n)
1696     strncat(*dst, src, n);
1697     else
1698     strcat(*dst, src);
1699 vapier 1.41 }
1700     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1701     {
1702     static char my_app[2];
1703     my_app[0] = append;
1704     my_app[1] = '\0';
1705     xstrcat(dst, my_app, curr_len);
1706     }
1707    
1708    
1709 vapier 1.72
1710 vapier 1.10 int main(int argc, char *argv[])
1711 solar 1.1 {
1712 vapier 1.10 if (argc < 2)
1713     usage(EXIT_FAILURE);
1714     parseargs(argc, argv);
1715 solar 1.21 fclose(stdout);
1716 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1717 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()");
1718 solar 1.61 #endif
1719 vapier 1.10 return EXIT_SUCCESS;
1720 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20