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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.136 - (hide annotations) (download) (as text)
Fri Mar 17 15:27:00 2006 UTC (8 years, 4 months ago) by solar
Branch: MAIN
Changes since 1.135: +6 -4 lines
File MIME type: text/x-csrc
- add invert matching for section headers from spanky for flameeyes. Example: scanelf -B -k \!.symtab /usr/lib/debug -Rq -F%F#k

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

  ViewVC Help
Powered by ViewVC 1.1.20