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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.154 - (hide annotations) (download) (as text)
Sat Jun 3 18:25:18 2006 UTC (9 years ago) by solar
Branch: MAIN
Changes since 1.153: +29 -3 lines
File MIME type: text/x-csrc
- add work arounds for NetBSD

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

  ViewVC Help
Powered by ViewVC 1.1.20