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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.128 - (hide annotations) (download) (as text)
Fri Feb 17 15:36:16 2006 UTC (8 years, 4 months ago) by solar
Branch: MAIN
Changes since 1.127: +11 -8 lines
File MIME type: text/x-csrc
- finished up ei_pax handling

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

  ViewVC Help
Powered by ViewVC 1.1.20