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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.131 - (hide annotations) (download) (as text)
Thu Mar 2 14:40:53 2006 UTC (8 years, 1 month ago) by solar
Branch: MAIN
Changes since 1.130: +5 -3 lines
File MIME type: text/x-csrc
- we do not want to display lazy bindings incorrectly on executable files that were linked static

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

  ViewVC Help
Powered by ViewVC 1.1.20