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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.129 - (hide annotations) (download) (as text)
Sat Feb 18 15:51:11 2006 UTC (8 years, 9 months ago) by solar
Branch: MAIN
Changes since 1.128: +18 -15 lines
File MIME type: text/x-csrc
- Make -E take strings vs just numerics. Fixed off by one in ld.so.conf include file handling(Reported by PaX autho.r).  Made sure we only set ei pax flags when etype is ET_EXEC || ET_DYN. Updated README, man page

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

  ViewVC Help
Powered by ViewVC 1.1.20