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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.224 - (hide annotations) (download) (as text)
Mon Aug 8 01:56:16 2011 UTC (2 years, 11 months ago) by vapier
Branch: MAIN
Changes since 1.223: +4 -4 lines
File MIME type: text/x-csrc
fixup style in previous root patch

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

  ViewVC Help
Powered by ViewVC 1.1.20