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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.179 - (hide annotations) (download) (as text)
Sat Jun 9 18:54:44 2007 UTC (7 years, 4 months ago) by solar
Branch: MAIN
Changes since 1.178: +4 -4 lines
File MIME type: text/x-csrc
- update copyright headers

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

  ViewVC Help
Powered by ViewVC 1.1.20