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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.134 - (hide annotations) (download) (as text)
Wed Mar 15 03:20:29 2006 UTC (8 years, 6 months ago) by vapier
Branch: MAIN
Changes since 1.133: +21 -5 lines
File MIME type: text/x-csrc
add support for scanning for just defined/undefined symbols

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

  ViewVC Help
Powered by ViewVC 1.1.20