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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.174 - (hide annotations) (download) (as text)
Thu Jan 18 08:12:55 2007 UTC (7 years, 6 months ago) by solar
Branch: MAIN
Changes since 1.173: +31 -4 lines
File MIME type: text/x-csrc
- added regexp symbol matching using existing gmatch option

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

  ViewVC Help
Powered by ViewVC 1.1.20