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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20