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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.155 - (hide annotations) (download) (as text)
Sun Jun 11 00:07:33 2006 UTC (8 years, 3 months ago) by vapier
Branch: MAIN
Changes since 1.154: +72 -70 lines
File MIME type: text/x-csrc
move utility funcs back to the bottom where they belong

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

  ViewVC Help
Powered by ViewVC 1.1.20