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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.171 - (hide annotations) (download) (as text)
Tue Jan 9 23:01:09 2007 UTC (7 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.170: +5 -2 lines
File MIME type: text/x-csrc
add support for %M to display ECLASS

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

  ViewVC Help
Powered by ViewVC 1.1.20