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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.197 - (hide annotations) (download) (as text)
Mon Nov 17 18:03:38 2008 UTC (6 years, 1 month ago) by flameeyes
Branch: MAIN
Changes since 1.196: +32 -15 lines
File MIME type: text/x-csrc
Rewrite symbol matching code in scanelf.

The previous code was entirely broken when trying to match symbols in
unstripped binaries when giving multiple symbols as target.

The new code differs from the old one in quite a few ways:

- debug output when -g option is passed is disabled in the code
  (hacky, but still better than before!);

- regular expression matching is actually used when -g option is
  passed;

- by default, the symbol name is tested against the symbol name
  without version; no-version symbol name matching is possible by
  using the -g option and adding a final $;

- multiple symbols and single symbols are handled in the same way so
  that there is no more difference between them;

- the returned symbol name is the actual symbol name as found in the
  file, so includes the version when the file is not stripped.

While this means that there are some minimal differences between the
previous code, it's arguable that this code is less buggy and more
consistent than the one before.

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

  ViewVC Help
Powered by ViewVC 1.1.20