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

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.109 Revision 1.188
1/* 1/*
2 * Copyright 2003-2006 Gentoo Foundation 2 * Copyright 2003-2007 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.109 2006/01/20 00:20:30 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.188 2007/08/31 17:45:24 solar Exp $
5 * 5 *
6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10static const char *rcsid = "$Id: scanelf.c,v 1.188 2007/08/31 17:45:24 solar Exp $";
11const char * const argv0 = "scanelf";
12
10#include "paxinc.h" 13#include "paxinc.h"
11 14
12static const char *rcsid = "$Id: scanelf.c,v 1.109 2006/01/20 00:20:30 vapier Exp $";
13#define argv0 "scanelf"
14
15#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16
17
18 16
19/* prototypes */ 17/* prototypes */
18static int file_matches_list(const char *filename, char **matchlist);
20static int scanelf_elfobj(elfobj *elf); 19static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len); 20static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len); 21static int scanelf_archive(const char *filename, int fd, size_t len);
23static void scanelf_file(const char *filename); 22static int scanelf_file(const char *filename, const struct stat *st_cache);
24static void scanelf_dir(const char *path); 23static int scanelf_dir(const char *path);
25static void scanelf_ldpath(void); 24static void scanelf_ldpath(void);
26static void scanelf_envpath(void); 25static void scanelf_envpath(void);
27static void usage(int status); 26static void usage(int status);
27static char **get_split_env(const char *envvar);
28static void parseenv(void);
28static void parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
29static char *xstrdup(const char *s); 30static int rematch(const char *regex, const char *match, int cflags);
30static void *xmalloc(size_t size);
31static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
33static inline void xchrcat(char **dst, const char append, size_t *curr_len);
34 31
35/* variables to control behavior */ 32/* variables to control behavior */
33static char match_etypes[126] = "";
36static char *ldpaths[256]; 34static char *ldpaths[256];
37static char scan_ldpath = 0; 35static char scan_ldpath = 0;
38static char scan_envpath = 0; 36static char scan_envpath = 0;
39static char scan_symlink = 1; 37static char scan_symlink = 1;
40static char scan_archives = 0; 38static char scan_archives = 0;
41static char dir_recurse = 0; 39static char dir_recurse = 0;
42static char dir_crossmount = 1; 40static char dir_crossmount = 1;
43static char show_pax = 0; 41static char show_pax = 0;
42static char show_perms = 0;
44static char show_phdr = 0; 43static char show_phdr = 0;
45static char show_textrel = 0; 44static char show_textrel = 0;
46static char show_rpath = 0; 45static char show_rpath = 0;
47static char show_needed = 0; 46static char show_needed = 0;
48static char show_interp = 0; 47static char show_interp = 0;
49static char show_bind = 0; 48static char show_bind = 0;
50static char show_soname = 0; 49static char show_soname = 0;
51static char show_textrels = 0; 50static char show_textrels = 0;
52static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
53static char be_quiet = 0; 53static char be_quiet = 0;
54static char be_verbose = 0; 54static char be_verbose = 0;
55static char be_wewy_wewy_quiet = 0; 55static char be_wewy_wewy_quiet = 0;
56static char be_semi_verbose = 0;
56static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
57static char *find_lib = NULL; 58static char *find_lib = NULL;
59static char *find_section = NULL;
58static char *out_format = NULL; 60static char *out_format = NULL;
59static char *search_path = NULL; 61static char *search_path = NULL;
60static char fix_elf = 0; 62static char fix_elf = 0;
61static char gmatch = 0; 63static char g_match = 0;
62static char use_ldcache = 0; 64static char use_ldcache = 0;
63 65
66static char **qa_textrels = NULL;
67static char **qa_execstack = NULL;
68static char **qa_wx_load = NULL;
64 69
70int match_bits = 0;
71unsigned int match_perms = 0;
65caddr_t ldcache = 0; 72caddr_t ldcache = 0;
66size_t ldcache_size = 0; 73size_t ldcache_size = 0;
74unsigned long setpax = 0UL;
75
76int has_objdump = 0;
77
78static char *getstr_perms(const char *fname);
79static char *getstr_perms(const char *fname)
80{
81 struct stat st;
82 static char buf[8];
83
84 if ((stat(fname, &st)) == (-1))
85 return (char *) "";
86
87 snprintf(buf, sizeof(buf), "%o", st.st_mode);
88
89 return (char *) buf + 2;
90}
91
92/* find the path to a file by name */
93static char *which(const char *fname)
94{
95 static char fullpath[BUFSIZ];
96 char *path, *p;
97
98 path = getenv("PATH");
99 if (!path)
100 return NULL;
101
102 path = xstrdup(path);
103 while ((p = strrchr(path, ':')) != NULL) {
104 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
105 *p = 0;
106 if (access(fullpath, R_OK) != (-1)) {
107 free(path);
108 return (char *) fullpath;
109 }
110 }
111 free(path);
112 return NULL;
113}
114
115/* 1 on failure. 0 otherwise */
116static int rematch(const char *regex, const char *match, int cflags)
117{
118 regex_t preg;
119 int ret;
120
121 if ((match == NULL) || (regex == NULL))
122 return EXIT_FAILURE;
123
124
125 if ((ret = regcomp(&preg, regex, cflags))) {
126 char err[256];
127
128 if (regerror(ret, &preg, err, sizeof(err)))
129 fprintf(stderr, "regcomp failed: %s", err);
130 else
131 fprintf(stderr, "regcomp failed");
132
133 return EXIT_FAILURE;
134 }
135 ret = regexec(&preg, match, 0, NULL, 0);
136 regfree(&preg);
137
138 return ret;
139}
67 140
68/* sub-funcs for scanelf_file() */ 141/* sub-funcs for scanelf_file() */
69static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 142static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
70{ 143{
71 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 144 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
90 } \ 163 } \
91 } 164 }
92 GET_SYMTABS(32) 165 GET_SYMTABS(32)
93 GET_SYMTABS(64) 166 GET_SYMTABS(64)
94} 167}
168
95static char *scanelf_file_pax(elfobj *elf, char *found_pax) 169static char *scanelf_file_pax(elfobj *elf, char *found_pax)
96{ 170{
97 static char ret[7]; 171 static char ret[7];
98 unsigned long i, shown; 172 unsigned long i, shown;
99 173
108 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 182 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
109 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 183 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
110 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 184 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
111 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 185 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
112 continue; \ 186 continue; \
113 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 187 if (fix_elf && setpax) { \
188 /* set the paxctl flags */ \
189 ESET(phdr[i].p_flags, setpax); \
190 } \
191 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
114 continue; \ 192 continue; \
115 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 193 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
116 *found_pax = 1; \ 194 *found_pax = 1; \
117 ++shown; \ 195 ++shown; \
118 break; \ 196 break; \
119 } \ 197 } \
120 } 198 }
121 SHOW_PAX(32) 199 SHOW_PAX(32)
122 SHOW_PAX(64) 200 SHOW_PAX(64)
201 }
202
203
204 if (fix_elf && setpax) {
205 /* set the chpax settings */
206 if (elf->elf_class == ELFCLASS32) {
207 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
208 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
209 } else {
210 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
211 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
212 }
123 } 213 }
124 214
125 /* fall back to EI_PAX if no PT_PAX was found */ 215 /* fall back to EI_PAX if no PT_PAX was found */
126 if (!*ret) { 216 if (!*ret) {
127 static char *paxflags; 217 static char *paxflags;
162 uint32_t flags, check_flags; \ 252 uint32_t flags, check_flags; \
163 if (elf->phdr != NULL) { \ 253 if (elf->phdr != NULL) { \
164 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 254 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
165 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 255 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
166 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 256 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
257 if (multi_stack++) \
167 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 258 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
259 if (file_matches_list(elf->filename, qa_execstack)) \
260 continue; \
168 found = found_phdr; \ 261 found = found_phdr; \
169 offset = 0; \ 262 offset = 0; \
170 check_flags = PF_X; \ 263 check_flags = PF_X; \
171 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 264 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
265 if (multi_relro++) \
172 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 266 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
173 found = found_relro; \ 267 found = found_relro; \
174 offset = 4; \ 268 offset = 4; \
175 check_flags = PF_X; \ 269 check_flags = PF_X; \
176 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 270 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
271 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
272 if (multi_load++ > max_pt_load) \
177 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \ 273 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
274 if (file_matches_list(elf->filename, qa_wx_load)) \
275 continue; \
178 found = found_load; \ 276 found = found_load; \
179 offset = 8; \ 277 offset = 8; \
180 check_flags = PF_W|PF_X; \ 278 check_flags = PF_W|PF_X; \
181 } else \ 279 } else \
182 continue; \ 280 continue; \
183 flags = EGET(phdr[i].p_flags); \ 281 flags = EGET(phdr[i].p_flags); \
184 if (be_quiet && ((flags & check_flags) != check_flags)) \ 282 if (be_quiet && ((flags & check_flags) != check_flags)) \
185 continue; \ 283 continue; \
186 if (fix_elf && ((flags & PF_X) != flags)) { \ 284 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
187 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \ 285 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
188 ret[3] = ret[7] = '!'; \ 286 ret[3] = ret[7] = '!'; \
189 flags = EGET(phdr[i].p_flags); \ 287 flags = EGET(phdr[i].p_flags); \
190 } \ 288 } \
191 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 289 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
195 } else if (elf->shdr != NULL) { \ 293 } else if (elf->shdr != NULL) { \
196 /* no program headers which means this is prob an object file */ \ 294 /* no program headers which means this is prob an object file */ \
197 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 295 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
198 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 296 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
199 char *str; \ 297 char *str; \
200 if ((void*)strtbl > (void*)(elf->data + sizeof(*strtbl))) \ 298 if ((void*)strtbl > (void*)elf->data_end) \
201 goto skip_this_shdr##B; \ 299 goto skip_this_shdr##B; \
202 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 300 check_flags = SHF_WRITE|SHF_EXECINSTR; \
203 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 301 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
204 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 302 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
205 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 303 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
219 break; \ 317 break; \
220 } \ 318 } \
221 } \ 319 } \
222 skip_this_shdr##B: \ 320 skip_this_shdr##B: \
223 if (!multi_stack) { \ 321 if (!multi_stack) { \
322 if (file_matches_list(elf->filename, qa_execstack)) \
323 return NULL; \
224 *found_phdr = 1; \ 324 *found_phdr = 1; \
225 shown = 1; \ 325 shown = 1; \
226 memcpy(ret, "!WX", 3); \ 326 memcpy(ret, "!WX", 3); \
227 } \ 327 } \
228 } \ 328 } \
233 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 333 if (be_wewy_wewy_quiet || (be_quiet && !shown))
234 return NULL; 334 return NULL;
235 else 335 else
236 return ret; 336 return ret;
237} 337}
338
339/*
340 * See if this ELF contains a DT_TEXTREL tag in any of its
341 * PT_DYNAMIC sections.
342 */
238static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 343static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
239{ 344{
240 static const char *ret = "TEXTREL"; 345 static const char *ret = "TEXTREL";
241 unsigned long i; 346 unsigned long i;
242 347
243 if (!show_textrel && !show_textrels) return NULL; 348 if (!show_textrel && !show_textrels) return NULL;
349
350 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
244 351
245 if (elf->phdr) { 352 if (elf->phdr) {
246#define SHOW_TEXTREL(B) \ 353#define SHOW_TEXTREL(B) \
247 if (elf->elf_class == ELFCLASS ## B) { \ 354 if (elf->elf_class == ELFCLASS ## B) { \
248 Elf ## B ## _Dyn *dyn; \ 355 Elf ## B ## _Dyn *dyn; \
249 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 356 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
250 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 357 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
251 Elf ## B ## _Off offset; \ 358 Elf ## B ## _Off offset; \
252 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 359 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
253 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 360 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
254 offset = EGET(phdr[i].p_offset); \ 361 offset = EGET(phdr[i].p_offset); \
255 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 362 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
256 dyn = DYN ## B (elf->data + offset); \ 363 dyn = DYN ## B (elf->data + offset); \
257 while (EGET(dyn->d_tag) != DT_NULL) { \ 364 while (EGET(dyn->d_tag) != DT_NULL) { \
258 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 365 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
270 if (be_quiet || be_wewy_wewy_quiet) 377 if (be_quiet || be_wewy_wewy_quiet)
271 return NULL; 378 return NULL;
272 else 379 else
273 return " - "; 380 return " - ";
274} 381}
382
383/*
384 * Scan the .text section to see if there are any relocations in it.
385 * Should rewrite this to check PT_LOAD sections that are marked
386 * Executable rather than the section named '.text'.
387 */
275static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 388static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
276{ 389{
277 unsigned long s, r, rmax; 390 unsigned long s, r, rmax;
278 void *symtab_void, *strtab_void, *text_void; 391 void *symtab_void, *strtab_void, *text_void;
279 392
331 if (be_verbose <= 2) continue; \ 444 if (be_verbose <= 2) continue; \
332 } else \ 445 } else \
333 *found_textrels = 1; \ 446 *found_textrels = 1; \
334 /* locate this relocation symbol name */ \ 447 /* locate this relocation symbol name */ \
335 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 448 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
336 if (sym > elf->data) { \ 449 if ((void*)sym > (void*)elf->data_end) { \
337 warn("corrupt ELF symbol"); \ 450 warn("%s: corrupt ELF symbol", elf->filename); \
338 continue; \ 451 continue; \
339 } \ 452 } \
340 sym_max = ELF ## B ## _R_SYM(r_info); \ 453 sym_max = ELF ## B ## _R_SYM(r_info); \
341 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 454 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
342 sym += sym_max; \ 455 sym += sym_max; \
346 /* show the raw details about this reloc */ \ 459 /* show the raw details about this reloc */ \
347 printf(" %s: ", elf->base_filename); \ 460 printf(" %s: ", elf->base_filename); \
348 if (sym && sym->st_name) \ 461 if (sym && sym->st_name) \
349 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 462 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
350 else \ 463 else \
351 printf("(memory/fake?)"); \ 464 printf("(memory/data?)"); \
352 printf(" [0x%lX]", (unsigned long)r_offset); \ 465 printf(" [0x%lX]", (unsigned long)r_offset); \
353 /* now try to find the closest symbol that this rel is probably in */ \ 466 /* now try to find the closest symbol that this rel is probably in */ \
354 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 467 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
355 func = NULL; \ 468 func = NULL; \
356 offset_tmp = 0; \ 469 offset_tmp = 0; \
360 offset_tmp = EGET(sym->st_value); \ 473 offset_tmp = EGET(sym->st_value); \
361 } \ 474 } \
362 ++sym; \ 475 ++sym; \
363 } \ 476 } \
364 printf(" in "); \ 477 printf(" in "); \
365 if (func && func->st_name) \ 478 if (func && func->st_name) { \
366 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ 479 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
480 if (r_offset > EGET(func->st_size)) \
481 printf("(optimized out: previous %s)", func_name); \
367 else \ 482 else \
368 printf("(NULL: fake?)"); \ 483 printf("%s", func_name); \
484 } else \
485 printf("(optimized out)"); \
369 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 486 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
487 if (be_verbose && has_objdump) { \
488 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
489 char *sysbuf; \
490 size_t syslen; \
491 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"; \
492 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
493 sysbuf = xmalloc(syslen); \
494 if (end_addr < r_offset) \
495 /* not uncommon when things are optimized out */ \
496 end_addr = r_offset + 0x100; \
497 snprintf(sysbuf, syslen, sysfmt, \
498 (unsigned long)offset_tmp, \
499 (unsigned long)end_addr, \
500 elf->filename, \
501 (unsigned long)r_offset); \
502 fflush(stdout); \
503 system(sysbuf); \
504 fflush(stdout); \
505 free(sysbuf); \
506 } \
370 } \ 507 } \
371 } } 508 } }
372 SHOW_TEXTRELS(32) 509 SHOW_TEXTRELS(32)
373 SHOW_TEXTRELS(64) 510 SHOW_TEXTRELS(64)
374 } 511 }
392 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 529 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
393 break; 530 break;
394 case '$': 531 case '$':
395 if (fstat(elf->fd, &st) != -1) 532 if (fstat(elf->fd, &st) != -1)
396 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 533 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
397 warnf("Security problem with %s='%s' in %s with mode set of %o", 534 warnf("Security problem with %s='%s' in %s with mode set of %o",
398 dt_type, item, elf->filename, st.st_mode & 07777); 535 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
399 break; 536 break;
400 default: 537 default:
401 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename); 538 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
402 break; 539 break;
403 } 540 }
423 Elf ## B ## _Off offset; \ 560 Elf ## B ## _Off offset; \
424 Elf ## B ## _Xword word; \ 561 Elf ## B ## _Xword word; \
425 /* Scan all the program headers */ \ 562 /* Scan all the program headers */ \
426 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 563 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
427 /* Just scan dynamic headers */ \ 564 /* Just scan dynamic headers */ \
428 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 565 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
429 offset = EGET(phdr[i].p_offset); \ 566 offset = EGET(phdr[i].p_offset); \
430 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 567 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
431 /* Just scan dynamic RPATH/RUNPATH headers */ \ 568 /* Just scan dynamic RPATH/RUNPATH headers */ \
432 dyn = DYN ## B (elf->data + offset); \ 569 dyn = DYN ## B (elf->data + offset); \
433 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 570 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
562#define FLAG_POWERPC_LIB64 0x0500 699#define FLAG_POWERPC_LIB64 0x0500
563#define FLAG_MIPS64_LIBN32 0x0600 700#define FLAG_MIPS64_LIBN32 0x0600
564#define FLAG_MIPS64_LIBN64 0x0700 701#define FLAG_MIPS64_LIBN64 0x0700
565 702
566static char *lookup_cache_lib(elfobj *, char *); 703static char *lookup_cache_lib(elfobj *, char *);
704
705#if defined(__GLIBC__) || defined(__UCLIBC__)
706
567static char *lookup_cache_lib(elfobj *elf, char *fname) 707static char *lookup_cache_lib(elfobj *elf, char *fname)
568{ 708{
569 int fd = 0; 709 int fd = 0;
570 char *strs; 710 char *strs;
571 static char buf[__PAX_UTILS_PATH_MAX] = ""; 711 static char buf[__PAX_UTILS_PATH_MAX] = "";
597 ldcache_size = st.st_size; 737 ldcache_size = st.st_size;
598 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); 738 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
599 739
600 close(fd); 740 close(fd);
601 741
602 if (ldcache == (caddr_t)-1) 742 if (ldcache == (caddr_t)-1) {
743 ldcache = 0;
603 return NULL; 744 return NULL;
745 }
604 746
605 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 747 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
606 return NULL; 748 return NULL;
607 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)) 749 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
608 return NULL; 750 return NULL;
625 continue; 767 continue;
626 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 768 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
627 } 769 }
628 return buf; 770 return buf;
629} 771}
772#elif defined(__NetBSD__)
773static char *lookup_cache_lib(elfobj *elf, char *fname)
774{
775 static char buf[__PAX_UTILS_PATH_MAX] = "";
776 static struct stat st;
630 777
778 char **ldpath;
779 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
780 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
781 continue; /* if the pathname is too long, or something went wrong, ignore */
782
783 if (stat(buf, &st) != 0)
784 continue; /* if the lib doesn't exist in *ldpath, look further */
785
786 /* NetBSD doesn't actually do sanity checks, it just loads the file
787 * and if that doesn't work, continues looking in other directories.
788 * This cannot easily be safely emulated, unfortunately. For now,
789 * just assume that if it exists, it's a valid library. */
790
791 return buf;
792 }
793
794 /* not found in any path */
795 return NULL;
796}
797#else
798#warning Cache support not implemented for your target
799static char *lookup_cache_lib(elfobj *elf, char *fname)
800{
801 return NULL;
802}
803#endif
631 804
632static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 805static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
633{ 806{
634 unsigned long i; 807 unsigned long i;
635 char *needed; 808 char *needed;
647 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 820 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
648 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 821 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
649 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 822 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
650 Elf ## B ## _Off offset; \ 823 Elf ## B ## _Off offset; \
651 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 824 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
652 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 825 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
653 offset = EGET(phdr[i].p_offset); \ 826 offset = EGET(phdr[i].p_offset); \
654 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 827 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
655 dyn = DYN ## B (elf->data + offset); \ 828 dyn = DYN ## B (elf->data + offset); \
656 while (EGET(dyn->d_tag) != DT_NULL) { \ 829 while (EGET(dyn->d_tag) != DT_NULL) { \
657 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 830 if (EGET(dyn->d_tag) == DT_NEEDED) { \
669 needed = p; \ 842 needed = p; \
670 xstrcat(ret, needed, ret_len); \ 843 xstrcat(ret, needed, ret_len); \
671 } \ 844 } \
672 *found_needed = 1; \ 845 *found_needed = 1; \
673 } else { \ 846 } else { \
674 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 847 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
675 *found_lib = 1; \ 848 *found_lib = 1; \
676 return (be_wewy_wewy_quiet ? NULL : needed); \ 849 return (be_wewy_wewy_quiet ? NULL : needed); \
677 } \ 850 } \
678 } \ 851 } \
679 } \ 852 } \
710} 883}
711static char *scanelf_file_bind(elfobj *elf, char *found_bind) 884static char *scanelf_file_bind(elfobj *elf, char *found_bind)
712{ 885{
713 unsigned long i; 886 unsigned long i;
714 struct stat s; 887 struct stat s;
888 char dynamic = 0;
715 889
716 if (!show_bind) return NULL; 890 if (!show_bind) return NULL;
717 if (!elf->phdr) return NULL; 891 if (!elf->phdr) return NULL;
718 892
719#define SHOW_BIND(B) \ 893#define SHOW_BIND(B) \
721 Elf ## B ## _Dyn *dyn; \ 895 Elf ## B ## _Dyn *dyn; \
722 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 896 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
723 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 897 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
724 Elf ## B ## _Off offset; \ 898 Elf ## B ## _Off offset; \
725 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 899 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
726 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 900 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
901 dynamic = 1; \
727 offset = EGET(phdr[i].p_offset); \ 902 offset = EGET(phdr[i].p_offset); \
728 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 903 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
729 dyn = DYN ## B (elf->data + offset); \ 904 dyn = DYN ## B (elf->data + offset); \
730 while (EGET(dyn->d_tag) != DT_NULL) { \ 905 while (EGET(dyn->d_tag) != DT_NULL) { \
731 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 906 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
742 SHOW_BIND(32) 917 SHOW_BIND(32)
743 SHOW_BIND(64) 918 SHOW_BIND(64)
744 919
745 if (be_wewy_wewy_quiet) return NULL; 920 if (be_wewy_wewy_quiet) return NULL;
746 921
922 /* don't output anything if quiet mode and the ELF is static or not setuid */
747 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 923 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
748 return NULL; 924 return NULL;
749 } else { 925 } else {
750 *found_bind = 1; 926 *found_bind = 1;
751 return (char *) "LAZY"; 927 return (char *) (dynamic ? "LAZY" : "STATIC");
752 } 928 }
753} 929}
754static char *scanelf_file_soname(elfobj *elf, char *found_soname) 930static char *scanelf_file_soname(elfobj *elf, char *found_soname)
755{ 931{
756 unsigned long i; 932 unsigned long i;
768 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 944 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
769 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 945 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
770 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 946 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
771 Elf ## B ## _Off offset; \ 947 Elf ## B ## _Off offset; \
772 /* only look for soname in shared objects */ \ 948 /* only look for soname in shared objects */ \
773 if (ehdr->e_type != ET_DYN) \ 949 if (EGET(ehdr->e_type) != ET_DYN) \
774 return NULL; \ 950 return NULL; \
775 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 951 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
776 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 952 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
777 offset = EGET(phdr[i].p_offset); \ 953 offset = EGET(phdr[i].p_offset); \
778 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 954 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
779 dyn = DYN ## B (elf->data + offset); \ 955 dyn = DYN ## B (elf->data + offset); \
780 while (EGET(dyn->d_tag) != DT_NULL) { \ 956 while (EGET(dyn->d_tag) != DT_NULL) { \
781 if (EGET(dyn->d_tag) == DT_SONAME) { \ 957 if (EGET(dyn->d_tag) == DT_SONAME) { \
795 SHOW_SONAME(64) 971 SHOW_SONAME(64)
796 } 972 }
797 973
798 return NULL; 974 return NULL;
799} 975}
976
800static char *scanelf_file_sym(elfobj *elf, char *found_sym) 977static char *scanelf_file_sym(elfobj *elf, char *found_sym)
801{ 978{
802 unsigned long i; 979 unsigned long i;
803 char *ret; 980 char *ret;
804 void *symtab_void, *strtab_void; 981 void *symtab_void, *strtab_void;
812#define FIND_SYM(B) \ 989#define FIND_SYM(B) \
813 if (elf->elf_class == ELFCLASS ## B) { \ 990 if (elf->elf_class == ELFCLASS ## B) { \
814 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 991 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
815 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 992 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
816 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 993 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
817 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 994 unsigned long cnt = EGET(symtab->sh_entsize); \
818 char *symname; \ 995 char *symname; \
996 if (cnt) \
997 cnt = EGET(symtab->sh_size) / cnt; \
819 for (i = 0; i < cnt; ++i) { \ 998 for (i = 0; i < cnt; ++i) { \
820 if (sym->st_name) { \ 999 if (sym->st_name) { \
1000 /* make sure the symbol name is in acceptable memory range */ \
821 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1001 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
822 if (*find_sym == '*') { \ 1002 if ((void*)symname > (void*)elf->data_end) { \
1003 warnf("%s: corrupt ELF symbols", elf->filename); \
1004 ++sym; \
1005 continue; \
1006 } \
1007 /* debug display ... show all symbols and some extra info */ \
1008 if (g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
823 printf("%s(%s) %5lX %15s %s\n", \ 1009 printf("%s(%s) %5lX %15s %s %s\n", \
824 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1010 ((*found_sym == 0) ? "\n\t" : "\t"), \
825 elf->base_filename, \ 1011 elf->base_filename, \
826 (unsigned long)sym->st_size, \ 1012 (unsigned long)sym->st_size, \
827 get_elfstttype(sym->st_info), \ 1013 get_elfstttype(sym->st_info), \
828 symname); \ 1014 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
829 *found_sym = 1; \ 1015 *found_sym = 1; \
830 } else { \ 1016 } else { \
1017 /* allow the user to specify a comma delimited list of symbols to search for */ \
831 char *this_sym, *next_sym; \ 1018 char *this_sym, *this_sym_ver, *next_sym; \
1019 this_sym = ret; \
832 this_sym = find_sym; \ 1020 this_sym_ver = versioned_symname; \
833 do { \ 1021 do { \
834 next_sym = strchr(this_sym, ','); \ 1022 next_sym = strchr(this_sym, ','); \
835 if (next_sym == NULL) \ 1023 if (next_sym == NULL) \
836 next_sym = this_sym + strlen(this_sym); \ 1024 next_sym = this_sym + strlen(this_sym); \
1025 /* do we want a defined symbol ? */ \
1026 if (*this_sym == '+') { \
1027 if (sym->st_shndx == SHN_UNDEF) \
1028 goto skip_this_sym##B; \
1029 ++this_sym; \
1030 ++this_sym_ver; \
1031 /* do we want an undefined symbol ? */ \
1032 } else if (*this_sym == '-') { \
1033 if (sym->st_shndx != SHN_UNDEF) \
1034 goto skip_this_sym##B; \
1035 ++this_sym; \
1036 ++this_sym_ver; \
1037 } \
1038 /* ok, lets compare the name now */ \
837 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \ 1039 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
838 (strcmp(symname, versioned_symname) == 0)) { \ 1040 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
1041 if (be_semi_verbose) { \
1042 char buf[126]; \
1043 snprintf(buf, sizeof(buf), "%lX %s %s", \
1044 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1045 ret = buf; \
1046 } else \
839 ret = this_sym; \ 1047 ret = this_sym; \
840 (*found_sym)++; \ 1048 (*found_sym)++; \
841 goto break_out; \ 1049 goto break_out; \
842 } \ 1050 } \
843 this_sym = next_sym + 1; \ 1051 skip_this_sym##B: this_sym = next_sym + 1; \
844 } while (*next_sym != '\0'); \ 1052 } while (*next_sym != '\0'); \
845 } \ 1053 } \
846 } \ 1054 } \
847 ++sym; \ 1055 ++sym; \
848 } } 1056 } }
858 if (be_quiet) 1066 if (be_quiet)
859 return NULL; 1067 return NULL;
860 else 1068 else
861 return (char *)" - "; 1069 return (char *)" - ";
862} 1070}
1071
1072
1073static char *scanelf_file_sections(elfobj *elf, char *found_section)
1074{
1075 if (!find_section)
1076 return NULL;
1077
1078#define FIND_SECTION(B) \
1079 if (elf->elf_class == ELFCLASS ## B) { \
1080 int invert; \
1081 Elf ## B ## _Shdr *section; \
1082 invert = (*find_section == '!' ? 1 : 0); \
1083 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1084 if ((section == NULL && invert) || (section != NULL && !invert)) \
1085 *found_section = 1; \
1086 }
1087 FIND_SECTION(32)
1088 FIND_SECTION(64)
1089
1090 if (be_wewy_wewy_quiet)
1091 return NULL;
1092
1093 if (*found_section)
1094 return find_section;
1095
1096 if (be_quiet)
1097 return NULL;
1098 else
1099 return (char *)" - ";
1100}
1101
863/* scan an elf file and show all the fun stuff */ 1102/* scan an elf file and show all the fun stuff */
864#define prints(str) write(fileno(stdout), str, strlen(str)) 1103#define prints(str) write(fileno(stdout), str, strlen(str))
865static int scanelf_elfobj(elfobj *elf) 1104static int scanelf_elfobj(elfobj *elf)
866{ 1105{
867 unsigned long i; 1106 unsigned long i;
868 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1107 char found_pax, found_phdr, found_relro, found_load, found_textrel,
869 found_rpath, found_needed, found_interp, found_bind, found_soname, 1108 found_rpath, found_needed, found_interp, found_bind, found_soname,
870 found_sym, found_lib, found_file, found_textrels; 1109 found_sym, found_lib, found_file, found_textrels, found_section;
871 static char *out_buffer = NULL; 1110 static char *out_buffer = NULL;
872 static size_t out_len; 1111 static size_t out_len;
873 1112
874 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1113 found_pax = found_phdr = found_relro = found_load = found_textrel = \
875 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1114 found_rpath = found_needed = found_interp = found_bind = found_soname = \
876 found_sym = found_lib = found_file = found_textrels = 0; 1115 found_sym = found_lib = found_file = found_textrels = found_section = 0;
877 1116
878 if (be_verbose > 1) 1117 if (be_verbose > 2)
879 printf("%s: scanning file {%s,%s}\n", elf->filename, 1118 printf("%s: scanning file {%s,%s}\n", elf->filename,
880 get_elfeitype(EI_CLASS, elf->elf_class), 1119 get_elfeitype(EI_CLASS, elf->elf_class),
881 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1120 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
882 else if (be_verbose) 1121 else if (be_verbose > 1)
883 printf("%s: scanning file\n", elf->filename); 1122 printf("%s: scanning file\n", elf->filename);
884 1123
885 /* init output buffer */ 1124 /* init output buffer */
886 if (!out_buffer) { 1125 if (!out_buffer) {
887 out_len = sizeof(char) * 80; 1126 out_len = sizeof(char) * 80;
888 out_buffer = (char*)xmalloc(out_len); 1127 out_buffer = xmalloc(out_len);
889 } 1128 }
890 *out_buffer = '\0'; 1129 *out_buffer = '\0';
891 1130
892 /* show the header */ 1131 /* show the header */
893 if (!be_quiet && show_banner) { 1132 if (!be_quiet && show_banner) {
894 for (i = 0; out_format[i]; ++i) { 1133 for (i = 0; out_format[i]; ++i) {
895 if (!IS_MODIFIER(out_format[i])) continue; 1134 if (!IS_MODIFIER(out_format[i])) continue;
896 1135
897 switch (out_format[++i]) { 1136 switch (out_format[++i]) {
1137 case '+': break;
898 case '%': break; 1138 case '%': break;
899 case '#': break; 1139 case '#': break;
900 case 'F': 1140 case 'F':
901 case 'p': 1141 case 'p':
902 case 'f': prints("FILE "); found_file = 1; break; 1142 case 'f': prints("FILE "); found_file = 1; break;
903 case 'o': prints(" TYPE "); break; 1143 case 'o': prints(" TYPE "); break;
904 case 'x': prints(" PAX "); break; 1144 case 'x': prints(" PAX "); break;
905 case 'e': prints("STK/REL/PTL "); break; 1145 case 'e': prints("STK/REL/PTL "); break;
906 case 't': prints("TEXTREL "); break; 1146 case 't': prints("TEXTREL "); break;
907 case 'r': prints("RPATH "); break; 1147 case 'r': prints("RPATH "); break;
1148 case 'M': prints("CLASS "); break;
908 case 'n': prints("NEEDED "); break; 1149 case 'n': prints("NEEDED "); break;
909 case 'i': prints("INTERP "); break; 1150 case 'i': prints("INTERP "); break;
910 case 'b': prints("BIND "); break; 1151 case 'b': prints("BIND "); break;
911 case 'S': prints("SONAME "); break; 1152 case 'S': prints("SONAME "); break;
912 case 's': prints("SYM "); break; 1153 case 's': prints("SYM "); break;
913 case 'N': prints("LIB "); break; 1154 case 'N': prints("LIB "); break;
914 case 'T': prints("TEXTRELS "); break; 1155 case 'T': prints("TEXTRELS "); break;
1156 case 'k': prints("SECTION "); break;
1157 case 'a': prints("ARCH "); break;
1158 case 'O': prints("PERM "); break;
1159 case 'D': prints("ENDIAN "); break;
915 default: warnf("'%c' has no title ?", out_format[i]); 1160 default: warnf("'%c' has no title ?", out_format[i]);
916 } 1161 }
917 } 1162 }
918 if (!found_file) prints("FILE "); 1163 if (!found_file) prints("FILE ");
919 prints("\n"); 1164 prints("\n");
924 /* dump all the good stuff */ 1169 /* dump all the good stuff */
925 for (i = 0; out_format[i]; ++i) { 1170 for (i = 0; out_format[i]; ++i) {
926 const char *out; 1171 const char *out;
927 const char *tmp; 1172 const char *tmp;
928 1173
929 /* make sure we trim leading spaces in quiet mode */
930 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
931 *out_buffer = '\0';
932
933 if (!IS_MODIFIER(out_format[i])) { 1174 if (!IS_MODIFIER(out_format[i])) {
934 xchrcat(&out_buffer, out_format[i], &out_len); 1175 xchrcat(&out_buffer, out_format[i], &out_len);
935 continue; 1176 continue;
936 } 1177 }
937 1178
938 out = NULL; 1179 out = NULL;
939 be_wewy_wewy_quiet = (out_format[i] == '#'); 1180 be_wewy_wewy_quiet = (out_format[i] == '#');
1181 be_semi_verbose = (out_format[i] == '+');
940 switch (out_format[++i]) { 1182 switch (out_format[++i]) {
1183 case '+':
941 case '%': 1184 case '%':
942 case '#': 1185 case '#':
943 xchrcat(&out_buffer, out_format[i], &out_len); break; 1186 xchrcat(&out_buffer, out_format[i], &out_len); break;
944 case 'F': 1187 case 'F':
945 found_file = 1; 1188 found_file = 1;
971 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1214 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
972 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1215 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
973 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1216 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
974 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; 1217 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
975 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1218 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1219 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1220 case 'D': out = get_endian(elf); break;
1221 case 'O': out = getstr_perms(elf->filename); break;
976 case 'n': 1222 case 'n':
977 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1223 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
978 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1224 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
979 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1225 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
980 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1226 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
981 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1227 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1228 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1229 case 'a': out = get_elfemtype(elf); break;
982 default: warnf("'%c' has no scan code?", out_format[i]); 1230 default: warnf("'%c' has no scan code?", out_format[i]);
983 } 1231 }
984 if (out) { 1232 if (out) {
985 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1233 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
986 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1234 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
991 } 1239 }
992 1240
993#define FOUND_SOMETHING() \ 1241#define FOUND_SOMETHING() \
994 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1242 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
995 found_rpath || found_needed || found_interp || found_bind || \ 1243 found_rpath || found_needed || found_interp || found_bind || \
996 found_soname || found_sym || found_lib || found_textrels) 1244 found_soname || found_sym || found_lib || found_textrels || found_section )
997 1245
998 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1246 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
999 xchrcat(&out_buffer, ' ', &out_len); 1247 xchrcat(&out_buffer, ' ', &out_len);
1000 xstrcat(&out_buffer, elf->filename, &out_len); 1248 xstrcat(&out_buffer, elf->filename, &out_len);
1001 } 1249 }
1008} 1256}
1009 1257
1010/* scan a single elf */ 1258/* scan a single elf */
1011static int scanelf_elf(const char *filename, int fd, size_t len) 1259static int scanelf_elf(const char *filename, int fd, size_t len)
1012{ 1260{
1013 int ret; 1261 int ret = 1;
1014 elfobj *elf; 1262 elfobj *elf;
1015 1263
1016 /* verify this is real ELF */ 1264 /* verify this is real ELF */
1017 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { 1265 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1018 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 1266 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1019 return 1; 1267 return ret;
1268 }
1269 switch (match_bits) {
1270 case 32:
1271 if (elf->elf_class != ELFCLASS32)
1272 goto label_done;
1273 break;
1274 case 64:
1275 if (elf->elf_class != ELFCLASS64)
1276 goto label_done;
1277 break;
1278 default: break;
1279 }
1280 if (strlen(match_etypes)) {
1281 char sbuf[126];
1282 strncpy(sbuf, match_etypes, sizeof(sbuf));
1283 if (strchr(match_etypes, ',') != NULL) {
1284 char *p;
1285 while ((p = strrchr(sbuf, ',')) != NULL) {
1286 *p = 0;
1287 if (etype_lookup(p+1) == get_etype(elf))
1288 goto label_ret;
1289 }
1020 } 1290 }
1291 if (etype_lookup(sbuf) != get_etype(elf))
1292 goto label_done;
1293 }
1021 1294
1295label_ret:
1022 ret = scanelf_elfobj(elf); 1296 ret = scanelf_elfobj(elf);
1297
1298label_done:
1023 unreadelf(elf); 1299 unreadelf(elf);
1024 return ret; 1300 return ret;
1025} 1301}
1302
1026/* scan an archive of elfs */ 1303/* scan an archive of elfs */
1027static int scanelf_archive(const char *filename, int fd, size_t len) 1304static int scanelf_archive(const char *filename, int fd, size_t len)
1028{ 1305{
1029 archive_handle *ar; 1306 archive_handle *ar;
1030 archive_member *m; 1307 archive_member *m;
1046 munmap(ar_buffer, len); 1323 munmap(ar_buffer, len);
1047 1324
1048 return 0; 1325 return 0;
1049} 1326}
1050/* scan a file which may be an elf or an archive or some other magical beast */ 1327/* scan a file which may be an elf or an archive or some other magical beast */
1051static void scanelf_file(const char *filename) 1328static int scanelf_file(const char *filename, const struct stat *st_cache)
1052{ 1329{
1330 const struct stat *st = st_cache;
1053 struct stat st; 1331 struct stat symlink_st;
1054 int fd; 1332 int fd;
1055 1333
1056 /* make sure 'filename' exists */
1057 if (lstat(filename, &st) == -1) {
1058 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1059 return;
1060 }
1061
1062 /* always handle regular files and handle symlinked files if no -y */ 1334 /* always handle regular files and handle symlinked files if no -y */
1063 if (S_ISLNK(st.st_mode)) { 1335 if (S_ISLNK(st->st_mode)) {
1064 if (!scan_symlink) return; 1336 if (!scan_symlink) return 1;
1065 stat(filename, &st); 1337 stat(filename, &symlink_st);
1338 st = &symlink_st;
1066 } 1339 }
1340
1067 if (!S_ISREG(st.st_mode)) { 1341 if (!S_ISREG(st->st_mode)) {
1068 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1342 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1069 return; 1343 return 1;
1070 } 1344 }
1071 1345
1346 if (match_perms) {
1347 if ((st->st_mode | match_perms) != st->st_mode)
1348 return 1;
1349 }
1072 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1350 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1073 return; 1351 return 1;
1074 1352
1075 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1353 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1076 /* if it isn't an ELF, maybe it's an .a archive */ 1354 /* if it isn't an ELF, maybe it's an .a archive */
1077 scanelf_archive(filename, fd, st.st_size); 1355 scanelf_archive(filename, fd, st->st_size);
1078 1356
1079 close(fd); 1357 close(fd);
1358 return 0;
1080} 1359}
1081 1360
1082/* scan a directory for ET_EXEC files and print when we find one */ 1361/* scan a directory for ET_EXEC files and print when we find one */
1083static void scanelf_dir(const char *path) 1362static int scanelf_dir(const char *path)
1084{ 1363{
1085 register DIR *dir; 1364 register DIR *dir;
1086 register struct dirent *dentry; 1365 register struct dirent *dentry;
1087 struct stat st_top, st; 1366 struct stat st_top, st;
1088 char buf[__PAX_UTILS_PATH_MAX]; 1367 char buf[__PAX_UTILS_PATH_MAX];
1089 size_t pathlen = 0, len = 0; 1368 size_t pathlen = 0, len = 0;
1369 int ret = 0;
1090 1370
1091 /* make sure path exists */ 1371 /* make sure path exists */
1092 if (lstat(path, &st_top) == -1) { 1372 if (lstat(path, &st_top) == -1) {
1093 if (be_verbose > 2) printf("%s: does not exist\n", path); 1373 if (be_verbose > 2) printf("%s: does not exist\n", path);
1094 return; 1374 return 1;
1095 } 1375 }
1096 1376
1097 /* ok, if it isn't a directory, assume we can open it */ 1377 /* ok, if it isn't a directory, assume we can open it */
1098 if (!S_ISDIR(st_top.st_mode)) { 1378 if (!S_ISDIR(st_top.st_mode)) {
1099 scanelf_file(path); 1379 return scanelf_file(path, &st_top);
1100 return;
1101 } 1380 }
1102 1381
1103 /* now scan the dir looking for fun stuff */ 1382 /* now scan the dir looking for fun stuff */
1104 if ((dir = opendir(path)) == NULL) { 1383 if ((dir = opendir(path)) == NULL) {
1105 warnf("could not opendir %s: %s", path, strerror(errno)); 1384 warnf("could not opendir %s: %s", path, strerror(errno));
1106 return; 1385 return 1;
1107 } 1386 }
1108 if (be_verbose) printf("%s: scanning dir\n", path); 1387 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1109 1388
1110 pathlen = strlen(path); 1389 pathlen = strlen(path);
1111 while ((dentry = readdir(dir))) { 1390 while ((dentry = readdir(dir))) {
1112 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1391 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1113 continue; 1392 continue;
1115 if (len >= sizeof(buf)) { 1394 if (len >= sizeof(buf)) {
1116 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1395 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1117 (unsigned long)len, (unsigned long)sizeof(buf)); 1396 (unsigned long)len, (unsigned long)sizeof(buf));
1118 continue; 1397 continue;
1119 } 1398 }
1120 sprintf(buf, "%s/%s", path, dentry->d_name); 1399 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1121 if (lstat(buf, &st) != -1) { 1400 if (lstat(buf, &st) != -1) {
1122 if (S_ISREG(st.st_mode)) 1401 if (S_ISREG(st.st_mode))
1123 scanelf_file(buf); 1402 ret = scanelf_file(buf, &st);
1124 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1403 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1125 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1404 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1126 scanelf_dir(buf); 1405 ret = scanelf_dir(buf);
1127 } 1406 }
1128 } 1407 }
1129 } 1408 }
1130 closedir(dir); 1409 closedir(dir);
1410 return ret;
1131} 1411}
1132 1412
1133static int scanelf_from_file(char *filename) 1413static int scanelf_from_file(const char *filename)
1134{ 1414{
1135 FILE *fp = NULL; 1415 FILE *fp = NULL;
1136 char *p; 1416 char *p;
1137 char path[__PAX_UTILS_PATH_MAX]; 1417 char path[__PAX_UTILS_PATH_MAX];
1418 int ret = 0;
1138 1419
1139 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1420 if (strcmp(filename, "-") == 0)
1140 fp = stdin; 1421 fp = stdin;
1141 else if ((fp = fopen(filename, "r")) == NULL) 1422 else if ((fp = fopen(filename, "r")) == NULL)
1142 return 1; 1423 return 1;
1143 1424
1144 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1425 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1145 if ((p = strchr(path, '\n')) != NULL) 1426 if ((p = strchr(path, '\n')) != NULL)
1146 *p = 0; 1427 *p = 0;
1147 search_path = path; 1428 search_path = path;
1148 scanelf_dir(path); 1429 ret = scanelf_dir(path);
1149 } 1430 }
1150 if (fp != stdin) 1431 if (fp != stdin)
1151 fclose(fp); 1432 fclose(fp);
1152 return 0; 1433 return ret;
1153} 1434}
1154 1435
1155static void load_ld_so_conf() 1436#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1437
1438static int load_ld_cache_config(int i, const char *fname)
1156{ 1439{
1157 FILE *fp = NULL; 1440 FILE *fp = NULL;
1158 char *p; 1441 char *p;
1159 char path[__PAX_UTILS_PATH_MAX]; 1442 char path[__PAX_UTILS_PATH_MAX];
1160 int i = 0;
1161 1443
1162 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1444 if (i + 1 == ARRAY_SIZE(ldpaths))
1163 return; 1445 return i;
1446
1447 if ((fp = fopen(fname, "r")) == NULL)
1448 return i;
1164 1449
1165 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1450 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1166 if (*path != '/')
1167 continue;
1168
1169 if ((p = strrchr(path, '\r')) != NULL) 1451 if ((p = strrchr(path, '\r')) != NULL)
1170 *p = 0; 1452 *p = 0;
1171 if ((p = strchr(path, '\n')) != NULL) 1453 if ((p = strchr(path, '\n')) != NULL)
1172 *p = 0; 1454 *p = 0;
1455#ifdef __linux__
1456 /* recursive includes of the same file will make this segfault. */
1457 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1458 glob64_t gl;
1459 size_t x;
1460 char gpath[__PAX_UTILS_PATH_MAX];
1461
1462 memset(gpath, 0, sizeof(gpath));
1463
1464 if (path[8] != '/')
1465 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1466 else
1467 strncpy(gpath, &path[8], sizeof(gpath));
1468
1469 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1470 for (x = 0; x < gl.gl_pathc; ++x) {
1471 /* try to avoid direct loops */
1472 if (strcmp(gl.gl_pathv[x], fname) == 0)
1473 continue;
1474 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1475 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1476 globfree64(&gl);
1477 return i;
1478 }
1479 }
1480 globfree64 (&gl);
1481 continue;
1482 }
1483 }
1484#endif
1485 if (*path != '/')
1486 continue;
1173 1487
1174 ldpaths[i++] = xstrdup(path); 1488 ldpaths[i++] = xstrdup(path);
1175 1489
1176 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1490 if (i + 1 == ARRAY_SIZE(ldpaths))
1177 break; 1491 break;
1178 } 1492 }
1179 ldpaths[i] = NULL; 1493 ldpaths[i] = NULL;
1180 1494
1181 fclose(fp); 1495 fclose(fp);
1496 return i;
1182} 1497}
1498
1499#elif defined(__FreeBSD__) || (__DragonFly__)
1500
1501static int load_ld_cache_config(int i, const char *fname)
1502{
1503 FILE *fp = NULL;
1504 char *b = NULL, *p;
1505 struct elfhints_hdr hdr;
1506
1507 if (i + 1 == ARRAY_SIZE(ldpaths))
1508 return i;
1509
1510 if ((fp = fopen(fname, "r")) == NULL)
1511 return i;
1512
1513 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1514 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1515 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1516 {
1517 fclose(fp);
1518 return i;
1519 }
1520
1521 b = xmalloc(hdr.dirlistlen + 1);
1522 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1523 fclose(fp);
1524 free(b);
1525 return i;
1526 }
1527
1528 while ((p = strsep(&b, ":"))) {
1529 if (*p == '\0') continue;
1530 ldpaths[i++] = xstrdup(p);
1531
1532 if (i + 1 == ARRAY_SIZE(ldpaths))
1533 break;
1534 }
1535 ldpaths[i] = NULL;
1536
1537 free(b);
1538 fclose(fp);
1539 return i;
1540}
1541
1542#else
1543
1544#warning Cache config support not implemented for your target
1545static int load_ld_cache_config(int i, const char *fname)
1546{
1547 memset(ldpaths, 0x00, sizeof(ldpaths));
1548}
1549
1550#endif
1183 1551
1184/* scan /etc/ld.so.conf for paths */ 1552/* scan /etc/ld.so.conf for paths */
1185static void scanelf_ldpath() 1553static void scanelf_ldpath(void)
1186{ 1554{
1187 char scan_l, scan_ul, scan_ull; 1555 char scan_l, scan_ul, scan_ull;
1188 int i = 0; 1556 int i = 0;
1189 1557
1190 if (!ldpaths[0]) 1558 if (!ldpaths[0])
1204 if (!scan_ul) scanelf_dir("/usr/lib"); 1572 if (!scan_ul) scanelf_dir("/usr/lib");
1205 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1573 if (!scan_ull) scanelf_dir("/usr/local/lib");
1206} 1574}
1207 1575
1208/* scan env PATH for paths */ 1576/* scan env PATH for paths */
1209static void scanelf_envpath() 1577static void scanelf_envpath(void)
1210{ 1578{
1211 char *path, *p; 1579 char *path, *p;
1212 1580
1213 path = getenv("PATH"); 1581 path = getenv("PATH");
1214 if (!path) 1582 if (!path)
1222 1590
1223 free(path); 1591 free(path);
1224} 1592}
1225 1593
1226 1594
1227/* usage / invocation handling functions */ 1595/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H I J K P Q U W Y Z */
1228#define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:BhV" 1596#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DO:BhV"
1229#define a_argument required_argument 1597#define a_argument required_argument
1230static struct option const long_opts[] = { 1598static struct option const long_opts[] = {
1231 {"path", no_argument, NULL, 'p'}, 1599 {"path", no_argument, NULL, 'p'},
1232 {"ldpath", no_argument, NULL, 'l'}, 1600 {"ldpath", no_argument, NULL, 'l'},
1233 {"recursive", no_argument, NULL, 'R'}, 1601 {"recursive", no_argument, NULL, 'R'},
1234 {"mount", no_argument, NULL, 'm'}, 1602 {"mount", no_argument, NULL, 'm'},
1235 {"symlink", no_argument, NULL, 'y'}, 1603 {"symlink", no_argument, NULL, 'y'},
1236 {"archives", no_argument, NULL, 'A'}, 1604 {"archives", no_argument, NULL, 'A'},
1237 {"ldcache", no_argument, NULL, 'L'}, 1605 {"ldcache", no_argument, NULL, 'L'},
1238 {"fix", no_argument, NULL, 'X'}, 1606 {"fix", no_argument, NULL, 'X'},
1607 {"setpax", a_argument, NULL, 'z'},
1239 {"pax", no_argument, NULL, 'x'}, 1608 {"pax", no_argument, NULL, 'x'},
1240 {"header", no_argument, NULL, 'e'}, 1609 {"header", no_argument, NULL, 'e'},
1241 {"textrel", no_argument, NULL, 't'}, 1610 {"textrel", no_argument, NULL, 't'},
1242 {"rpath", no_argument, NULL, 'r'}, 1611 {"rpath", no_argument, NULL, 'r'},
1243 {"needed", no_argument, NULL, 'n'}, 1612 {"needed", no_argument, NULL, 'n'},
1244 {"interp", no_argument, NULL, 'i'}, 1613 {"interp", no_argument, NULL, 'i'},
1245 {"bind", no_argument, NULL, 'b'}, 1614 {"bind", no_argument, NULL, 'b'},
1246 {"soname", no_argument, NULL, 'S'}, 1615 {"soname", no_argument, NULL, 'S'},
1247 {"symbol", a_argument, NULL, 's'}, 1616 {"symbol", a_argument, NULL, 's'},
1617 {"section", a_argument, NULL, 'k'},
1248 {"lib", a_argument, NULL, 'N'}, 1618 {"lib", a_argument, NULL, 'N'},
1249 {"gmatch", no_argument, NULL, 'g'}, 1619 {"gmatch", no_argument, NULL, 'g'},
1250 {"textrels", no_argument, NULL, 'T'}, 1620 {"textrels", no_argument, NULL, 'T'},
1621 {"etype", a_argument, NULL, 'E'},
1622 {"bits", a_argument, NULL, 'M'},
1623 {"endian", no_argument, NULL, 'D'},
1624 {"perms", a_argument, NULL, 'O'},
1251 {"all", no_argument, NULL, 'a'}, 1625 {"all", no_argument, NULL, 'a'},
1252 {"quiet", no_argument, NULL, 'q'}, 1626 {"quiet", no_argument, NULL, 'q'},
1253 {"verbose", no_argument, NULL, 'v'}, 1627 {"verbose", no_argument, NULL, 'v'},
1254 {"format", a_argument, NULL, 'F'}, 1628 {"format", a_argument, NULL, 'F'},
1255 {"from", a_argument, NULL, 'f'}, 1629 {"from", a_argument, NULL, 'f'},
1266 "Scan directories recursively", 1640 "Scan directories recursively",
1267 "Don't recursively cross mount points", 1641 "Don't recursively cross mount points",
1268 "Don't scan symlinks", 1642 "Don't scan symlinks",
1269 "Scan archives (.a files)", 1643 "Scan archives (.a files)",
1270 "Utilize ld.so.cache information (use with -r/-n)", 1644 "Utilize ld.so.cache information (use with -r/-n)",
1271 "Try and 'fix' bad things (use with -r/-e)\n", 1645 "Try and 'fix' bad things (use with -r/-e)",
1646 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1272 "Print PaX markings", 1647 "Print PaX markings",
1273 "Print GNU_STACK/PT_LOAD markings", 1648 "Print GNU_STACK/PT_LOAD markings",
1274 "Print TEXTREL information", 1649 "Print TEXTREL information",
1275 "Print RPATH information", 1650 "Print RPATH information",
1276 "Print NEEDED information", 1651 "Print NEEDED information",
1277 "Print INTERP information", 1652 "Print INTERP information",
1278 "Print BIND information", 1653 "Print BIND information",
1279 "Print SONAME information", 1654 "Print SONAME information",
1280 "Find a specified symbol", 1655 "Find a specified symbol",
1656 "Find a specified section",
1281 "Find a specified library", 1657 "Find a specified library",
1282 "Use strncmp to match libraries. (use with -N)", 1658 "Use strncmp to match libraries. (use with -N)",
1283 "Locate cause of TEXTREL", 1659 "Locate cause of TEXTREL",
1660 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1661 "Print only ELF files matching numeric bits",
1662 "Print Endianness",
1663 "Print only ELF files matching octal permissions",
1284 "Print all scanned info (-x -e -t -r -b)\n", 1664 "Print all scanned info (-x -e -t -r -b)\n",
1285 "Only output 'bad' things", 1665 "Only output 'bad' things",
1286 "Be verbose (can be specified more than once)", 1666 "Be verbose (can be specified more than once)",
1287 "Use specified format for output", 1667 "Use specified format for output",
1288 "Read input stream from a filename", 1668 "Read input stream from a filename",
1300 printf("* Scan ELF binaries for stuff\n\n" 1680 printf("* Scan ELF binaries for stuff\n\n"
1301 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 1681 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1302 printf("Options: -[%s]\n", PARSE_FLAGS); 1682 printf("Options: -[%s]\n", PARSE_FLAGS);
1303 for (i = 0; long_opts[i].name; ++i) 1683 for (i = 0; long_opts[i].name; ++i)
1304 if (long_opts[i].has_arg == no_argument) 1684 if (long_opts[i].has_arg == no_argument)
1305 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1685 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1306 long_opts[i].name, opts_help[i]); 1686 long_opts[i].name, opts_help[i]);
1307 else 1687 else
1308 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1688 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1309 long_opts[i].name, opts_help[i]); 1689 long_opts[i].name, opts_help[i]);
1310 1690
1311 if (status != EXIT_SUCCESS) 1691 puts("\nFor more information, see the scanelf(1) manpage");
1312 exit(status);
1313
1314 puts("\nThe format modifiers for the -F option are:");
1315 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1316 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1317 puts(" i INTERP \tb BIND \ts symbol");
1318 puts(" N library \to Type \tT TEXTRELs");
1319 puts(" S SONAME");
1320 puts(" p filename (with search path removed)");
1321 puts(" f filename (short name/basename)");
1322 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1323
1324 exit(status); 1692 exit(status);
1325} 1693}
1326 1694
1327/* parse command line arguments and preform needed actions */ 1695/* parse command line arguments and preform needed actions */
1696#define do_pax_state(option, flag) \
1697 if (islower(option)) { \
1698 flags &= ~PF_##flag; \
1699 flags |= PF_NO##flag; \
1700 } else { \
1701 flags &= ~PF_NO##flag; \
1702 flags |= PF_##flag; \
1703 }
1328static void parseargs(int argc, char *argv[]) 1704static int parseargs(int argc, char *argv[])
1329{ 1705{
1330 int i; 1706 int i;
1331 char *from_file = NULL; 1707 const char *from_file = NULL;
1708 int ret = 0;
1332 1709
1333 opterr = 0; 1710 opterr = 0;
1334 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1711 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1335 switch (i) { 1712 switch (i) {
1336 1713
1343 case 'h': usage(EXIT_SUCCESS); break; 1720 case 'h': usage(EXIT_SUCCESS); break;
1344 case 'f': 1721 case 'f':
1345 if (from_file) warn("You prob don't want to specify -f twice"); 1722 if (from_file) warn("You prob don't want to specify -f twice");
1346 from_file = optarg; 1723 from_file = optarg;
1347 break; 1724 break;
1725 case 'E':
1726 strncpy(match_etypes, optarg, sizeof(match_etypes));
1727 break;
1728 case 'M':
1729 match_bits = atoi(optarg);
1730 if (match_bits == 0) {
1731 if (strcmp(optarg, "ELFCLASS32") == 0)
1732 match_bits = 32;
1733 if (strcmp(optarg, "ELFCLASS64") == 0)
1734 match_bits = 64;
1735 }
1736 break;
1737 case 'O':
1738 if (sscanf(optarg, "%o", &match_perms) == (-1))
1739 match_bits = 0;
1740 break;
1348 case 'o': { 1741 case 'o': {
1349 FILE *fp = NULL;
1350 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1742 if (freopen(optarg, "w", stdout) == NULL)
1351 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1743 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1352 SET_STDOUT(fp);
1353 break; 1744 break;
1354 } 1745 }
1355 1746 case 'k':
1747 if (find_section) warn("You prob don't want to specify -k twice");
1748 find_section = optarg;
1749 break;
1356 case 's': { 1750 case 's': {
1357 if (find_sym) warn("You prob don't want to specify -s twice"); 1751 if (find_sym) warn("You prob don't want to specify -s twice");
1358 find_sym = optarg; 1752 find_sym = optarg;
1359 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1753 versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1360 sprintf(versioned_symname, "%s@", find_sym); 1754 sprintf(versioned_symname, "%s@", find_sym);
1361 break; 1755 break;
1362 } 1756 }
1363 case 'N': { 1757 case 'N': {
1364 if (find_lib) warn("You prob don't want to specify -N twice"); 1758 if (find_lib) warn("You prob don't want to specify -N twice");
1369 case 'F': { 1763 case 'F': {
1370 if (out_format) warn("You prob don't want to specify -F twice"); 1764 if (out_format) warn("You prob don't want to specify -F twice");
1371 out_format = optarg; 1765 out_format = optarg;
1372 break; 1766 break;
1373 } 1767 }
1768 case 'z': {
1769 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1770 size_t x;
1374 1771
1375 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */ 1772 for (x = 0; x < strlen(optarg); x++) {
1773 switch (optarg[x]) {
1774 case 'p':
1775 case 'P':
1776 do_pax_state(optarg[x], PAGEEXEC);
1777 break;
1778 case 's':
1779 case 'S':
1780 do_pax_state(optarg[x], SEGMEXEC);
1781 break;
1782 case 'm':
1783 case 'M':
1784 do_pax_state(optarg[x], MPROTECT);
1785 break;
1786 case 'e':
1787 case 'E':
1788 do_pax_state(optarg[x], EMUTRAMP);
1789 break;
1790 case 'r':
1791 case 'R':
1792 do_pax_state(optarg[x], RANDMMAP);
1793 break;
1794 case 'x':
1795 case 'X':
1796 do_pax_state(optarg[x], RANDEXEC);
1797 break;
1798 default:
1799 break;
1800 }
1801 }
1802 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1803 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1804 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1805 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1806 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1807 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1808 setpax = flags;
1809 break;
1810 }
1811 case 'g': g_match = 1; break;
1376 case 'L': use_ldcache = 1; break; 1812 case 'L': use_ldcache = 1; break;
1377 case 'y': scan_symlink = 0; break; 1813 case 'y': scan_symlink = 0; break;
1378 case 'A': scan_archives = 1; break; 1814 case 'A': scan_archives = 1; break;
1379 case 'B': show_banner = 0; break; 1815 case 'B': show_banner = 0; break;
1380 case 'l': scan_ldpath = 1; break; 1816 case 'l': scan_ldpath = 1; break;
1391 case 'b': show_bind = 1; break; 1827 case 'b': show_bind = 1; break;
1392 case 'S': show_soname = 1; break; 1828 case 'S': show_soname = 1; break;
1393 case 'T': show_textrels = 1; break; 1829 case 'T': show_textrels = 1; break;
1394 case 'q': be_quiet = 1; break; 1830 case 'q': be_quiet = 1; break;
1395 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1831 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1396 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1832 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1397 1833 case 'D': show_endian = 1; break;
1398 case ':': 1834 case ':':
1399 err("Option missing parameter\n"); 1835 err("Option '%c' is missing parameter", optopt);
1400 case '?': 1836 case '?':
1401 err("Unknown option\n"); 1837 err("Unknown option '%c' or argument missing", optopt);
1402 default: 1838 default:
1403 err("Unhandled option '%c'", i); 1839 err("Unhandled option '%c'; please report this", i);
1404 }
1405 } 1840 }
1406 1841 }
1842 if (show_textrels && be_verbose) {
1843 if (which("objdump") != NULL)
1844 has_objdump = 1;
1845 }
1407 /* let the format option override all other options */ 1846 /* let the format option override all other options */
1408 if (out_format) { 1847 if (out_format) {
1409 show_pax = show_phdr = show_textrel = show_rpath = \ 1848 show_pax = show_phdr = show_textrel = show_rpath = \
1410 show_needed = show_interp = show_bind = show_soname = \ 1849 show_needed = show_interp = show_bind = show_soname = \
1411 show_textrels = 0; 1850 show_textrels = show_perms = show_endian = 0;
1412 for (i = 0; out_format[i]; ++i) { 1851 for (i = 0; out_format[i]; ++i) {
1413 if (!IS_MODIFIER(out_format[i])) continue; 1852 if (!IS_MODIFIER(out_format[i])) continue;
1414 1853
1415 switch (out_format[++i]) { 1854 switch (out_format[++i]) {
1855 case '+': break;
1416 case '%': break; 1856 case '%': break;
1417 case '#': break; 1857 case '#': break;
1418 case 'F': break; 1858 case 'F': break;
1419 case 'p': break; 1859 case 'p': break;
1420 case 'f': break; 1860 case 'f': break;
1861 case 'k': break;
1421 case 's': break; 1862 case 's': break;
1422 case 'N': break; 1863 case 'N': break;
1423 case 'o': break; 1864 case 'o': break;
1865 case 'a': break;
1866 case 'M': break;
1867 case 'D': show_endian = 1; break;
1868 case 'O': show_perms = 1; break;
1424 case 'x': show_pax = 1; break; 1869 case 'x': show_pax = 1; break;
1425 case 'e': show_phdr = 1; break; 1870 case 'e': show_phdr = 1; break;
1426 case 't': show_textrel = 1; break; 1871 case 't': show_textrel = 1; break;
1427 case 'r': show_rpath = 1; break; 1872 case 'r': show_rpath = 1; break;
1428 case 'n': show_needed = 1; break; 1873 case 'n': show_needed = 1; break;
1429 case 'i': show_interp = 1; break; 1874 case 'i': show_interp = 1; break;
1430 case 'b': show_bind = 1; break; 1875 case 'b': show_bind = 1; break;
1431 case 'S': show_soname = 1; break; 1876 case 'S': show_soname = 1; break;
1432 case 'T': show_textrels = 1; break; 1877 case 'T': show_textrels = 1; break;
1433 default: 1878 default:
1434 err("Invalid format specifier '%c' (byte %i)", 1879 err("Invalid format specifier '%c' (byte %i)",
1435 out_format[i], i+1); 1880 out_format[i], i+1);
1436 } 1881 }
1437 } 1882 }
1438 1883
1439 /* construct our default format */ 1884 /* construct our default format */
1440 } else { 1885 } else {
1441 size_t fmt_len = 30; 1886 size_t fmt_len = 30;
1442 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1887 out_format = xmalloc(sizeof(char) * fmt_len);
1443 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1888 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1444 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1889 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1890 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1891 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1445 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1892 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1446 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1893 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1447 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1894 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1448 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1895 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1449 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1896 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1450 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1897 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1451 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1898 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1452 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1899 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1453 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1900 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1901 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1454 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1902 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1455 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1903 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1456 } 1904 }
1457 if (be_verbose > 2) printf("Format: %s\n", out_format); 1905 if (be_verbose > 2) printf("Format: %s\n", out_format);
1458 1906
1459 /* now lets actually do the scanning */ 1907 /* now lets actually do the scanning */
1460 if (scan_ldpath || use_ldcache) 1908 if (scan_ldpath || use_ldcache)
1461 load_ld_so_conf(); 1909 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1462 if (scan_ldpath) scanelf_ldpath(); 1910 if (scan_ldpath) scanelf_ldpath();
1463 if (scan_envpath) scanelf_envpath(); 1911 if (scan_envpath) scanelf_envpath();
1912 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1913 from_file = "-";
1464 if (from_file) { 1914 if (from_file) {
1465 scanelf_from_file(from_file); 1915 scanelf_from_file(from_file);
1466 from_file = *argv; 1916 from_file = *argv;
1467 } 1917 }
1468 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1918 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1469 err("Nothing to scan !?"); 1919 err("Nothing to scan !?");
1470 while (optind < argc) { 1920 while (optind < argc) {
1471 search_path = argv[optind++]; 1921 search_path = argv[optind++];
1472 scanelf_dir(search_path); 1922 ret = scanelf_dir(search_path);
1473 } 1923 }
1474 1924
1475 /* clean up */ 1925 /* clean up */
1476 if (versioned_symname) free(versioned_symname); 1926 free(versioned_symname);
1477 for (i = 0; ldpaths[i]; ++i) 1927 for (i = 0; ldpaths[i]; ++i)
1478 free(ldpaths[i]); 1928 free(ldpaths[i]);
1479 1929
1480 if (ldcache != 0) 1930 if (ldcache != 0)
1481 munmap(ldcache, ldcache_size); 1931 munmap(ldcache, ldcache_size);
1482}
1483
1484
1485
1486/* utility funcs */
1487static char *xstrdup(const char *s)
1488{
1489 char *ret = strdup(s);
1490 if (!ret) err("Could not strdup(): %s", strerror(errno));
1491 return ret; 1932 return ret;
1492} 1933}
1493static void *xmalloc(size_t size)
1494{
1495 void *ret = malloc(size);
1496 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1497 return ret;
1498}
1499static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1500{
1501 size_t new_len;
1502 1934
1503 new_len = strlen(*dst) + strlen(src); 1935static char **get_split_env(const char *envvar)
1504 if (*curr_len <= new_len) {
1505 *curr_len = new_len + (*curr_len / 2);
1506 *dst = realloc(*dst, *curr_len);
1507 if (!*dst)
1508 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1509 }
1510
1511 if (n)
1512 strncat(*dst, src, n);
1513 else
1514 strcat(*dst, src);
1515}
1516static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1517{ 1936{
1518 static char my_app[2]; 1937 const char *delims = " \t\n";
1519 my_app[0] = append; 1938 char **envvals = NULL;
1520 my_app[1] = '\0'; 1939 char *env, *s;
1521 xstrcat(dst, my_app, curr_len); 1940 int nentry;
1522}
1523 1941
1942 if ((env = getenv(envvar)) == NULL)
1943 return NULL;
1944
1945 env = xstrdup(env);
1946 if (env == NULL)
1947 return NULL;
1948
1949 s = strtok(env, delims);
1950 if (s == NULL) {
1951 free(env);
1952 return NULL;
1953 }
1954
1955 nentry = 0;
1956 while (s != NULL) {
1957 ++nentry;
1958 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1959 envvals[nentry-1] = s;
1960 s = strtok(NULL, delims);
1961 }
1962 envvals[nentry] = NULL;
1963
1964 /* don't want to free(env) as it contains the memory that backs
1965 * the envvals array of strings */
1966 return envvals;
1967}
1968
1969static void parseenv(void)
1970{
1971 qa_textrels = get_split_env("QA_TEXTRELS");
1972 qa_execstack = get_split_env("QA_EXECSTACK");
1973 qa_wx_load = get_split_env("QA_WX_LOAD");
1974}
1975
1976#ifdef __PAX_UTILS_CLEANUP
1977static void cleanup(void)
1978{
1979 free(out_format);
1980 free(qa_textrels);
1981 free(qa_execstack);
1982 free(qa_wx_load);
1983}
1984#endif
1524 1985
1525 1986
1526int main(int argc, char *argv[]) 1987int main(int argc, char *argv[])
1527{ 1988{
1989 int ret;
1528 if (argc < 2) 1990 if (argc < 2)
1529 usage(EXIT_FAILURE); 1991 usage(EXIT_FAILURE);
1992 parseenv();
1530 parseargs(argc, argv); 1993 ret = parseargs(argc, argv);
1531 fclose(stdout); 1994 fclose(stdout);
1532#ifdef __BOUNDS_CHECKING_ON 1995#ifdef __PAX_UTILS_CLEANUP
1533 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 1996 cleanup();
1997 warn("The calls to add/delete heap should be off:\n"
1998 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1999 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1534#endif 2000#endif
1535 return EXIT_SUCCESS; 2001 return ret;
1536} 2002}
2003
2004
2005/* Match filename against entries in matchlist, return TRUE
2006 * if the file is listed */
2007static int file_matches_list(const char *filename, char **matchlist)
2008{
2009 char **file;
2010 char *match;
2011 char buf[__PAX_UTILS_PATH_MAX];
2012
2013 if (matchlist == NULL)
2014 return 0;
2015
2016 for (file = matchlist; *file != NULL; file++) {
2017 if (search_path) {
2018 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2019 match = buf;
2020 } else {
2021 match = *file;
2022 }
2023 if (fnmatch(match, filename, 0) == 0)
2024 return 1;
2025 }
2026 return 0;
2027}

Legend:
Removed from v.1.109  
changed lines
  Added in v.1.188

  ViewVC Help
Powered by ViewVC 1.1.20