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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.119 - (hide annotations) (download) (as text)
Sun Feb 5 02:25:58 2006 UTC (8 years, 9 months ago) by solar
Branch: MAIN
Changes since 1.118: +33 -4 lines
File MIME type: text/x-csrc
- add ability to scan files based on etype via new -E option. syntax is -E 1 or -E 1,2,3,4

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

  ViewVC Help
Powered by ViewVC 1.1.20