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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.170 - (hide annotations) (download) (as text)
Tue Jan 9 18:46:22 2007 UTC (8 years, 4 months ago) by solar
Branch: MAIN
Changes since 1.169: +32 -4 lines
File MIME type: text/x-csrc
- dont call objdump without first making sure it exists.

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.170 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.169 2007/01/09 00:23:13 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.170 static const char *rcsid = "$Id: scanelf.c,v 1.169 2007/01/09 00:23:13 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 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     case 'n': prints("NEEDED "); break;
1104     case 'i': prints("INTERP "); break;
1105 vapier 1.49 case 'b': prints("BIND "); break;
1106 vapier 1.84 case 'S': prints("SONAME "); break;
1107 vapier 1.41 case 's': prints("SYM "); break;
1108 vapier 1.72 case 'N': prints("LIB "); break;
1109 vapier 1.76 case 'T': prints("TEXTRELS "); break;
1110 vapier 1.126 case 'k': prints("SECTION "); break;
1111 vapier 1.166 case 'a': prints("ARCH "); break;
1112 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
1113 vapier 1.39 }
1114 vapier 1.27 }
1115 vapier 1.49 if (!found_file) prints("FILE ");
1116 vapier 1.41 prints("\n");
1117 vapier 1.49 found_file = 0;
1118 vapier 1.39 show_banner = 0;
1119     }
1120    
1121     /* dump all the good stuff */
1122 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1123 vapier 1.41 const char *out;
1124 vapier 1.66 const char *tmp;
1125 vapier 1.41
1126 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
1127 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
1128     continue;
1129     }
1130 vapier 1.39
1131 vapier 1.41 out = NULL;
1132 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
1133 solar 1.132 be_semi_verbose = (out_format[i] == '+');
1134 vapier 1.41 switch (out_format[++i]) {
1135 solar 1.132 case '+':
1136 vapier 1.70 case '%':
1137     case '#':
1138     xchrcat(&out_buffer, out_format[i], &out_len); break;
1139     case 'F':
1140 vapier 1.76 found_file = 1;
1141 solar 1.127 if (be_wewy_wewy_quiet) break;
1142 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1143 vapier 1.70 break;
1144 vapier 1.66 case 'p':
1145 vapier 1.76 found_file = 1;
1146 solar 1.127 if (be_wewy_wewy_quiet) break;
1147 vapier 1.106 tmp = elf->filename;
1148 vapier 1.66 if (search_path) {
1149     ssize_t len_search = strlen(search_path);
1150 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1151     if (!strncmp(elf->filename, search_path, len_search) && \
1152 vapier 1.66 len_file > len_search)
1153     tmp += len_search;
1154     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1155     }
1156     xstrcat(&out_buffer, tmp, &out_len);
1157     break;
1158     case 'f':
1159 vapier 1.76 found_file = 1;
1160 solar 1.127 if (be_wewy_wewy_quiet) break;
1161 vapier 1.106 tmp = strrchr(elf->filename, '/');
1162     tmp = (tmp == NULL ? elf->filename : tmp+1);
1163 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1164     break;
1165 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1166     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1167 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1168 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1169 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1170 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1171 vapier 1.72 case 'n':
1172     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1173 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1174 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1175 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1176 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1177 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1178 vapier 1.166 case 'a': out = get_elfemtype(elf); break;
1179 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1180 vapier 1.29 }
1181 vapier 1.95 if (out) {
1182     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1183     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1184     xstrncat(&out_buffer, out, &out_len, (tmp-out));
1185     else
1186     xstrcat(&out_buffer, out, &out_len);
1187     }
1188 vapier 1.39 }
1189    
1190 vapier 1.54 #define FOUND_SOMETHING() \
1191 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1192 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1193 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1194 vapier 1.54
1195     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1196     xchrcat(&out_buffer, ' ', &out_len);
1197 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1198 vapier 1.27 }
1199 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1200 vapier 1.41 puts(out_buffer);
1201 vapier 1.79 fflush(stdout);
1202     }
1203 vapier 1.10
1204 vapier 1.105 return 0;
1205     }
1206    
1207 vapier 1.106 /* scan a single elf */
1208     static int scanelf_elf(const char *filename, int fd, size_t len)
1209     {
1210 solar 1.120 int ret = 1;
1211 vapier 1.106 elfobj *elf;
1212    
1213     /* verify this is real ELF */
1214     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1215     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1216 solar 1.120 return ret;
1217     }
1218     switch (match_bits) {
1219     case 32:
1220     if (elf->elf_class != ELFCLASS32)
1221     goto label_done;
1222     break;
1223     case 64:
1224     if (elf->elf_class != ELFCLASS64)
1225     goto label_done;
1226     break;
1227     default: break;
1228 vapier 1.106 }
1229 solar 1.119 if (strlen(match_etypes)) {
1230     char sbuf[126];
1231     strncpy(sbuf, match_etypes, sizeof(sbuf));
1232     if (strchr(match_etypes, ',') != NULL) {
1233     char *p;
1234     while((p = strrchr(sbuf, ',')) != NULL) {
1235     *p = 0;
1236 solar 1.129 if (etype_lookup(p+1) == get_etype(elf))
1237 solar 1.119 goto label_ret;
1238     }
1239     }
1240 solar 1.129 if (etype_lookup(sbuf) != get_etype(elf))
1241 solar 1.119 goto label_done;
1242     }
1243    
1244     label_ret:
1245 vapier 1.106 ret = scanelf_elfobj(elf);
1246 solar 1.119
1247     label_done:
1248 vapier 1.106 unreadelf(elf);
1249     return ret;
1250     }
1251 solar 1.119
1252 vapier 1.105 /* scan an archive of elfs */
1253 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1254 vapier 1.105 {
1255 vapier 1.106 archive_handle *ar;
1256 vapier 1.105 archive_member *m;
1257 vapier 1.106 char *ar_buffer;
1258     elfobj *elf;
1259    
1260     ar = ar_open_fd(filename, fd);
1261     if (ar == NULL)
1262     return 1;
1263    
1264     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1265     while ((m=ar_next(ar)) != NULL) {
1266     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1267     if (elf) {
1268     scanelf_elfobj(elf);
1269     unreadelf(elf);
1270     }
1271     }
1272     munmap(ar_buffer, len);
1273    
1274 vapier 1.105 return 0;
1275     }
1276     /* scan a file which may be an elf or an archive or some other magical beast */
1277 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache)
1278 vapier 1.105 {
1279 vapier 1.161 const struct stat *st = st_cache;
1280     struct stat symlink_st;
1281 vapier 1.106 int fd;
1282 vapier 1.105
1283     /* always handle regular files and handle symlinked files if no -y */
1284 vapier 1.161 if (S_ISLNK(st->st_mode)) {
1285 solar 1.164 if (!scan_symlink) return 1;
1286 vapier 1.161 stat(filename, &symlink_st);
1287     st = &symlink_st;
1288 vapier 1.105 }
1289 vapier 1.161
1290     if (!S_ISREG(st->st_mode)) {
1291 vapier 1.105 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1292 solar 1.164 return 1;
1293 vapier 1.105 }
1294    
1295 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1296 solar 1.164 return 1;
1297 vapier 1.106
1298 vapier 1.161 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1299 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1300 vapier 1.161 scanelf_archive(filename, fd, st->st_size);
1301 vapier 1.106
1302     close(fd);
1303 solar 1.164 return 0;
1304 solar 1.6 }
1305    
1306 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1307 solar 1.164 static int scanelf_dir(const char *path)
1308 solar 1.1 {
1309 vapier 1.10 register DIR *dir;
1310     register struct dirent *dentry;
1311 vapier 1.14 struct stat st_top, st;
1312 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1313 vapier 1.32 size_t pathlen = 0, len = 0;
1314 solar 1.164 int ret = 0;
1315 vapier 1.10
1316     /* make sure path exists */
1317 vapier 1.39 if (lstat(path, &st_top) == -1) {
1318     if (be_verbose > 2) printf("%s: does not exist\n", path);
1319 solar 1.164 return 1;
1320 vapier 1.39 }
1321 solar 1.11
1322 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1323 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1324 solar 1.164 return scanelf_file(path, &st_top);
1325 vapier 1.10 }
1326    
1327     /* now scan the dir looking for fun stuff */
1328     if ((dir = opendir(path)) == NULL) {
1329     warnf("could not opendir %s: %s", path, strerror(errno));
1330 solar 1.164 return 1;
1331 vapier 1.10 }
1332 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1333 solar 1.11
1334 vapier 1.32 pathlen = strlen(path);
1335 vapier 1.10 while ((dentry = readdir(dir))) {
1336     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1337     continue;
1338 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1339     if (len >= sizeof(buf)) {
1340 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1341     (unsigned long)len, (unsigned long)sizeof(buf));
1342 vapier 1.32 continue;
1343     }
1344 solar 1.143 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1345 solar 1.20 if (lstat(buf, &st) != -1) {
1346 vapier 1.10 if (S_ISREG(st.st_mode))
1347 solar 1.164 ret = scanelf_file(buf, &st);
1348 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1349 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1350 solar 1.164 ret = scanelf_dir(buf);
1351 vapier 1.10 }
1352     }
1353     }
1354     closedir(dir);
1355 solar 1.164 return ret;
1356 solar 1.1 }
1357    
1358 vapier 1.133 static int scanelf_from_file(const char *filename)
1359 vapier 1.47 {
1360 solar 1.45 FILE *fp = NULL;
1361     char *p;
1362 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1363 solar 1.164 int ret = 0;
1364 solar 1.45
1365 solar 1.132 if (strcmp(filename, "-") == 0)
1366 solar 1.45 fp = stdin;
1367     else if ((fp = fopen(filename, "r")) == NULL)
1368     return 1;
1369    
1370 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1371 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1372     *p = 0;
1373 vapier 1.66 search_path = path;
1374 solar 1.164 ret = scanelf_dir(path);
1375 solar 1.45 }
1376     if (fp != stdin)
1377     fclose(fp);
1378 solar 1.164 return ret;
1379 solar 1.45 }
1380    
1381 solar 1.154 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1382 vapier 1.148
1383     static int load_ld_cache_config(int i, const char *fname)
1384 vapier 1.48 {
1385     FILE *fp = NULL;
1386     char *p;
1387 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1388 vapier 1.48
1389 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1390 solar 1.123 return i;
1391    
1392     if ((fp = fopen(fname, "r")) == NULL)
1393     return i;
1394 vapier 1.48
1395 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1396 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1397     *p = 0;
1398     if ((p = strchr(path, '\n')) != NULL)
1399     *p = 0;
1400 solar 1.154 #ifdef __linux__
1401 solar 1.123 // recursive includes of the same file will make this segfault.
1402 solar 1.129 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1403 solar 1.123 glob64_t gl;
1404     size_t x;
1405     char gpath[__PAX_UTILS_PATH_MAX];
1406    
1407 solar 1.129 memset(gpath, 0, sizeof(gpath));
1408 solar 1.123
1409     if (path[8] != '/')
1410 solar 1.129 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1411 solar 1.123 else
1412 solar 1.129 strncpy(gpath, &path[8], sizeof(gpath));
1413 solar 1.123
1414     if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1415     for (x = 0; x < gl.gl_pathc; ++x) {
1416     /* try to avoid direct loops */
1417     if (strcmp(gl.gl_pathv[x], fname) == 0)
1418     continue;
1419 vapier 1.148 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1420 vapier 1.149 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1421 solar 1.123 globfree64(&gl);
1422     return i;
1423     }
1424     }
1425     globfree64 (&gl);
1426     continue;
1427 solar 1.160 }
1428 solar 1.123 }
1429 solar 1.154 #endif
1430 solar 1.123 if (*path != '/')
1431     continue;
1432 vapier 1.48
1433     ldpaths[i++] = xstrdup(path);
1434    
1435 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1436 vapier 1.48 break;
1437     }
1438     ldpaths[i] = NULL;
1439    
1440     fclose(fp);
1441 solar 1.123 return i;
1442 vapier 1.48 }
1443 flameeyes 1.141
1444 vapier 1.148 #elif defined(__FreeBSD__) || (__DragonFly__)
1445    
1446     static int load_ld_cache_config(int i, const char *fname)
1447 flameeyes 1.141 {
1448     FILE *fp = NULL;
1449     char *b = NULL, *p;
1450     struct elfhints_hdr hdr;
1451 vapier 1.152
1452 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1453 flameeyes 1.141 return i;
1454    
1455     if ((fp = fopen(fname, "r")) == NULL)
1456     return i;
1457    
1458 vapier 1.152 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1459     hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1460     fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1461     {
1462 flameeyes 1.141 fclose(fp);
1463     return i;
1464     }
1465 vapier 1.152
1466 flameeyes 1.141 b = (char*)malloc(hdr.dirlistlen+1);
1467 vapier 1.152 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1468 flameeyes 1.141 fclose(fp);
1469     free(b);
1470     return i;
1471     }
1472 vapier 1.152
1473     while ((p = strsep(&b, ":"))) {
1474     if (*p == '\0') continue;
1475 flameeyes 1.141 ldpaths[i++] = xstrdup(p);
1476 vapier 1.152
1477 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1478 flameeyes 1.141 break;
1479     }
1480     ldpaths[i] = NULL;
1481 vapier 1.157
1482 flameeyes 1.141 free(b);
1483     fclose(fp);
1484     return i;
1485     }
1486 vapier 1.148
1487     #else
1488    
1489     #warning Cache config support not implemented for your target
1490     static int load_ld_cache_config(int i, const char *fname)
1491     {
1492     memset(ldpaths, 0x00, sizeof(ldpaths));
1493     }
1494    
1495 flameeyes 1.141 #endif
1496 vapier 1.48
1497 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1498     static void scanelf_ldpath()
1499     {
1500 vapier 1.17 char scan_l, scan_ul, scan_ull;
1501 vapier 1.48 int i = 0;
1502 vapier 1.10
1503 vapier 1.48 if (!ldpaths[0])
1504     err("Unable to load any paths from ld.so.conf");
1505 vapier 1.10
1506 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1507    
1508 vapier 1.48 while (ldpaths[i]) {
1509     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1510     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1511     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1512     scanelf_dir(ldpaths[i]);
1513     ++i;
1514     }
1515 vapier 1.10
1516 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1517     if (!scan_ul) scanelf_dir("/usr/lib");
1518     if (!scan_ull) scanelf_dir("/usr/local/lib");
1519 vapier 1.10 }
1520 solar 1.1
1521 vapier 1.10 /* scan env PATH for paths */
1522     static void scanelf_envpath()
1523 solar 1.1 {
1524 solar 1.34 char *path, *p;
1525 vapier 1.10
1526     path = getenv("PATH");
1527     if (!path)
1528     err("PATH is not set in your env !");
1529 vapier 1.41 path = xstrdup(path);
1530 vapier 1.10
1531     while ((p = strrchr(path, ':')) != NULL) {
1532     scanelf_dir(p + 1);
1533     *p = 0;
1534     }
1535 vapier 1.17
1536 solar 1.34 free(path);
1537 solar 1.1 }
1538    
1539 vapier 1.10 /* usage / invocation handling functions */
1540 solar 1.127 #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1541 vapier 1.27 #define a_argument required_argument
1542 vapier 1.10 static struct option const long_opts[] = {
1543     {"path", no_argument, NULL, 'p'},
1544     {"ldpath", no_argument, NULL, 'l'},
1545     {"recursive", no_argument, NULL, 'R'},
1546 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1547 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1548 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1549     {"ldcache", no_argument, NULL, 'L'},
1550 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1551 solar 1.127 {"setpax", a_argument, NULL, 'z'},
1552 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1553 solar 1.16 {"header", no_argument, NULL, 'e'},
1554 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1555     {"rpath", no_argument, NULL, 'r'},
1556 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1557 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1558 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1559 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1560 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1561 solar 1.124 {"section", a_argument, NULL, 'k'},
1562 vapier 1.76 {"lib", a_argument, NULL, 'N'},
1563 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1564 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1565 solar 1.119 {"etype", a_argument, NULL, 'E'},
1566 solar 1.120 {"bits", a_argument, NULL, 'M'},
1567 vapier 1.10 {"all", no_argument, NULL, 'a'},
1568     {"quiet", no_argument, NULL, 'q'},
1569 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1570 vapier 1.76 {"format", a_argument, NULL, 'F'},
1571     {"from", a_argument, NULL, 'f'},
1572     {"file", a_argument, NULL, 'o'},
1573 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1574 vapier 1.10 {"help", no_argument, NULL, 'h'},
1575     {"version", no_argument, NULL, 'V'},
1576     {NULL, no_argument, NULL, 0x0}
1577     };
1578 solar 1.57
1579 solar 1.68 static const char *opts_help[] = {
1580 vapier 1.10 "Scan all directories in PATH environment",
1581     "Scan all directories in /etc/ld.so.conf",
1582 vapier 1.14 "Scan directories recursively",
1583 vapier 1.37 "Don't recursively cross mount points",
1584 vapier 1.101 "Don't scan symlinks",
1585 vapier 1.105 "Scan archives (.a files)",
1586     "Utilize ld.so.cache information (use with -r/-n)",
1587 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
1588     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1589 vapier 1.10 "Print PaX markings",
1590 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1591 vapier 1.10 "Print TEXTREL information",
1592     "Print RPATH information",
1593 vapier 1.32 "Print NEEDED information",
1594 vapier 1.38 "Print INTERP information",
1595 vapier 1.49 "Print BIND information",
1596 vapier 1.84 "Print SONAME information",
1597 vapier 1.27 "Find a specified symbol",
1598 solar 1.124 "Find a specified section",
1599 vapier 1.72 "Find a specified library",
1600 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1601 vapier 1.76 "Locate cause of TEXTREL",
1602 solar 1.129 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1603 solar 1.120 "Print only ELF files matching numeric bits",
1604 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1605 vapier 1.14 "Only output 'bad' things",
1606     "Be verbose (can be specified more than once)",
1607 vapier 1.39 "Use specified format for output",
1608 solar 1.45 "Read input stream from a filename",
1609 vapier 1.24 "Write output stream to a filename",
1610 vapier 1.14 "Don't display the header",
1611 vapier 1.10 "Print this help and exit",
1612     "Print version and exit",
1613     NULL
1614     };
1615    
1616     /* display usage and exit */
1617     static void usage(int status)
1618 solar 1.1 {
1619 vapier 1.44 unsigned long i;
1620 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1621 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1622 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1623 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1624 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1625 vapier 1.157 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1626 vapier 1.27 long_opts[i].name, opts_help[i]);
1627     else
1628 solar 1.124 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1629 vapier 1.27 long_opts[i].name, opts_help[i]);
1630 solar 1.45
1631     if (status != EXIT_SUCCESS)
1632     exit(status);
1633 vapier 1.157
1634 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
1635 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1636     puts(" t TEXTREL \tr RPATH \tn NEEDED");
1637     puts(" i INTERP \tb BIND \ts symbol");
1638 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
1639 vapier 1.166 puts(" S SONAME \tk section \ta arch");
1640 vapier 1.70 puts(" p filename (with search path removed)");
1641 vapier 1.88 puts(" f filename (short name/basename)");
1642 vapier 1.70 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1643 solar 1.45
1644 solar 1.121 puts("\nELF Etypes:");
1645     print_etypes(stdout);
1646    
1647 vapier 1.10 exit(status);
1648 solar 1.1 }
1649    
1650     /* parse command line arguments and preform needed actions */
1651 vapier 1.165 #define do_pax_state(option, flag) \
1652     if (islower(option)) { \
1653     flags &= ~PF_##flag; \
1654     flags |= PF_NO##flag; \
1655     } else { \
1656     flags &= ~PF_NO##flag; \
1657     flags |= PF_##flag; \
1658     }
1659 solar 1.164 static int parseargs(int argc, char *argv[])
1660 vapier 1.10 {
1661 vapier 1.48 int i;
1662 vapier 1.133 const char *from_file = NULL;
1663 solar 1.164 int ret = 0;
1664 vapier 1.10
1665     opterr = 0;
1666 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1667     switch (i) {
1668 vapier 1.10
1669 vapier 1.39 case 'V':
1670 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1671     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1672     VERSION, __FILE__, __DATE__, rcsid, argv0);
1673 vapier 1.10 exit(EXIT_SUCCESS);
1674     break;
1675     case 'h': usage(EXIT_SUCCESS); break;
1676 solar 1.45 case 'f':
1677 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1678     from_file = optarg;
1679 solar 1.45 break;
1680 solar 1.119 case 'E':
1681     strncpy(match_etypes, optarg, sizeof(match_etypes));
1682     break;
1683 solar 1.120 case 'M':
1684     match_bits = atoi(optarg);
1685     break;
1686 vapier 1.24 case 'o': {
1687 vapier 1.146 if (freopen(optarg, "w", stdout) == NULL)
1688 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1689 solar 1.21 break;
1690     }
1691 solar 1.124 case 'k':
1692 vapier 1.126 if (find_section) warn("You prob don't want to specify -k twice");
1693 solar 1.124 find_section = optarg;
1694     break;
1695 vapier 1.39 case 's': {
1696 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1697     find_sym = optarg;
1698     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1699 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1700     break;
1701     }
1702 vapier 1.72 case 'N': {
1703 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1704     find_lib = optarg;
1705 vapier 1.72 break;
1706     }
1707 vapier 1.39
1708     case 'F': {
1709 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1710     out_format = optarg;
1711 vapier 1.39 break;
1712     }
1713 solar 1.127 case 'z': {
1714 solar 1.129 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1715 solar 1.127 size_t x;
1716 vapier 1.27
1717 solar 1.127 for (x = 0 ; x < strlen(optarg); x++) {
1718     switch(optarg[x]) {
1719     case 'p':
1720     case 'P':
1721 vapier 1.165 do_pax_state(optarg[x], PAGEEXEC);
1722 solar 1.127 break;
1723     case 's':
1724     case 'S':
1725 vapier 1.165 do_pax_state(optarg[x], SEGMEXEC);
1726 solar 1.127 break;
1727     case 'm':
1728     case 'M':
1729 vapier 1.165 do_pax_state(optarg[x], MPROTECT);
1730 solar 1.127 break;
1731     case 'e':
1732     case 'E':
1733 vapier 1.165 do_pax_state(optarg[x], EMUTRAMP);
1734 solar 1.127 break;
1735     case 'r':
1736     case 'R':
1737 vapier 1.165 do_pax_state(optarg[x], RANDMMAP);
1738 solar 1.127 break;
1739     case 'x':
1740     case 'X':
1741 vapier 1.165 do_pax_state(optarg[x], RANDEXEC);
1742 solar 1.127 break;
1743     default:
1744     break;
1745     }
1746     }
1747     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1748     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1749     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1750     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1751     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1752     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1753     setpax = flags;
1754     break;
1755     }
1756 vapier 1.122 case 'g': gmatch = 1; break;
1757 vapier 1.102 case 'L': use_ldcache = 1; break;
1758 vapier 1.37 case 'y': scan_symlink = 0; break;
1759 vapier 1.105 case 'A': scan_archives = 1; break;
1760 solar 1.16 case 'B': show_banner = 0; break;
1761 vapier 1.10 case 'l': scan_ldpath = 1; break;
1762     case 'p': scan_envpath = 1; break;
1763     case 'R': dir_recurse = 1; break;
1764 vapier 1.14 case 'm': dir_crossmount = 0; break;
1765 vapier 1.101 case 'X': ++fix_elf; break;
1766 vapier 1.10 case 'x': show_pax = 1; break;
1767 solar 1.73 case 'e': show_phdr = 1; break;
1768 vapier 1.10 case 't': show_textrel = 1; break;
1769     case 'r': show_rpath = 1; break;
1770 vapier 1.32 case 'n': show_needed = 1; break;
1771 vapier 1.38 case 'i': show_interp = 1; break;
1772 vapier 1.49 case 'b': show_bind = 1; break;
1773 vapier 1.84 case 'S': show_soname = 1; break;
1774 vapier 1.76 case 'T': show_textrels = 1; break;
1775 vapier 1.10 case 'q': be_quiet = 1; break;
1776 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1777 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1778 vapier 1.10
1779     case ':':
1780 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1781 vapier 1.10 case '?':
1782 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1783 vapier 1.10 default:
1784 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1785 vapier 1.10 }
1786     }
1787 solar 1.170 if (show_textrels && be_verbose) {
1788     if (which("objdump") != NULL)
1789     has_objdump = 1;
1790     }
1791 vapier 1.39 /* let the format option override all other options */
1792     if (out_format) {
1793 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1794 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1795     show_textrels = 0;
1796 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1797 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1798 vapier 1.39
1799 vapier 1.48 switch (out_format[++i]) {
1800 solar 1.132 case '+': break;
1801 vapier 1.39 case '%': break;
1802 vapier 1.70 case '#': break;
1803 vapier 1.39 case 'F': break;
1804 vapier 1.66 case 'p': break;
1805     case 'f': break;
1806 solar 1.124 case 'k': break;
1807 vapier 1.39 case 's': break;
1808 vapier 1.72 case 'N': break;
1809 vapier 1.41 case 'o': break;
1810 vapier 1.166 case 'a': break;
1811 vapier 1.39 case 'x': show_pax = 1; break;
1812 solar 1.73 case 'e': show_phdr = 1; break;
1813 vapier 1.39 case 't': show_textrel = 1; break;
1814     case 'r': show_rpath = 1; break;
1815     case 'n': show_needed = 1; break;
1816     case 'i': show_interp = 1; break;
1817 vapier 1.49 case 'b': show_bind = 1; break;
1818 vapier 1.84 case 'S': show_soname = 1; break;
1819 vapier 1.76 case 'T': show_textrels = 1; break;
1820 vapier 1.39 default:
1821 vapier 1.162 err("Invalid format specifier '%c' (byte %i)",
1822 vapier 1.48 out_format[i], i+1);
1823 vapier 1.39 }
1824     }
1825 vapier 1.41
1826     /* construct our default format */
1827     } else {
1828     size_t fmt_len = 30;
1829     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1830 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1831     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1832     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1833     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1834     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1835     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1836     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1837     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1838 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1839 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1840     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1841 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1842 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1843     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1844 vapier 1.39 }
1845 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1846 vapier 1.39
1847     /* now lets actually do the scanning */
1848 vapier 1.102 if (scan_ldpath || use_ldcache)
1849 vapier 1.148 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1850 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1851     if (scan_envpath) scanelf_envpath();
1852 solar 1.153 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1853 vapier 1.133 from_file = "-";
1854 solar 1.45 if (from_file) {
1855     scanelf_from_file(from_file);
1856     from_file = *argv;
1857     }
1858     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1859 vapier 1.25 err("Nothing to scan !?");
1860 vapier 1.66 while (optind < argc) {
1861     search_path = argv[optind++];
1862 solar 1.164 ret = scanelf_dir(search_path);
1863 vapier 1.66 }
1864 vapier 1.27
1865 vapier 1.39 /* clean up */
1866 vapier 1.152 free(versioned_symname);
1867 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1868     free(ldpaths[i]);
1869 solar 1.96
1870     if (ldcache != 0)
1871     munmap(ldcache, ldcache_size);
1872 solar 1.164 return ret;
1873 vapier 1.10 }
1874    
1875 vapier 1.150 static char **get_split_env(const char *envvar)
1876     {
1877 vapier 1.152 const char *delims = " \t\n";
1878 solar 1.143 char **envvals = NULL;
1879 vapier 1.152 char *env, *s;
1880 kevquinn 1.142 int nentry;
1881    
1882 solar 1.143 if ((env = getenv(envvar)) == NULL)
1883     return NULL;
1884 kevquinn 1.142
1885 solar 1.143 env = xstrdup(env);
1886     if (env == NULL)
1887     return NULL;
1888 kevquinn 1.142
1889 vapier 1.152 s = strtok(env, delims);
1890     if (s == NULL) {
1891     free(env);
1892     return NULL;
1893     }
1894    
1895 solar 1.143 nentry = 0;
1896 vapier 1.152 while (s != NULL) {
1897     ++nentry;
1898     envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1899     envvals[nentry-1] = s;
1900     s = strtok(NULL, delims);
1901 kevquinn 1.142 }
1902 vapier 1.152 envvals[nentry] = NULL;
1903 kevquinn 1.142
1904 vapier 1.152 /* don't want to free(env) as it contains the memory that backs
1905     * the envvals array of strings */
1906 kevquinn 1.142 return envvals;
1907     }
1908 vapier 1.150 static void parseenv()
1909     {
1910     qa_textrels = get_split_env("QA_TEXTRELS");
1911     qa_execstack = get_split_env("QA_EXECSTACK");
1912     qa_wx_load = get_split_env("QA_WX_LOAD");
1913 vapier 1.41 }
1914 solar 1.163
1915 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1916     static void cleanup()
1917     {
1918     free(out_format);
1919     free(qa_textrels);
1920     free(qa_execstack);
1921     free(qa_wx_load);
1922     }
1923     #endif
1924 vapier 1.41
1925    
1926 vapier 1.10 int main(int argc, char *argv[])
1927 solar 1.1 {
1928 solar 1.164 int ret;
1929 vapier 1.10 if (argc < 2)
1930     usage(EXIT_FAILURE);
1931 kevquinn 1.142 parseenv();
1932 solar 1.164 ret = parseargs(argc, argv);
1933 solar 1.21 fclose(stdout);
1934 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1935     cleanup();
1936     warn("The calls to add/delete heap should be off:\n"
1937     "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1938     "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1939 solar 1.61 #endif
1940 solar 1.164 return ret;
1941 solar 1.1 }
1942 vapier 1.155
1943    
1944    
1945     /* utility funcs */
1946     static char *xstrdup(const char *s)
1947     {
1948     char *ret = strdup(s);
1949     if (!ret) err("Could not strdup(): %s", strerror(errno));
1950     return ret;
1951     }
1952     static void *xmalloc(size_t size)
1953     {
1954     void *ret = malloc(size);
1955     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1956     return ret;
1957     }
1958     static void *xrealloc(void *ptr, size_t size)
1959     {
1960     void *ret = realloc(ptr, size);
1961     if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
1962     return ret;
1963     }
1964     static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1965     {
1966     size_t new_len;
1967    
1968     new_len = strlen(*dst) + strlen(src);
1969     if (*curr_len <= new_len) {
1970     *curr_len = new_len + (*curr_len / 2);
1971     *dst = realloc(*dst, *curr_len);
1972     if (!*dst)
1973     err("could not realloc() %li bytes", (unsigned long)*curr_len);
1974     }
1975    
1976     if (n)
1977     strncat(*dst, src, n);
1978     else
1979     strcat(*dst, src);
1980     }
1981     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1982     {
1983     static char my_app[2];
1984     my_app[0] = append;
1985     my_app[1] = '\0';
1986     xstrcat(dst, my_app, curr_len);
1987     }
1988    
1989     /* Match filename against entries in matchlist, return TRUE
1990     * if the file is listed */
1991     static int file_matches_list(const char *filename, char **matchlist)
1992     {
1993     char **file;
1994     char *match;
1995     char buf[__PAX_UTILS_PATH_MAX];
1996    
1997     if (matchlist == NULL)
1998     return 0;
1999    
2000     for (file = matchlist; *file != NULL; file++) {
2001     if (search_path) {
2002     snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2003     match = buf;
2004     } else {
2005     match = *file;
2006     }
2007     if (fnmatch(match, filename, 0) == 0)
2008     return 1;
2009     }
2010     return 0;
2011     }

  ViewVC Help
Powered by ViewVC 1.1.20