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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.175 - (hide annotations) (download) (as text)
Thu Jan 18 08:15:16 2007 UTC (7 years, 5 months ago) by solar
Branch: MAIN
Changes since 1.174: +4 -3 lines
File MIME type: text/x-csrc
typo

1 solar 1.1 /*
2 vapier 1.98 * Copyright 2003-2006 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 solar 1.175 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.174 2007/01/18 08:12:55 solar Exp $
5 solar 1.1 *
6 vapier 1.98 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.89 #include "paxinc.h"
11 flameeyes 1.141
12 solar 1.175 static const char *rcsid = "$Id: scanelf.c,v 1.174 2007/01/18 08:12:55 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.86 static char gmatch = 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 vapier 1.102 dt_type, item, elf->filename, st.st_mode & 07777);
517 solar 1.83 break;
518     default:
519 vapier 1.102 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
520 solar 1.83 break;
521     }
522     }
523 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
524 vapier 1.39 {
525 vapier 1.48 unsigned long i, s;
526     char *rpath, *runpath, **r;
527 vapier 1.39 void *strtbl_void;
528 vapier 1.10
529 vapier 1.39 if (!show_rpath) return;
530 vapier 1.10
531 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
532     rpath = runpath = NULL;
533 vapier 1.10
534 vapier 1.44 if (elf->phdr && strtbl_void) {
535 vapier 1.26 #define SHOW_RPATH(B) \
536     if (elf->elf_class == ELFCLASS ## B) { \
537     Elf ## B ## _Dyn *dyn; \
538     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
539     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
540     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
541 vapier 1.44 Elf ## B ## _Off offset; \
542 vapier 1.60 Elf ## B ## _Xword word; \
543 vapier 1.48 /* Scan all the program headers */ \
544 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
545 vapier 1.48 /* Just scan dynamic headers */ \
546 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
547 vapier 1.44 offset = EGET(phdr[i].p_offset); \
548     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
549 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
550 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
551 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
552     if (word == DT_RPATH) { \
553     r = &rpath; \
554     } else if (word == DT_RUNPATH) { \
555     r = &runpath; \
556     } else { \
557     ++dyn; \
558     continue; \
559     } \
560     /* Verify the memory is somewhat sane */ \
561     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
562 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
563 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
564     *r = (char*)(elf->data + offset); \
565 vapier 1.103 /* cache the length in case we need to nuke this section later on */ \
566     if (fix_elf) \
567     offset = strlen(*r); \
568 vapier 1.48 /* If quiet, don't output paths in ld.so.conf */ \
569 vapier 1.69 if (be_quiet) { \
570     size_t len; \
571     char *start, *end; \
572 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
573     /* since *r is read-only memory, we can only move the ptr forward. */ \
574     start = *r; \
575     /* scan each path in : delimited list */ \
576     while (start) { \
577 vapier 1.102 rpath_security_checks(elf, start, get_elfdtype(word)); \
578 vapier 1.69 end = strchr(start, ':'); \
579 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
580 vapier 1.102 if (use_ldcache) \
581     for (s = 0; ldpaths[s]; ++s) \
582     if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
583     *r = end; \
584     /* corner case ... if RPATH reads "/usr/lib:", we want \
585     * to show ':' rather than '' */ \
586     if (end && end[1] != '\0') \
587     (*r)++; \
588     break; \
589     } \
590 vapier 1.100 if (!*r || !end) \
591     break; \
592 vapier 1.75 else \
593     start = start + len + 1; \
594 vapier 1.69 } \
595     } \
596 vapier 1.101 if (*r) { \
597 solar 1.107 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
598 vapier 1.101 /* just nuke it */ \
599     nuke_it##B: \
600 vapier 1.103 memset(*r, 0x00, offset); \
601 vapier 1.102 *r = NULL; \
602 vapier 1.101 ESET(dyn->d_tag, DT_DEBUG); \
603 vapier 1.103 ESET(dyn->d_un.d_ptr, 0); \
604 vapier 1.101 } else if (fix_elf) { \
605     /* try to clean "bad" paths */ \
606     size_t len, tmpdir_len; \
607     char *start, *end; \
608     const char *tmpdir; \
609     start = *r; \
610     tmpdir = (getenv("TMPDIR") ? : "."); \
611     tmpdir_len = strlen(tmpdir); \
612     while (1) { \
613     end = strchr(start, ':'); \
614     if (start == end) { \
615     eat_this_path##B: \
616     len = strlen(end); \
617     memmove(start, end+1, len); \
618     start[len-1] = '\0'; \
619     end = start - 1; \
620     } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
621     if (!end) { \
622     if (start == *r) \
623     goto nuke_it##B; \
624     *--start = '\0'; \
625     } else \
626     goto eat_this_path##B; \
627     } \
628     if (!end) \
629     break; \
630     start = end + 1; \
631     } \
632 vapier 1.102 if (**r == '\0') \
633     goto nuke_it##B; \
634 vapier 1.101 } \
635 vapier 1.102 if (*r) \
636     *found_rpath = 1; \
637 vapier 1.101 } \
638 vapier 1.26 } \
639     ++dyn; \
640     } \
641     } }
642     SHOW_RPATH(32)
643     SHOW_RPATH(64)
644 vapier 1.10 }
645 vapier 1.41
646 solar 1.127 if (be_wewy_wewy_quiet) return;
647 vapier 1.70
648 vapier 1.39 if (rpath && runpath) {
649 vapier 1.41 if (!strcmp(rpath, runpath)) {
650     xstrcat(ret, runpath, ret_len);
651     } else {
652 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
653 vapier 1.41 xchrcat(ret, '{', ret_len);
654     xstrcat(ret, rpath, ret_len);
655     xchrcat(ret, ',', ret_len);
656     xstrcat(ret, runpath, ret_len);
657     xchrcat(ret, '}', ret_len);
658 vapier 1.39 }
659     } else if (rpath || runpath)
660 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
661     else if (!be_quiet)
662     xstrcat(ret, " - ", ret_len);
663 vapier 1.39 }
664 solar 1.96
665     #define LDSO_CACHE_MAGIC "ld.so-"
666     #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
667     #define LDSO_CACHE_VER "1.7.0"
668     #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
669 vapier 1.97 #define FLAG_ANY -1
670     #define FLAG_TYPE_MASK 0x00ff
671     #define FLAG_LIBC4 0x0000
672     #define FLAG_ELF 0x0001
673     #define FLAG_ELF_LIBC5 0x0002
674     #define FLAG_ELF_LIBC6 0x0003
675     #define FLAG_REQUIRED_MASK 0xff00
676     #define FLAG_SPARC_LIB64 0x0100
677     #define FLAG_IA64_LIB64 0x0200
678     #define FLAG_X8664_LIB64 0x0300
679     #define FLAG_S390_LIB64 0x0400
680     #define FLAG_POWERPC_LIB64 0x0500
681     #define FLAG_MIPS64_LIBN32 0x0600
682     #define FLAG_MIPS64_LIBN64 0x0700
683 solar 1.96
684 vapier 1.97 static char *lookup_cache_lib(elfobj *, char *);
685 vapier 1.148
686 flameeyes 1.141 #if defined(__GLIBC__) || defined(__UCLIBC__)
687 vapier 1.148
688 vapier 1.97 static char *lookup_cache_lib(elfobj *elf, char *fname)
689 solar 1.96 {
690     int fd = 0;
691     char *strs;
692 vapier 1.104 static char buf[__PAX_UTILS_PATH_MAX] = "";
693 solar 1.96 const char *cachefile = "/etc/ld.so.cache";
694     struct stat st;
695    
696     typedef struct {
697     char magic[LDSO_CACHE_MAGIC_LEN];
698     char version[LDSO_CACHE_VER_LEN];
699     int nlibs;
700     } header_t;
701 vapier 1.97 header_t *header;
702 solar 1.96
703     typedef struct {
704     int flags;
705     int sooffset;
706     int liboffset;
707     } libentry_t;
708     libentry_t *libent;
709    
710     if (fname == NULL)
711     return NULL;
712    
713     if (ldcache == 0) {
714 vapier 1.97 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
715 solar 1.96 return NULL;
716 vapier 1.97
717     /* cache these values so we only map/unmap the cache file once */
718 solar 1.96 ldcache_size = st.st_size;
719 vapier 1.97 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
720    
721     close(fd);
722 solar 1.96
723 solar 1.116 if (ldcache == (caddr_t)-1) {
724     ldcache = 0;
725 solar 1.96 return NULL;
726 solar 1.116 }
727 solar 1.96
728     if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
729     return NULL;
730     if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
731     return NULL;
732     }
733    
734     header = (header_t *) ldcache;
735     libent = (libentry_t *) (ldcache + sizeof(header_t));
736     strs = (char *) &libent[header->nlibs];
737    
738     for (fd = 0; fd < header->nlibs; fd++) {
739 vapier 1.97 /* this should be more fine grained, but for now we assume that
740     * diff arches will not be cached together. and we ignore the
741     * the different multilib mips cases. */
742     if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
743     continue;
744     if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
745     continue;
746    
747 solar 1.96 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
748     continue;
749     strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
750     }
751     return buf;
752     }
753 solar 1.154 #elif defined(__NetBSD__)
754     static char *lookup_cache_lib(elfobj *elf, char *fname)
755     {
756     static char buf[__PAX_UTILS_PATH_MAX] = "";
757     static struct stat st;
758    
759     char **ldpath;
760     for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
761     if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
762     continue; /* if the pathname is too long, or something went wrong, ignore */
763    
764     if (stat(buf, &st) != 0)
765     continue; /* if the lib doesn't exist in *ldpath, look further */
766    
767     /* NetBSD doesn't actually do sanity checks, it just loads the file
768     * and if that doesn't work, continues looking in other directories.
769     * This cannot easily be safely emulated, unfortunately. For now,
770     * just assume that if it exists, it's a valid library. */
771 vapier 1.148
772 solar 1.154 return buf;
773     }
774    
775     /* not found in any path */
776     return NULL;
777     }
778 flameeyes 1.141 #else
779 vapier 1.148 #warning Cache support not implemented for your target
780 flameeyes 1.141 static char *lookup_cache_lib(elfobj *elf, char *fname)
781     {
782     return NULL;
783     }
784     #endif
785 solar 1.96
786 vapier 1.84 static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
787 vapier 1.39 {
788 vapier 1.44 unsigned long i;
789 vapier 1.39 char *needed;
790     void *strtbl_void;
791 solar 1.96 char *p;
792 vapier 1.39
793 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
794 vapier 1.10
795 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
796 vapier 1.32
797 vapier 1.44 if (elf->phdr && strtbl_void) {
798 vapier 1.32 #define SHOW_NEEDED(B) \
799     if (elf->elf_class == ELFCLASS ## B) { \
800     Elf ## B ## _Dyn *dyn; \
801     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
802     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
803     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
804 vapier 1.44 Elf ## B ## _Off offset; \
805 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
806     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
807 vapier 1.44 offset = EGET(phdr[i].p_offset); \
808     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
809     dyn = DYN ## B (elf->data + offset); \
810 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
811     if (EGET(dyn->d_tag) == DT_NEEDED) { \
812 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
813 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
814 vapier 1.49 ++dyn; \
815     continue; \
816     } \
817 vapier 1.44 needed = (char*)(elf->data + offset); \
818 vapier 1.72 if (op == 0) { \
819 solar 1.127 if (!be_wewy_wewy_quiet) { \
820 vapier 1.72 if (*found_needed) xchrcat(ret, ',', ret_len); \
821 vapier 1.102 if (use_ldcache) \
822 vapier 1.97 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
823 solar 1.96 needed = p; \
824 vapier 1.72 xstrcat(ret, needed, ret_len); \
825     } \
826     *found_needed = 1; \
827     } else { \
828 solar 1.86 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
829 vapier 1.81 *found_lib = 1; \
830 solar 1.127 return (be_wewy_wewy_quiet ? NULL : needed); \
831 vapier 1.81 } \
832 vapier 1.72 } \
833 vapier 1.32 } \
834     ++dyn; \
835     } \
836     } }
837     SHOW_NEEDED(32)
838     SHOW_NEEDED(64)
839 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
840 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
841 vapier 1.32 }
842 vapier 1.72
843     return NULL;
844 vapier 1.39 }
845 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
846 vapier 1.39 {
847     void *strtbl_void;
848    
849 vapier 1.41 if (!show_interp) return NULL;
850 vapier 1.32
851 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
852 vapier 1.38
853 vapier 1.39 if (strtbl_void) {
854 vapier 1.38 #define SHOW_INTERP(B) \
855     if (elf->elf_class == ELFCLASS ## B) { \
856 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
857     *found_interp = 1; \
858 solar 1.127 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
859 vapier 1.38 }
860     SHOW_INTERP(32)
861     SHOW_INTERP(64)
862     }
863 vapier 1.41 return NULL;
864 vapier 1.39 }
865 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
866     {
867     unsigned long i;
868     struct stat s;
869 solar 1.131 char dynamic = 0;
870 vapier 1.49
871     if (!show_bind) return NULL;
872 vapier 1.51 if (!elf->phdr) return NULL;
873 vapier 1.49
874     #define SHOW_BIND(B) \
875     if (elf->elf_class == ELFCLASS ## B) { \
876     Elf ## B ## _Dyn *dyn; \
877     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
878     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
879     Elf ## B ## _Off offset; \
880     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
881     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
882 solar 1.131 dynamic = 1; \
883 vapier 1.49 offset = EGET(phdr[i].p_offset); \
884     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
885     dyn = DYN ## B (elf->data + offset); \
886     while (EGET(dyn->d_tag) != DT_NULL) { \
887     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
888     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
889     { \
890     if (be_quiet) return NULL; \
891     *found_bind = 1; \
892 solar 1.127 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
893 vapier 1.49 } \
894     ++dyn; \
895     } \
896     } \
897     }
898     SHOW_BIND(32)
899     SHOW_BIND(64)
900    
901 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
902 vapier 1.70
903 vapier 1.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 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
958 vapier 1.39 {
959 vapier 1.44 unsigned long i;
960 vapier 1.95 char *ret;
961 vapier 1.39 void *symtab_void, *strtab_void;
962 vapier 1.38
963 vapier 1.41 if (!find_sym) return NULL;
964 vapier 1.95 ret = find_sym;
965 vapier 1.32
966 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
967 vapier 1.27
968 vapier 1.39 if (symtab_void && strtab_void) {
969 vapier 1.27 #define FIND_SYM(B) \
970     if (elf->elf_class == ELFCLASS ## B) { \
971     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
972     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
973     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
974 vapier 1.115 unsigned long cnt = EGET(symtab->sh_entsize); \
975 vapier 1.27 char *symname; \
976 vapier 1.115 if (cnt) \
977     cnt = EGET(symtab->sh_size) / cnt; \
978 vapier 1.27 for (i = 0; i < cnt; ++i) { \
979     if (sym->st_name) { \
980 vapier 1.134 /* make sure the symbol name is in acceptable memory range */ \
981 vapier 1.27 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
982 vapier 1.115 if ((void*)symname > (void*)elf->data_end) { \
983     warnf("%s: corrupt ELF symbols", elf->filename); \
984 vapier 1.134 ++sym; \
985 vapier 1.111 continue; \
986     } \
987 vapier 1.134 /* debug display ... show all symbols and some extra info */ \
988 solar 1.174 if (gmatch ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
989 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
990 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
991 vapier 1.76 elf->base_filename, \
992 vapier 1.94 (unsigned long)sym->st_size, \
993 vapier 1.95 get_elfstttype(sym->st_info), \
994 vapier 1.32 symname); \
995 vapier 1.39 *found_sym = 1; \
996 vapier 1.95 } else { \
997 vapier 1.134 /* allow the user to specify a comma delimited list of symbols to search for */ \
998 vapier 1.156 char *this_sym, *this_sym_ver, *next_sym; \
999 vapier 1.134 this_sym = ret; \
1000 vapier 1.156 this_sym_ver = versioned_symname; \
1001 vapier 1.95 do { \
1002     next_sym = strchr(this_sym, ','); \
1003     if (next_sym == NULL) \
1004     next_sym = this_sym + strlen(this_sym); \
1005 vapier 1.134 /* do we want a defined symbol ? */ \
1006     if (*this_sym == '+') { \
1007 vapier 1.140 if (sym->st_shndx == SHN_UNDEF) \
1008 vapier 1.134 goto skip_this_sym##B; \
1009     ++this_sym; \
1010 vapier 1.156 ++this_sym_ver; \
1011 vapier 1.134 /* do we want an undefined symbol ? */ \
1012     } else if (*this_sym == '-') { \
1013 vapier 1.140 if (sym->st_shndx != SHN_UNDEF) \
1014 vapier 1.134 goto skip_this_sym##B; \
1015     ++this_sym; \
1016 vapier 1.156 ++this_sym_ver; \
1017 vapier 1.134 } \
1018     /* ok, lets compare the name now */ \
1019 vapier 1.95 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
1020 vapier 1.156 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
1021 solar 1.132 if (be_semi_verbose) { \
1022     char buf[126]; \
1023     snprintf(buf, sizeof(buf), "%lX %s %s", \
1024     (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1025     ret = buf; \
1026     } else \
1027     ret = this_sym; \
1028 vapier 1.95 (*found_sym)++; \
1029     goto break_out; \
1030     } \
1031 vapier 1.134 skip_this_sym##B: this_sym = next_sym + 1; \
1032 vapier 1.95 } while (*next_sym != '\0'); \
1033     } \
1034 vapier 1.27 } \
1035     ++sym; \
1036     } }
1037     FIND_SYM(32)
1038     FIND_SYM(64)
1039 vapier 1.39 }
1040 vapier 1.70
1041 vapier 1.95 break_out:
1042 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
1043 vapier 1.70
1044 vapier 1.41 if (*find_sym != '*' && *found_sym)
1045 vapier 1.95 return ret;
1046 vapier 1.41 if (be_quiet)
1047     return NULL;
1048     else
1049 solar 1.68 return (char *)" - ";
1050 vapier 1.39 }
1051 solar 1.119
1052    
1053 solar 1.124 static char *scanelf_file_sections(elfobj *elf, char *found_section)
1054     {
1055     if (!find_section)
1056     return NULL;
1057    
1058     #define FIND_SECTION(B) \
1059     if (elf->elf_class == ELFCLASS ## B) { \
1060 solar 1.136 int invert; \
1061 solar 1.124 Elf ## B ## _Shdr *section; \
1062 solar 1.136 invert = (*find_section == '!' ? 1 : 0); \
1063     section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1064     if ((section == NULL && invert) || (section != NULL && !invert)) \
1065 solar 1.124 *found_section = 1; \
1066     }
1067     FIND_SECTION(32)
1068     FIND_SECTION(64)
1069    
1070 vapier 1.138 if (be_wewy_wewy_quiet)
1071     return NULL;
1072 solar 1.124
1073     if (*found_section)
1074     return find_section;
1075    
1076     if (be_quiet)
1077     return NULL;
1078     else
1079     return (char *)" - ";
1080     }
1081    
1082 vapier 1.39 /* scan an elf file and show all the fun stuff */
1083 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
1084 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
1085 vapier 1.39 {
1086 vapier 1.44 unsigned long i;
1087 vapier 1.162 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1088     found_rpath, found_needed, found_interp, found_bind, found_soname,
1089 solar 1.124 found_sym, found_lib, found_file, found_textrels, found_section;
1090 vapier 1.41 static char *out_buffer = NULL;
1091     static size_t out_len;
1092 vapier 1.39
1093 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1094 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1095 solar 1.124 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1096 vapier 1.39
1097 vapier 1.114 if (be_verbose > 2)
1098 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
1099 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
1100     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1101 vapier 1.114 else if (be_verbose > 1)
1102 vapier 1.106 printf("%s: scanning file\n", elf->filename);
1103 vapier 1.39
1104 vapier 1.41 /* init output buffer */
1105     if (!out_buffer) {
1106     out_len = sizeof(char) * 80;
1107     out_buffer = (char*)xmalloc(out_len);
1108     }
1109     *out_buffer = '\0';
1110    
1111 vapier 1.39 /* show the header */
1112     if (!be_quiet && show_banner) {
1113 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1114 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1115 vapier 1.41
1116     switch (out_format[++i]) {
1117 solar 1.132 case '+': break;
1118 vapier 1.41 case '%': break;
1119 vapier 1.70 case '#': break;
1120 vapier 1.66 case 'F':
1121     case 'p':
1122     case 'f': prints("FILE "); found_file = 1; break;
1123 vapier 1.41 case 'o': prints(" TYPE "); break;
1124     case 'x': prints(" PAX "); break;
1125 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
1126 vapier 1.41 case 't': prints("TEXTREL "); break;
1127     case 'r': prints("RPATH "); break;
1128 vapier 1.171 case 'M': prints("CLASS "); break;
1129 vapier 1.41 case 'n': prints("NEEDED "); break;
1130     case 'i': prints("INTERP "); break;
1131 vapier 1.49 case 'b': prints("BIND "); break;
1132 vapier 1.84 case 'S': prints("SONAME "); break;
1133 vapier 1.41 case 's': prints("SYM "); break;
1134 vapier 1.72 case 'N': prints("LIB "); break;
1135 vapier 1.76 case 'T': prints("TEXTRELS "); break;
1136 vapier 1.126 case 'k': prints("SECTION "); break;
1137 vapier 1.166 case 'a': prints("ARCH "); break;
1138 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
1139 vapier 1.39 }
1140 vapier 1.27 }
1141 vapier 1.49 if (!found_file) prints("FILE ");
1142 vapier 1.41 prints("\n");
1143 vapier 1.49 found_file = 0;
1144 vapier 1.39 show_banner = 0;
1145     }
1146    
1147     /* dump all the good stuff */
1148 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1149 vapier 1.41 const char *out;
1150 vapier 1.66 const char *tmp;
1151 vapier 1.41
1152 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
1153 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
1154     continue;
1155     }
1156 vapier 1.39
1157 vapier 1.41 out = NULL;
1158 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
1159 solar 1.132 be_semi_verbose = (out_format[i] == '+');
1160 vapier 1.41 switch (out_format[++i]) {
1161 solar 1.132 case '+':
1162 vapier 1.70 case '%':
1163     case '#':
1164     xchrcat(&out_buffer, out_format[i], &out_len); break;
1165     case 'F':
1166 vapier 1.76 found_file = 1;
1167 solar 1.127 if (be_wewy_wewy_quiet) break;
1168 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1169 vapier 1.70 break;
1170 vapier 1.66 case 'p':
1171 vapier 1.76 found_file = 1;
1172 solar 1.127 if (be_wewy_wewy_quiet) break;
1173 vapier 1.106 tmp = elf->filename;
1174 vapier 1.66 if (search_path) {
1175     ssize_t len_search = strlen(search_path);
1176 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1177     if (!strncmp(elf->filename, search_path, len_search) && \
1178 vapier 1.66 len_file > len_search)
1179     tmp += len_search;
1180     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1181     }
1182     xstrcat(&out_buffer, tmp, &out_len);
1183     break;
1184     case 'f':
1185 vapier 1.76 found_file = 1;
1186 solar 1.127 if (be_wewy_wewy_quiet) break;
1187 vapier 1.106 tmp = strrchr(elf->filename, '/');
1188     tmp = (tmp == NULL ? elf->filename : tmp+1);
1189 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1190     break;
1191 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1192     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1193 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1194 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1195 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1196 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1197 vapier 1.171 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1198 vapier 1.72 case 'n':
1199     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1200 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1201 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1202 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1203 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1204 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1205 vapier 1.166 case 'a': out = get_elfemtype(elf); break;
1206 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1207 vapier 1.29 }
1208 vapier 1.95 if (out) {
1209     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1210     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1211     xstrncat(&out_buffer, out, &out_len, (tmp-out));
1212     else
1213     xstrcat(&out_buffer, out, &out_len);
1214     }
1215 vapier 1.39 }
1216    
1217 vapier 1.54 #define FOUND_SOMETHING() \
1218 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1219 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1220 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1221 vapier 1.54
1222     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1223     xchrcat(&out_buffer, ' ', &out_len);
1224 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1225 vapier 1.27 }
1226 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1227 vapier 1.41 puts(out_buffer);
1228 vapier 1.79 fflush(stdout);
1229     }
1230 vapier 1.10
1231 vapier 1.105 return 0;
1232     }
1233    
1234 vapier 1.106 /* scan a single elf */
1235     static int scanelf_elf(const char *filename, int fd, size_t len)
1236     {
1237 solar 1.120 int ret = 1;
1238 vapier 1.106 elfobj *elf;
1239    
1240     /* verify this is real ELF */
1241     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1242     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1243 solar 1.120 return ret;
1244     }
1245     switch (match_bits) {
1246     case 32:
1247     if (elf->elf_class != ELFCLASS32)
1248     goto label_done;
1249     break;
1250     case 64:
1251     if (elf->elf_class != ELFCLASS64)
1252     goto label_done;
1253     break;
1254     default: break;
1255 vapier 1.106 }
1256 solar 1.119 if (strlen(match_etypes)) {
1257     char sbuf[126];
1258     strncpy(sbuf, match_etypes, sizeof(sbuf));
1259     if (strchr(match_etypes, ',') != NULL) {
1260     char *p;
1261     while((p = strrchr(sbuf, ',')) != NULL) {
1262     *p = 0;
1263 solar 1.129 if (etype_lookup(p+1) == get_etype(elf))
1264 solar 1.119 goto label_ret;
1265     }
1266     }
1267 solar 1.129 if (etype_lookup(sbuf) != get_etype(elf))
1268 solar 1.119 goto label_done;
1269     }
1270    
1271     label_ret:
1272 vapier 1.106 ret = scanelf_elfobj(elf);
1273 solar 1.119
1274     label_done:
1275 vapier 1.106 unreadelf(elf);
1276     return ret;
1277     }
1278 solar 1.119
1279 vapier 1.105 /* scan an archive of elfs */
1280 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1281 vapier 1.105 {
1282 vapier 1.106 archive_handle *ar;
1283 vapier 1.105 archive_member *m;
1284 vapier 1.106 char *ar_buffer;
1285     elfobj *elf;
1286    
1287     ar = ar_open_fd(filename, fd);
1288     if (ar == NULL)
1289     return 1;
1290    
1291     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1292     while ((m=ar_next(ar)) != NULL) {
1293     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1294     if (elf) {
1295     scanelf_elfobj(elf);
1296     unreadelf(elf);
1297     }
1298     }
1299     munmap(ar_buffer, len);
1300    
1301 vapier 1.105 return 0;
1302     }
1303     /* scan a file which may be an elf or an archive or some other magical beast */
1304 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache)
1305 vapier 1.105 {
1306 vapier 1.161 const struct stat *st = st_cache;
1307     struct stat symlink_st;
1308 vapier 1.106 int fd;
1309 vapier 1.105
1310     /* always handle regular files and handle symlinked files if no -y */
1311 vapier 1.161 if (S_ISLNK(st->st_mode)) {
1312 solar 1.164 if (!scan_symlink) return 1;
1313 vapier 1.161 stat(filename, &symlink_st);
1314     st = &symlink_st;
1315 vapier 1.105 }
1316 vapier 1.161
1317     if (!S_ISREG(st->st_mode)) {
1318 vapier 1.105 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1319 solar 1.164 return 1;
1320 vapier 1.105 }
1321    
1322 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1323 solar 1.164 return 1;
1324 vapier 1.106
1325 vapier 1.161 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1326 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1327 vapier 1.161 scanelf_archive(filename, fd, st->st_size);
1328 vapier 1.106
1329     close(fd);
1330 solar 1.164 return 0;
1331 solar 1.6 }
1332    
1333 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1334 solar 1.164 static int scanelf_dir(const char *path)
1335 solar 1.1 {
1336 vapier 1.10 register DIR *dir;
1337     register struct dirent *dentry;
1338 vapier 1.14 struct stat st_top, st;
1339 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1340 vapier 1.32 size_t pathlen = 0, len = 0;
1341 solar 1.164 int ret = 0;
1342 vapier 1.10
1343     /* make sure path exists */
1344 vapier 1.39 if (lstat(path, &st_top) == -1) {
1345     if (be_verbose > 2) printf("%s: does not exist\n", path);
1346 solar 1.164 return 1;
1347 vapier 1.39 }
1348 solar 1.11
1349 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1350 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1351 solar 1.164 return scanelf_file(path, &st_top);
1352 vapier 1.10 }
1353    
1354     /* now scan the dir looking for fun stuff */
1355     if ((dir = opendir(path)) == NULL) {
1356     warnf("could not opendir %s: %s", path, strerror(errno));
1357 solar 1.164 return 1;
1358 vapier 1.10 }
1359 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1360 solar 1.11
1361 vapier 1.32 pathlen = strlen(path);
1362 vapier 1.10 while ((dentry = readdir(dir))) {
1363     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1364     continue;
1365 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1366     if (len >= sizeof(buf)) {
1367 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1368     (unsigned long)len, (unsigned long)sizeof(buf));
1369 vapier 1.32 continue;
1370     }
1371 solar 1.143 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1372 solar 1.20 if (lstat(buf, &st) != -1) {
1373 vapier 1.10 if (S_ISREG(st.st_mode))
1374 solar 1.164 ret = scanelf_file(buf, &st);
1375 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1376 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1377 solar 1.164 ret = scanelf_dir(buf);
1378 vapier 1.10 }
1379     }
1380     }
1381     closedir(dir);
1382 solar 1.164 return ret;
1383 solar 1.1 }
1384    
1385 vapier 1.133 static int scanelf_from_file(const char *filename)
1386 vapier 1.47 {
1387 solar 1.45 FILE *fp = NULL;
1388     char *p;
1389 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1390 solar 1.164 int ret = 0;
1391 solar 1.45
1392 solar 1.132 if (strcmp(filename, "-") == 0)
1393 solar 1.45 fp = stdin;
1394     else if ((fp = fopen(filename, "r")) == NULL)
1395     return 1;
1396    
1397 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1398 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1399     *p = 0;
1400 vapier 1.66 search_path = path;
1401 solar 1.164 ret = scanelf_dir(path);
1402 solar 1.45 }
1403     if (fp != stdin)
1404     fclose(fp);
1405 solar 1.164 return ret;
1406 solar 1.45 }
1407    
1408 solar 1.154 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1409 vapier 1.148
1410     static int load_ld_cache_config(int i, const char *fname)
1411 vapier 1.48 {
1412     FILE *fp = NULL;
1413     char *p;
1414 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1415 vapier 1.48
1416 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1417 solar 1.123 return i;
1418    
1419     if ((fp = fopen(fname, "r")) == NULL)
1420     return i;
1421 vapier 1.48
1422 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1423 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1424     *p = 0;
1425     if ((p = strchr(path, '\n')) != NULL)
1426     *p = 0;
1427 solar 1.154 #ifdef __linux__
1428 solar 1.123 // recursive includes of the same file will make this segfault.
1429 solar 1.129 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1430 solar 1.123 glob64_t gl;
1431     size_t x;
1432     char gpath[__PAX_UTILS_PATH_MAX];
1433    
1434 solar 1.129 memset(gpath, 0, sizeof(gpath));
1435 solar 1.123
1436     if (path[8] != '/')
1437 solar 1.129 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1438 solar 1.123 else
1439 solar 1.129 strncpy(gpath, &path[8], sizeof(gpath));
1440 solar 1.123
1441     if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1442     for (x = 0; x < gl.gl_pathc; ++x) {
1443     /* try to avoid direct loops */
1444     if (strcmp(gl.gl_pathv[x], fname) == 0)
1445     continue;
1446 vapier 1.148 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1447 vapier 1.149 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1448 solar 1.123 globfree64(&gl);
1449     return i;
1450     }
1451     }
1452     globfree64 (&gl);
1453     continue;
1454 solar 1.160 }
1455 solar 1.123 }
1456 solar 1.154 #endif
1457 solar 1.123 if (*path != '/')
1458     continue;
1459 vapier 1.48
1460     ldpaths[i++] = xstrdup(path);
1461    
1462 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1463 vapier 1.48 break;
1464     }
1465     ldpaths[i] = NULL;
1466    
1467     fclose(fp);
1468 solar 1.123 return i;
1469 vapier 1.48 }
1470 flameeyes 1.141
1471 vapier 1.148 #elif defined(__FreeBSD__) || (__DragonFly__)
1472    
1473     static int load_ld_cache_config(int i, const char *fname)
1474 flameeyes 1.141 {
1475     FILE *fp = NULL;
1476     char *b = NULL, *p;
1477     struct elfhints_hdr hdr;
1478 vapier 1.152
1479 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1480 flameeyes 1.141 return i;
1481    
1482     if ((fp = fopen(fname, "r")) == NULL)
1483     return i;
1484    
1485 vapier 1.152 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1486     hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1487     fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1488     {
1489 flameeyes 1.141 fclose(fp);
1490     return i;
1491     }
1492 vapier 1.152
1493 flameeyes 1.141 b = (char*)malloc(hdr.dirlistlen+1);
1494 vapier 1.152 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1495 flameeyes 1.141 fclose(fp);
1496     free(b);
1497     return i;
1498     }
1499 vapier 1.152
1500     while ((p = strsep(&b, ":"))) {
1501     if (*p == '\0') continue;
1502 flameeyes 1.141 ldpaths[i++] = xstrdup(p);
1503 vapier 1.152
1504 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1505 flameeyes 1.141 break;
1506     }
1507     ldpaths[i] = NULL;
1508 vapier 1.157
1509 flameeyes 1.141 free(b);
1510     fclose(fp);
1511     return i;
1512     }
1513 vapier 1.148
1514     #else
1515    
1516     #warning Cache config support not implemented for your target
1517     static int load_ld_cache_config(int i, const char *fname)
1518     {
1519     memset(ldpaths, 0x00, sizeof(ldpaths));
1520     }
1521    
1522 flameeyes 1.141 #endif
1523 vapier 1.48
1524 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1525     static void scanelf_ldpath()
1526     {
1527 vapier 1.17 char scan_l, scan_ul, scan_ull;
1528 vapier 1.48 int i = 0;
1529 vapier 1.10
1530 vapier 1.48 if (!ldpaths[0])
1531     err("Unable to load any paths from ld.so.conf");
1532 vapier 1.10
1533 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1534    
1535 vapier 1.48 while (ldpaths[i]) {
1536     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1537     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1538     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1539     scanelf_dir(ldpaths[i]);
1540     ++i;
1541     }
1542 vapier 1.10
1543 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1544     if (!scan_ul) scanelf_dir("/usr/lib");
1545     if (!scan_ull) scanelf_dir("/usr/local/lib");
1546 vapier 1.10 }
1547 solar 1.1
1548 vapier 1.10 /* scan env PATH for paths */
1549     static void scanelf_envpath()
1550 solar 1.1 {
1551 solar 1.34 char *path, *p;
1552 vapier 1.10
1553     path = getenv("PATH");
1554     if (!path)
1555     err("PATH is not set in your env !");
1556 vapier 1.41 path = xstrdup(path);
1557 vapier 1.10
1558     while ((p = strrchr(path, ':')) != NULL) {
1559     scanelf_dir(p + 1);
1560     *p = 0;
1561     }
1562 vapier 1.17
1563 solar 1.34 free(path);
1564 solar 1.1 }
1565    
1566 vapier 1.10 /* usage / invocation handling functions */
1567 solar 1.127 #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1568 vapier 1.27 #define a_argument required_argument
1569 vapier 1.10 static struct option const long_opts[] = {
1570     {"path", no_argument, NULL, 'p'},
1571     {"ldpath", no_argument, NULL, 'l'},
1572     {"recursive", no_argument, NULL, 'R'},
1573 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1574 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1575 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1576     {"ldcache", no_argument, NULL, 'L'},
1577 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1578 solar 1.127 {"setpax", a_argument, NULL, 'z'},
1579 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1580 solar 1.16 {"header", no_argument, NULL, 'e'},
1581 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1582     {"rpath", no_argument, NULL, 'r'},
1583 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1584 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1585 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1586 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1587 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1588 solar 1.124 {"section", a_argument, NULL, 'k'},
1589 vapier 1.76 {"lib", a_argument, NULL, 'N'},
1590 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1591 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1592 solar 1.119 {"etype", a_argument, NULL, 'E'},
1593 solar 1.120 {"bits", a_argument, NULL, 'M'},
1594 vapier 1.10 {"all", no_argument, NULL, 'a'},
1595     {"quiet", no_argument, NULL, 'q'},
1596 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1597 vapier 1.76 {"format", a_argument, NULL, 'F'},
1598     {"from", a_argument, NULL, 'f'},
1599     {"file", a_argument, NULL, 'o'},
1600 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1601 vapier 1.10 {"help", no_argument, NULL, 'h'},
1602     {"version", no_argument, NULL, 'V'},
1603     {NULL, no_argument, NULL, 0x0}
1604     };
1605 solar 1.57
1606 solar 1.68 static const char *opts_help[] = {
1607 vapier 1.10 "Scan all directories in PATH environment",
1608     "Scan all directories in /etc/ld.so.conf",
1609 vapier 1.14 "Scan directories recursively",
1610 vapier 1.37 "Don't recursively cross mount points",
1611 vapier 1.101 "Don't scan symlinks",
1612 vapier 1.105 "Scan archives (.a files)",
1613     "Utilize ld.so.cache information (use with -r/-n)",
1614 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
1615     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1616 vapier 1.10 "Print PaX markings",
1617 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1618 vapier 1.10 "Print TEXTREL information",
1619     "Print RPATH information",
1620 vapier 1.32 "Print NEEDED information",
1621 vapier 1.38 "Print INTERP information",
1622 vapier 1.49 "Print BIND information",
1623 vapier 1.84 "Print SONAME information",
1624 vapier 1.27 "Find a specified symbol",
1625 solar 1.124 "Find a specified section",
1626 vapier 1.72 "Find a specified library",
1627 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1628 vapier 1.76 "Locate cause of TEXTREL",
1629 solar 1.129 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1630 solar 1.120 "Print only ELF files matching numeric bits",
1631 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1632 vapier 1.14 "Only output 'bad' things",
1633     "Be verbose (can be specified more than once)",
1634 vapier 1.39 "Use specified format for output",
1635 solar 1.45 "Read input stream from a filename",
1636 vapier 1.24 "Write output stream to a filename",
1637 vapier 1.14 "Don't display the header",
1638 vapier 1.10 "Print this help and exit",
1639     "Print version and exit",
1640     NULL
1641     };
1642    
1643     /* display usage and exit */
1644     static void usage(int status)
1645 solar 1.1 {
1646 vapier 1.44 unsigned long i;
1647 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1648 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1649 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1650 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1651 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1652 vapier 1.157 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1653 vapier 1.27 long_opts[i].name, opts_help[i]);
1654     else
1655 solar 1.124 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1656 vapier 1.27 long_opts[i].name, opts_help[i]);
1657 solar 1.45
1658 vapier 1.173 puts("\nFor more information, see the scanelf(1) manpage");
1659 vapier 1.10 exit(status);
1660 solar 1.1 }
1661    
1662     /* parse command line arguments and preform needed actions */
1663 vapier 1.165 #define do_pax_state(option, flag) \
1664     if (islower(option)) { \
1665     flags &= ~PF_##flag; \
1666     flags |= PF_NO##flag; \
1667     } else { \
1668     flags &= ~PF_NO##flag; \
1669     flags |= PF_##flag; \
1670     }
1671 solar 1.164 static int parseargs(int argc, char *argv[])
1672 vapier 1.10 {
1673 vapier 1.48 int i;
1674 vapier 1.133 const char *from_file = NULL;
1675 solar 1.164 int ret = 0;
1676 vapier 1.10
1677     opterr = 0;
1678 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1679     switch (i) {
1680 vapier 1.10
1681 vapier 1.39 case 'V':
1682 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1683     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1684     VERSION, __FILE__, __DATE__, rcsid, argv0);
1685 vapier 1.10 exit(EXIT_SUCCESS);
1686     break;
1687     case 'h': usage(EXIT_SUCCESS); break;
1688 solar 1.45 case 'f':
1689 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1690     from_file = optarg;
1691 solar 1.45 break;
1692 solar 1.119 case 'E':
1693     strncpy(match_etypes, optarg, sizeof(match_etypes));
1694     break;
1695 solar 1.120 case 'M':
1696     match_bits = atoi(optarg);
1697     break;
1698 vapier 1.24 case 'o': {
1699 vapier 1.146 if (freopen(optarg, "w", stdout) == NULL)
1700 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1701 solar 1.21 break;
1702     }
1703 solar 1.124 case 'k':
1704 vapier 1.126 if (find_section) warn("You prob don't want to specify -k twice");
1705 solar 1.124 find_section = optarg;
1706     break;
1707 vapier 1.39 case 's': {
1708 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1709     find_sym = optarg;
1710     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1711 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1712     break;
1713     }
1714 vapier 1.72 case 'N': {
1715 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1716     find_lib = optarg;
1717 vapier 1.72 break;
1718     }
1719 vapier 1.39
1720     case 'F': {
1721 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1722     out_format = optarg;
1723 vapier 1.39 break;
1724     }
1725 solar 1.127 case 'z': {
1726 solar 1.129 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1727 solar 1.127 size_t x;
1728 vapier 1.27
1729 solar 1.127 for (x = 0 ; x < strlen(optarg); x++) {
1730     switch(optarg[x]) {
1731     case 'p':
1732     case 'P':
1733 vapier 1.165 do_pax_state(optarg[x], PAGEEXEC);
1734 solar 1.127 break;
1735     case 's':
1736     case 'S':
1737 vapier 1.165 do_pax_state(optarg[x], SEGMEXEC);
1738 solar 1.127 break;
1739     case 'm':
1740     case 'M':
1741 vapier 1.165 do_pax_state(optarg[x], MPROTECT);
1742 solar 1.127 break;
1743     case 'e':
1744     case 'E':
1745 vapier 1.165 do_pax_state(optarg[x], EMUTRAMP);
1746 solar 1.127 break;
1747     case 'r':
1748     case 'R':
1749 vapier 1.165 do_pax_state(optarg[x], RANDMMAP);
1750 solar 1.127 break;
1751     case 'x':
1752     case 'X':
1753 vapier 1.165 do_pax_state(optarg[x], RANDEXEC);
1754 solar 1.127 break;
1755     default:
1756     break;
1757     }
1758     }
1759     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1760     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1761     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1762     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1763     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1764     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1765     setpax = flags;
1766     break;
1767     }
1768 vapier 1.122 case 'g': gmatch = 1; break;
1769 vapier 1.102 case 'L': use_ldcache = 1; break;
1770 vapier 1.37 case 'y': scan_symlink = 0; break;
1771 vapier 1.105 case 'A': scan_archives = 1; break;
1772 solar 1.16 case 'B': show_banner = 0; break;
1773 vapier 1.10 case 'l': scan_ldpath = 1; break;
1774     case 'p': scan_envpath = 1; break;
1775     case 'R': dir_recurse = 1; break;
1776 vapier 1.14 case 'm': dir_crossmount = 0; break;
1777 vapier 1.101 case 'X': ++fix_elf; break;
1778 vapier 1.10 case 'x': show_pax = 1; break;
1779 solar 1.73 case 'e': show_phdr = 1; break;
1780 vapier 1.10 case 't': show_textrel = 1; break;
1781     case 'r': show_rpath = 1; break;
1782 vapier 1.32 case 'n': show_needed = 1; break;
1783 vapier 1.38 case 'i': show_interp = 1; break;
1784 vapier 1.49 case 'b': show_bind = 1; break;
1785 vapier 1.84 case 'S': show_soname = 1; break;
1786 vapier 1.76 case 'T': show_textrels = 1; break;
1787 vapier 1.10 case 'q': be_quiet = 1; break;
1788 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1789 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1790 vapier 1.10
1791     case ':':
1792 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1793 vapier 1.10 case '?':
1794 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1795 vapier 1.10 default:
1796 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1797 vapier 1.10 }
1798     }
1799 solar 1.170 if (show_textrels && be_verbose) {
1800     if (which("objdump") != NULL)
1801     has_objdump = 1;
1802     }
1803 vapier 1.39 /* let the format option override all other options */
1804     if (out_format) {
1805 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1806 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1807     show_textrels = 0;
1808 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1809 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1810 vapier 1.39
1811 vapier 1.48 switch (out_format[++i]) {
1812 solar 1.132 case '+': break;
1813 vapier 1.39 case '%': break;
1814 vapier 1.70 case '#': break;
1815 vapier 1.39 case 'F': break;
1816 vapier 1.66 case 'p': break;
1817     case 'f': break;
1818 solar 1.124 case 'k': break;
1819 vapier 1.39 case 's': break;
1820 vapier 1.72 case 'N': break;
1821 vapier 1.41 case 'o': break;
1822 vapier 1.166 case 'a': break;
1823 vapier 1.171 case 'M': break;
1824 vapier 1.39 case 'x': show_pax = 1; break;
1825 solar 1.73 case 'e': show_phdr = 1; break;
1826 vapier 1.39 case 't': show_textrel = 1; break;
1827     case 'r': show_rpath = 1; break;
1828     case 'n': show_needed = 1; break;
1829     case 'i': show_interp = 1; break;
1830 vapier 1.49 case 'b': show_bind = 1; break;
1831 vapier 1.84 case 'S': show_soname = 1; break;
1832 vapier 1.76 case 'T': show_textrels = 1; break;
1833 vapier 1.39 default:
1834 vapier 1.162 err("Invalid format specifier '%c' (byte %i)",
1835 vapier 1.48 out_format[i], i+1);
1836 vapier 1.39 }
1837     }
1838 vapier 1.41
1839     /* construct our default format */
1840     } else {
1841     size_t fmt_len = 30;
1842     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1843 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1844     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1845     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1846     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1847     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1848     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1849     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1850     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1851 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1852 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1853     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1854 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1855 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1856     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1857 vapier 1.39 }
1858 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1859 vapier 1.39
1860     /* now lets actually do the scanning */
1861 vapier 1.102 if (scan_ldpath || use_ldcache)
1862 vapier 1.148 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1863 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1864     if (scan_envpath) scanelf_envpath();
1865 solar 1.153 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1866 vapier 1.133 from_file = "-";
1867 solar 1.45 if (from_file) {
1868     scanelf_from_file(from_file);
1869     from_file = *argv;
1870     }
1871     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1872 vapier 1.25 err("Nothing to scan !?");
1873 vapier 1.66 while (optind < argc) {
1874     search_path = argv[optind++];
1875 solar 1.164 ret = scanelf_dir(search_path);
1876 vapier 1.66 }
1877 vapier 1.27
1878 vapier 1.39 /* clean up */
1879 vapier 1.152 free(versioned_symname);
1880 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1881     free(ldpaths[i]);
1882 solar 1.96
1883     if (ldcache != 0)
1884     munmap(ldcache, ldcache_size);
1885 solar 1.164 return ret;
1886 vapier 1.10 }
1887    
1888 vapier 1.150 static char **get_split_env(const char *envvar)
1889     {
1890 vapier 1.152 const char *delims = " \t\n";
1891 solar 1.143 char **envvals = NULL;
1892 vapier 1.152 char *env, *s;
1893 kevquinn 1.142 int nentry;
1894    
1895 solar 1.143 if ((env = getenv(envvar)) == NULL)
1896     return NULL;
1897 kevquinn 1.142
1898 solar 1.143 env = xstrdup(env);
1899     if (env == NULL)
1900     return NULL;
1901 kevquinn 1.142
1902 vapier 1.152 s = strtok(env, delims);
1903     if (s == NULL) {
1904     free(env);
1905     return NULL;
1906     }
1907    
1908 solar 1.143 nentry = 0;
1909 vapier 1.152 while (s != NULL) {
1910     ++nentry;
1911     envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1912     envvals[nentry-1] = s;
1913     s = strtok(NULL, delims);
1914 kevquinn 1.142 }
1915 vapier 1.152 envvals[nentry] = NULL;
1916 kevquinn 1.142
1917 vapier 1.152 /* don't want to free(env) as it contains the memory that backs
1918     * the envvals array of strings */
1919 kevquinn 1.142 return envvals;
1920     }
1921 vapier 1.150 static void parseenv()
1922     {
1923     qa_textrels = get_split_env("QA_TEXTRELS");
1924     qa_execstack = get_split_env("QA_EXECSTACK");
1925     qa_wx_load = get_split_env("QA_WX_LOAD");
1926 vapier 1.41 }
1927 solar 1.163
1928 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1929     static void cleanup()
1930     {
1931     free(out_format);
1932     free(qa_textrels);
1933     free(qa_execstack);
1934     free(qa_wx_load);
1935     }
1936     #endif
1937 vapier 1.41
1938    
1939 vapier 1.10 int main(int argc, char *argv[])
1940 solar 1.1 {
1941 solar 1.164 int ret;
1942 vapier 1.10 if (argc < 2)
1943     usage(EXIT_FAILURE);
1944 kevquinn 1.142 parseenv();
1945 solar 1.164 ret = parseargs(argc, argv);
1946 solar 1.21 fclose(stdout);
1947 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1948     cleanup();
1949     warn("The calls to add/delete heap should be off:\n"
1950     "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1951     "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1952 solar 1.61 #endif
1953 solar 1.164 return ret;
1954 solar 1.1 }
1955 vapier 1.155
1956    
1957    
1958     /* utility funcs */
1959     static char *xstrdup(const char *s)
1960     {
1961     char *ret = strdup(s);
1962     if (!ret) err("Could not strdup(): %s", strerror(errno));
1963     return ret;
1964     }
1965     static void *xmalloc(size_t size)
1966     {
1967     void *ret = malloc(size);
1968     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1969     return ret;
1970     }
1971     static void *xrealloc(void *ptr, size_t size)
1972     {
1973     void *ret = realloc(ptr, size);
1974     if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
1975     return ret;
1976     }
1977     static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1978     {
1979     size_t new_len;
1980    
1981     new_len = strlen(*dst) + strlen(src);
1982     if (*curr_len <= new_len) {
1983     *curr_len = new_len + (*curr_len / 2);
1984     *dst = realloc(*dst, *curr_len);
1985     if (!*dst)
1986     err("could not realloc() %li bytes", (unsigned long)*curr_len);
1987     }
1988    
1989     if (n)
1990     strncat(*dst, src, n);
1991     else
1992     strcat(*dst, src);
1993     }
1994     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1995     {
1996     static char my_app[2];
1997     my_app[0] = append;
1998     my_app[1] = '\0';
1999     xstrcat(dst, my_app, curr_len);
2000     }
2001    
2002     /* Match filename against entries in matchlist, return TRUE
2003     * if the file is listed */
2004     static int file_matches_list(const char *filename, char **matchlist)
2005     {
2006     char **file;
2007     char *match;
2008     char buf[__PAX_UTILS_PATH_MAX];
2009    
2010     if (matchlist == NULL)
2011     return 0;
2012    
2013     for (file = matchlist; *file != NULL; file++) {
2014     if (search_path) {
2015     snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2016     match = buf;
2017     } else {
2018     match = *file;
2019     }
2020     if (fnmatch(match, filename, 0) == 0)
2021     return 1;
2022     }
2023     return 0;
2024     }

  ViewVC Help
Powered by ViewVC 1.1.20