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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.141 - (hide annotations) (download) (as text)
Sun Apr 23 15:24:38 2006 UTC (8 years, 8 months ago) by flameeyes
Branch: MAIN
Changes since 1.140: +64 -6 lines
File MIME type: text/x-csrc
Implement function to lookup into ld-elf.so.hints file on FreeBSD and DragonFly, change to GLIBC/UCLIBC conditionals access to ld.so.conf and ls.so.cache (should work on GNU/kFreeBSD).

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

  ViewVC Help
Powered by ViewVC 1.1.20