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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.169 - (hide annotations) (download) (as text)
Tue Jan 9 00:23:13 2007 UTC (7 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.168: +16 -8 lines
File MIME type: text/x-csrc
generally improve textrel output

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

  ViewVC Help
Powered by ViewVC 1.1.20