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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.138 - (hide annotations) (download) (as text)
Fri Mar 31 06:07:47 2006 UTC (8 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.137: +4 -4 lines
File MIME type: text/x-csrc
touchup style

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

  ViewVC Help
Powered by ViewVC 1.1.20