/[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.126 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.126 2006/02/16 05:47:23 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.126 2006/02/16 05:47:23 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 */
36static char match_etypes[126] = ""; 33static char match_etypes[126] = "";
37static char *ldpaths[256]; 34static char *ldpaths[256];
38static char scan_ldpath = 0; 35static char scan_ldpath = 0;
40static char scan_symlink = 1; 37static char scan_symlink = 1;
41static char scan_archives = 0; 38static char scan_archives = 0;
42static char dir_recurse = 0; 39static char dir_recurse = 0;
43static char dir_crossmount = 1; 40static char dir_crossmount = 1;
44static char show_pax = 0; 41static char show_pax = 0;
42static char show_perms = 0;
45static char show_phdr = 0; 43static char show_phdr = 0;
46static char show_textrel = 0; 44static char show_textrel = 0;
47static char show_rpath = 0; 45static char show_rpath = 0;
48static char show_needed = 0; 46static char show_needed = 0;
49static char show_interp = 0; 47static char show_interp = 0;
50static char show_bind = 0; 48static char show_bind = 0;
51static char show_soname = 0; 49static char show_soname = 0;
52static char show_textrels = 0; 50static char show_textrels = 0;
53static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
54static char be_quiet = 0; 53static char be_quiet = 0;
55static char be_verbose = 0; 54static char be_verbose = 0;
56static char be_very_quiet = 0; 55static char be_wewy_wewy_quiet = 0;
56static char be_semi_verbose = 0;
57static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
58static char *find_lib = NULL; 58static char *find_lib = NULL;
59static char *find_section = NULL; 59static char *find_section = NULL;
60static char *out_format = NULL; 60static char *out_format = NULL;
61static char *search_path = NULL; 61static char *search_path = NULL;
62static char fix_elf = 0; 62static char fix_elf = 0;
63static char gmatch = 0; 63static char g_match = 0;
64static char use_ldcache = 0; 64static char use_ldcache = 0;
65 65
66static char **qa_textrels = NULL;
67static char **qa_execstack = NULL;
68static char **qa_wx_load = NULL;
69
66int match_bits = 0; 70int match_bits = 0;
71unsigned int match_perms = 0;
67caddr_t ldcache = 0; 72caddr_t ldcache = 0;
68size_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}
69 140
70/* sub-funcs for scanelf_file() */ 141/* sub-funcs for scanelf_file() */
71static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 142static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
72{ 143{
73 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 144 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
92 } \ 163 } \
93 } 164 }
94 GET_SYMTABS(32) 165 GET_SYMTABS(32)
95 GET_SYMTABS(64) 166 GET_SYMTABS(64)
96} 167}
168
97static char *scanelf_file_pax(elfobj *elf, char *found_pax) 169static char *scanelf_file_pax(elfobj *elf, char *found_pax)
98{ 170{
99 static char ret[7]; 171 static char ret[7];
100 unsigned long i, shown; 172 unsigned long i, shown;
101 173
110 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 182 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
111 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 183 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
112 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 184 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
113 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 185 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
114 continue; \ 186 continue; \
115 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))) \
116 continue; \ 192 continue; \
117 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); \
118 *found_pax = 1; \ 194 *found_pax = 1; \
119 ++shown; \ 195 ++shown; \
120 break; \ 196 break; \
122 } 198 }
123 SHOW_PAX(32) 199 SHOW_PAX(32)
124 SHOW_PAX(64) 200 SHOW_PAX(64)
125 } 201 }
126 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 }
213 }
214
127 /* fall back to EI_PAX if no PT_PAX was found */ 215 /* fall back to EI_PAX if no PT_PAX was found */
128 if (!*ret) { 216 if (!*ret) {
129 static char *paxflags; 217 static char *paxflags;
130 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 218 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
131 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 219 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
132 *found_pax = 1; 220 *found_pax = 1;
133 return (be_very_quiet ? NULL : paxflags); 221 return (be_wewy_wewy_quiet ? NULL : paxflags);
134 } 222 }
135 strncpy(ret, paxflags, sizeof(ret)); 223 strncpy(ret, paxflags, sizeof(ret));
136 } 224 }
137 225
138 if (be_very_quiet || (be_quiet && !shown)) 226 if (be_wewy_wewy_quiet || (be_quiet && !shown))
139 return NULL; 227 return NULL;
140 else 228 else
141 return ret; 229 return ret;
142} 230}
143 231
164 uint32_t flags, check_flags; \ 252 uint32_t flags, check_flags; \
165 if (elf->phdr != NULL) { \ 253 if (elf->phdr != NULL) { \
166 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 254 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
167 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 255 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
168 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 256 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
257 if (multi_stack++) \
169 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; \
170 found = found_phdr; \ 261 found = found_phdr; \
171 offset = 0; \ 262 offset = 0; \
172 check_flags = PF_X; \ 263 check_flags = PF_X; \
173 } 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++) \
174 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 266 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
175 found = found_relro; \ 267 found = found_relro; \
176 offset = 4; \ 268 offset = 4; \
177 check_flags = PF_X; \ 269 check_flags = PF_X; \
178 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 270 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
179 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \ 271 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
272 if (multi_load++ > max_pt_load) \
180 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; \
181 found = found_load; \ 276 found = found_load; \
182 offset = 8; \ 277 offset = 8; \
183 check_flags = PF_W|PF_X; \ 278 check_flags = PF_W|PF_X; \
184 } else \ 279 } else \
185 continue; \ 280 continue; \
186 flags = EGET(phdr[i].p_flags); \ 281 flags = EGET(phdr[i].p_flags); \
187 if (be_quiet && ((flags & check_flags) != check_flags)) \ 282 if (be_quiet && ((flags & check_flags) != check_flags)) \
188 continue; \ 283 continue; \
189 if (fix_elf && ((flags & PF_X) != flags)) { \ 284 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
190 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \ 285 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
191 ret[3] = ret[7] = '!'; \ 286 ret[3] = ret[7] = '!'; \
192 flags = EGET(phdr[i].p_flags); \ 287 flags = EGET(phdr[i].p_flags); \
193 } \ 288 } \
194 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 289 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
222 break; \ 317 break; \
223 } \ 318 } \
224 } \ 319 } \
225 skip_this_shdr##B: \ 320 skip_this_shdr##B: \
226 if (!multi_stack) { \ 321 if (!multi_stack) { \
322 if (file_matches_list(elf->filename, qa_execstack)) \
323 return NULL; \
227 *found_phdr = 1; \ 324 *found_phdr = 1; \
228 shown = 1; \ 325 shown = 1; \
229 memcpy(ret, "!WX", 3); \ 326 memcpy(ret, "!WX", 3); \
230 } \ 327 } \
231 } \ 328 } \
232 } 329 }
233 SHOW_PHDR(32) 330 SHOW_PHDR(32)
234 SHOW_PHDR(64) 331 SHOW_PHDR(64)
235 332
236 if (be_very_quiet || (be_quiet && !shown)) 333 if (be_wewy_wewy_quiet || (be_quiet && !shown))
237 return NULL; 334 return NULL;
238 else 335 else
239 return ret; 336 return ret;
240} 337}
338
339/*
340 * See if this ELF contains a DT_TEXTREL tag in any of its
341 * PT_DYNAMIC sections.
342 */
241static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 343static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
242{ 344{
243 static const char *ret = "TEXTREL"; 345 static const char *ret = "TEXTREL";
244 unsigned long i; 346 unsigned long i;
245 347
246 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;
247 351
248 if (elf->phdr) { 352 if (elf->phdr) {
249#define SHOW_TEXTREL(B) \ 353#define SHOW_TEXTREL(B) \
250 if (elf->elf_class == ELFCLASS ## B) { \ 354 if (elf->elf_class == ELFCLASS ## B) { \
251 Elf ## B ## _Dyn *dyn; \ 355 Elf ## B ## _Dyn *dyn; \
252 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 356 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
253 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 357 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
254 Elf ## B ## _Off offset; \ 358 Elf ## B ## _Off offset; \
255 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 359 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
256 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; \
257 offset = EGET(phdr[i].p_offset); \ 361 offset = EGET(phdr[i].p_offset); \
258 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 362 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
259 dyn = DYN ## B (elf->data + offset); \ 363 dyn = DYN ## B (elf->data + offset); \
260 while (EGET(dyn->d_tag) != DT_NULL) { \ 364 while (EGET(dyn->d_tag) != DT_NULL) { \
261 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)*/ \
262 *found_textrel = 1; \ 366 *found_textrel = 1; \
263 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 367 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
264 return (be_very_quiet ? NULL : ret); \ 368 return (be_wewy_wewy_quiet ? NULL : ret); \
265 } \ 369 } \
266 ++dyn; \ 370 ++dyn; \
267 } \ 371 } \
268 } } 372 } }
269 SHOW_TEXTREL(32) 373 SHOW_TEXTREL(32)
270 SHOW_TEXTREL(64) 374 SHOW_TEXTREL(64)
271 } 375 }
272 376
273 if (be_quiet || be_very_quiet) 377 if (be_quiet || be_wewy_wewy_quiet)
274 return NULL; 378 return NULL;
275 else 379 else
276 return " - "; 380 return " - ";
277} 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 */
278static 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)
279{ 389{
280 unsigned long s, r, rmax; 390 unsigned long s, r, rmax;
281 void *symtab_void, *strtab_void, *text_void; 391 void *symtab_void, *strtab_void, *text_void;
282 392
349 /* show the raw details about this reloc */ \ 459 /* show the raw details about this reloc */ \
350 printf(" %s: ", elf->base_filename); \ 460 printf(" %s: ", elf->base_filename); \
351 if (sym && sym->st_name) \ 461 if (sym && sym->st_name) \
352 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))); \
353 else \ 463 else \
354 printf("(memory/fake?)"); \ 464 printf("(memory/data?)"); \
355 printf(" [0x%lX]", (unsigned long)r_offset); \ 465 printf(" [0x%lX]", (unsigned long)r_offset); \
356 /* 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 */ \
357 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 467 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
358 func = NULL; \ 468 func = NULL; \
359 offset_tmp = 0; \ 469 offset_tmp = 0; \
363 offset_tmp = EGET(sym->st_value); \ 473 offset_tmp = EGET(sym->st_value); \
364 } \ 474 } \
365 ++sym; \ 475 ++sym; \
366 } \ 476 } \
367 printf(" in "); \ 477 printf(" in "); \
368 if (func && func->st_name) \ 478 if (func && func->st_name) { \
369 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); \
370 else \ 482 else \
371 printf("(NULL: fake?)"); \ 483 printf("%s", func_name); \
484 } else \
485 printf("(optimized out)"); \
372 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 } \
373 } \ 507 } \
374 } } 508 } }
375 SHOW_TEXTRELS(32) 509 SHOW_TEXTRELS(32)
376 SHOW_TEXTRELS(64) 510 SHOW_TEXTRELS(64)
377 } 511 }
395 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 529 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
396 break; 530 break;
397 case '$': 531 case '$':
398 if (fstat(elf->fd, &st) != -1) 532 if (fstat(elf->fd, &st) != -1)
399 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 533 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
400 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",
401 dt_type, item, elf->filename, st.st_mode & 07777); 535 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
402 break; 536 break;
403 default: 537 default:
404 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);
405 break; 539 break;
406 } 540 }
426 Elf ## B ## _Off offset; \ 560 Elf ## B ## _Off offset; \
427 Elf ## B ## _Xword word; \ 561 Elf ## B ## _Xword word; \
428 /* Scan all the program headers */ \ 562 /* Scan all the program headers */ \
429 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 563 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
430 /* Just scan dynamic headers */ \ 564 /* Just scan dynamic headers */ \
431 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; \
432 offset = EGET(phdr[i].p_offset); \ 566 offset = EGET(phdr[i].p_offset); \
433 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 567 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
434 /* Just scan dynamic RPATH/RUNPATH headers */ \ 568 /* Just scan dynamic RPATH/RUNPATH headers */ \
435 dyn = DYN ## B (elf->data + offset); \ 569 dyn = DYN ## B (elf->data + offset); \
436 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 570 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
526 } } 660 } }
527 SHOW_RPATH(32) 661 SHOW_RPATH(32)
528 SHOW_RPATH(64) 662 SHOW_RPATH(64)
529 } 663 }
530 664
531 if (be_very_quiet) return; 665 if (be_wewy_wewy_quiet) return;
532 666
533 if (rpath && runpath) { 667 if (rpath && runpath) {
534 if (!strcmp(rpath, runpath)) { 668 if (!strcmp(rpath, runpath)) {
535 xstrcat(ret, runpath, ret_len); 669 xstrcat(ret, runpath, ret_len);
536 } else { 670 } else {
565#define FLAG_POWERPC_LIB64 0x0500 699#define FLAG_POWERPC_LIB64 0x0500
566#define FLAG_MIPS64_LIBN32 0x0600 700#define FLAG_MIPS64_LIBN32 0x0600
567#define FLAG_MIPS64_LIBN64 0x0700 701#define FLAG_MIPS64_LIBN64 0x0700
568 702
569static char *lookup_cache_lib(elfobj *, char *); 703static char *lookup_cache_lib(elfobj *, char *);
704
705#if defined(__GLIBC__) || defined(__UCLIBC__)
706
570static char *lookup_cache_lib(elfobj *elf, char *fname) 707static char *lookup_cache_lib(elfobj *elf, char *fname)
571{ 708{
572 int fd = 0; 709 int fd = 0;
573 char *strs; 710 char *strs;
574 static char buf[__PAX_UTILS_PATH_MAX] = ""; 711 static char buf[__PAX_UTILS_PATH_MAX] = "";
630 continue; 767 continue;
631 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 768 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
632 } 769 }
633 return buf; 770 return buf;
634} 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;
635 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
636 804
637static 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)
638{ 806{
639 unsigned long i; 807 unsigned long i;
640 char *needed; 808 char *needed;
652 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 820 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
653 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 821 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
654 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 822 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
655 Elf ## B ## _Off offset; \ 823 Elf ## B ## _Off offset; \
656 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 824 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
657 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; \
658 offset = EGET(phdr[i].p_offset); \ 826 offset = EGET(phdr[i].p_offset); \
659 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 827 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
660 dyn = DYN ## B (elf->data + offset); \ 828 dyn = DYN ## B (elf->data + offset); \
661 while (EGET(dyn->d_tag) != DT_NULL) { \ 829 while (EGET(dyn->d_tag) != DT_NULL) { \
662 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 830 if (EGET(dyn->d_tag) == DT_NEEDED) { \
665 ++dyn; \ 833 ++dyn; \
666 continue; \ 834 continue; \
667 } \ 835 } \
668 needed = (char*)(elf->data + offset); \ 836 needed = (char*)(elf->data + offset); \
669 if (op == 0) { \ 837 if (op == 0) { \
670 if (!be_very_quiet) { \ 838 if (!be_wewy_wewy_quiet) { \
671 if (*found_needed) xchrcat(ret, ',', ret_len); \ 839 if (*found_needed) xchrcat(ret, ',', ret_len); \
672 if (use_ldcache) \ 840 if (use_ldcache) \
673 if ((p = lookup_cache_lib(elf, needed)) != NULL) \ 841 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
674 needed = p; \ 842 needed = p; \
675 xstrcat(ret, needed, ret_len); \ 843 xstrcat(ret, needed, ret_len); \
676 } \ 844 } \
677 *found_needed = 1; \ 845 *found_needed = 1; \
678 } else { \ 846 } else { \
679 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 847 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
680 *found_lib = 1; \ 848 *found_lib = 1; \
681 return (be_very_quiet ? NULL : needed); \ 849 return (be_wewy_wewy_quiet ? NULL : needed); \
682 } \ 850 } \
683 } \ 851 } \
684 } \ 852 } \
685 ++dyn; \ 853 ++dyn; \
686 } \ 854 } \
704 if (strtbl_void) { 872 if (strtbl_void) {
705#define SHOW_INTERP(B) \ 873#define SHOW_INTERP(B) \
706 if (elf->elf_class == ELFCLASS ## B) { \ 874 if (elf->elf_class == ELFCLASS ## B) { \
707 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 875 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
708 *found_interp = 1; \ 876 *found_interp = 1; \
709 return (be_very_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \ 877 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
710 } 878 }
711 SHOW_INTERP(32) 879 SHOW_INTERP(32)
712 SHOW_INTERP(64) 880 SHOW_INTERP(64)
713 } 881 }
714 return NULL; 882 return NULL;
715} 883}
716static char *scanelf_file_bind(elfobj *elf, char *found_bind) 884static char *scanelf_file_bind(elfobj *elf, char *found_bind)
717{ 885{
718 unsigned long i; 886 unsigned long i;
719 struct stat s; 887 struct stat s;
888 char dynamic = 0;
720 889
721 if (!show_bind) return NULL; 890 if (!show_bind) return NULL;
722 if (!elf->phdr) return NULL; 891 if (!elf->phdr) return NULL;
723 892
724#define SHOW_BIND(B) \ 893#define SHOW_BIND(B) \
726 Elf ## B ## _Dyn *dyn; \ 895 Elf ## B ## _Dyn *dyn; \
727 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 896 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
728 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 897 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
729 Elf ## B ## _Off offset; \ 898 Elf ## B ## _Off offset; \
730 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 899 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
731 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; \
732 offset = EGET(phdr[i].p_offset); \ 902 offset = EGET(phdr[i].p_offset); \
733 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 903 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
734 dyn = DYN ## B (elf->data + offset); \ 904 dyn = DYN ## B (elf->data + offset); \
735 while (EGET(dyn->d_tag) != DT_NULL) { \ 905 while (EGET(dyn->d_tag) != DT_NULL) { \
736 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 906 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
737 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \ 907 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
738 { \ 908 { \
739 if (be_quiet) return NULL; \ 909 if (be_quiet) return NULL; \
740 *found_bind = 1; \ 910 *found_bind = 1; \
741 return (char *)(be_very_quiet ? NULL : "NOW"); \ 911 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
742 } \ 912 } \
743 ++dyn; \ 913 ++dyn; \
744 } \ 914 } \
745 } \ 915 } \
746 } 916 }
747 SHOW_BIND(32) 917 SHOW_BIND(32)
748 SHOW_BIND(64) 918 SHOW_BIND(64)
749 919
750 if (be_very_quiet) return NULL; 920 if (be_wewy_wewy_quiet) return NULL;
751 921
922 /* don't output anything if quiet mode and the ELF is static or not setuid */
752 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))))) {
753 return NULL; 924 return NULL;
754 } else { 925 } else {
755 *found_bind = 1; 926 *found_bind = 1;
756 return (char *) "LAZY"; 927 return (char *) (dynamic ? "LAZY" : "STATIC");
757 } 928 }
758} 929}
759static char *scanelf_file_soname(elfobj *elf, char *found_soname) 930static char *scanelf_file_soname(elfobj *elf, char *found_soname)
760{ 931{
761 unsigned long i; 932 unsigned long i;
773 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 944 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
774 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 945 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
775 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 946 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
776 Elf ## B ## _Off offset; \ 947 Elf ## B ## _Off offset; \
777 /* only look for soname in shared objects */ \ 948 /* only look for soname in shared objects */ \
778 if (ehdr->e_type != ET_DYN) \ 949 if (EGET(ehdr->e_type) != ET_DYN) \
779 return NULL; \ 950 return NULL; \
780 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 951 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
781 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; \
782 offset = EGET(phdr[i].p_offset); \ 953 offset = EGET(phdr[i].p_offset); \
783 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 954 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
784 dyn = DYN ## B (elf->data + offset); \ 955 dyn = DYN ## B (elf->data + offset); \
785 while (EGET(dyn->d_tag) != DT_NULL) { \ 956 while (EGET(dyn->d_tag) != DT_NULL) { \
786 if (EGET(dyn->d_tag) == DT_SONAME) { \ 957 if (EGET(dyn->d_tag) == DT_SONAME) { \
789 ++dyn; \ 960 ++dyn; \
790 continue; \ 961 continue; \
791 } \ 962 } \
792 soname = (char*)(elf->data + offset); \ 963 soname = (char*)(elf->data + offset); \
793 *found_soname = 1; \ 964 *found_soname = 1; \
794 return (be_very_quiet ? NULL : soname); \ 965 return (be_wewy_wewy_quiet ? NULL : soname); \
795 } \ 966 } \
796 ++dyn; \ 967 ++dyn; \
797 } \ 968 } \
798 } } 969 } }
799 SHOW_SONAME(32) 970 SHOW_SONAME(32)
800 SHOW_SONAME(64) 971 SHOW_SONAME(64)
801 } 972 }
802 973
803 return NULL; 974 return NULL;
804} 975}
976
805static char *scanelf_file_sym(elfobj *elf, char *found_sym) 977static char *scanelf_file_sym(elfobj *elf, char *found_sym)
806{ 978{
807 unsigned long i; 979 unsigned long i;
808 char *ret; 980 char *ret;
809 void *symtab_void, *strtab_void; 981 void *symtab_void, *strtab_void;
823 char *symname; \ 995 char *symname; \
824 if (cnt) \ 996 if (cnt) \
825 cnt = EGET(symtab->sh_size) / cnt; \ 997 cnt = EGET(symtab->sh_size) / cnt; \
826 for (i = 0; i < cnt; ++i) { \ 998 for (i = 0; i < cnt; ++i) { \
827 if (sym->st_name) { \ 999 if (sym->st_name) { \
1000 /* make sure the symbol name is in acceptable memory range */ \
828 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)); \
829 if ((void*)symname > (void*)elf->data_end) { \ 1002 if ((void*)symname > (void*)elf->data_end) { \
830 warnf("%s: corrupt ELF symbols", elf->filename); \ 1003 warnf("%s: corrupt ELF symbols", elf->filename); \
1004 ++sym; \
831 continue; \ 1005 continue; \
832 } \ 1006 } \
833 if (*find_sym == '*') { \ 1007 /* debug display ... show all symbols and some extra info */ \
1008 if (g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
834 printf("%s(%s) %5lX %15s %s\n", \ 1009 printf("%s(%s) %5lX %15s %s %s\n", \
835 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1010 ((*found_sym == 0) ? "\n\t" : "\t"), \
836 elf->base_filename, \ 1011 elf->base_filename, \
837 (unsigned long)sym->st_size, \ 1012 (unsigned long)sym->st_size, \
838 get_elfstttype(sym->st_info), \ 1013 get_elfstttype(sym->st_info), \
839 symname); \ 1014 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
840 *found_sym = 1; \ 1015 *found_sym = 1; \
841 } else { \ 1016 } else { \
1017 /* allow the user to specify a comma delimited list of symbols to search for */ \
842 char *this_sym, *next_sym; \ 1018 char *this_sym, *this_sym_ver, *next_sym; \
1019 this_sym = ret; \
843 this_sym = find_sym; \ 1020 this_sym_ver = versioned_symname; \
844 do { \ 1021 do { \
845 next_sym = strchr(this_sym, ','); \ 1022 next_sym = strchr(this_sym, ','); \
846 if (next_sym == NULL) \ 1023 if (next_sym == NULL) \
847 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 */ \
848 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') || \
849 (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 \
850 ret = this_sym; \ 1047 ret = this_sym; \
851 (*found_sym)++; \ 1048 (*found_sym)++; \
852 goto break_out; \ 1049 goto break_out; \
853 } \ 1050 } \
854 this_sym = next_sym + 1; \ 1051 skip_this_sym##B: this_sym = next_sym + 1; \
855 } while (*next_sym != '\0'); \ 1052 } while (*next_sym != '\0'); \
856 } \ 1053 } \
857 } \ 1054 } \
858 ++sym; \ 1055 ++sym; \
859 } } 1056 } }
860 FIND_SYM(32) 1057 FIND_SYM(32)
861 FIND_SYM(64) 1058 FIND_SYM(64)
862 } 1059 }
863 1060
864break_out: 1061break_out:
865 if (be_very_quiet) return NULL; 1062 if (be_wewy_wewy_quiet) return NULL;
866 1063
867 if (*find_sym != '*' && *found_sym) 1064 if (*find_sym != '*' && *found_sym)
868 return ret; 1065 return ret;
869 if (be_quiet) 1066 if (be_quiet)
870 return NULL; 1067 return NULL;
878 if (!find_section) 1075 if (!find_section)
879 return NULL; 1076 return NULL;
880 1077
881#define FIND_SECTION(B) \ 1078#define FIND_SECTION(B) \
882 if (elf->elf_class == ELFCLASS ## B) { \ 1079 if (elf->elf_class == ELFCLASS ## B) { \
1080 int invert; \
883 Elf ## B ## _Shdr *section; \ 1081 Elf ## B ## _Shdr *section; \
1082 invert = (*find_section == '!' ? 1 : 0); \
884 section = SHDR ## B (elf_findsecbyname(elf, find_section)); \ 1083 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
885 if (section != NULL) \ 1084 if ((section == NULL && invert) || (section != NULL && !invert)) \
886 *found_section = 1; \ 1085 *found_section = 1; \
887 } 1086 }
888 FIND_SECTION(32) 1087 FIND_SECTION(32)
889 FIND_SECTION(64) 1088 FIND_SECTION(64)
890 1089
891 1090 if (be_wewy_wewy_quiet)
892 if (be_very_quiet) return NULL; 1091 return NULL;
893 1092
894 if (*found_section) 1093 if (*found_section)
895 return find_section; 1094 return find_section;
896 1095
897 if (be_quiet) 1096 if (be_quiet)
903/* scan an elf file and show all the fun stuff */ 1102/* scan an elf file and show all the fun stuff */
904#define prints(str) write(fileno(stdout), str, strlen(str)) 1103#define prints(str) write(fileno(stdout), str, strlen(str))
905static int scanelf_elfobj(elfobj *elf) 1104static int scanelf_elfobj(elfobj *elf)
906{ 1105{
907 unsigned long i; 1106 unsigned long i;
908 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1107 char found_pax, found_phdr, found_relro, found_load, found_textrel,
909 found_rpath, found_needed, found_interp, found_bind, found_soname, 1108 found_rpath, found_needed, found_interp, found_bind, found_soname,
910 found_sym, found_lib, found_file, found_textrels, found_section; 1109 found_sym, found_lib, found_file, found_textrels, found_section;
911 static char *out_buffer = NULL; 1110 static char *out_buffer = NULL;
912 static size_t out_len; 1111 static size_t out_len;
913 1112
914 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1113 found_pax = found_phdr = found_relro = found_load = found_textrel = \
923 printf("%s: scanning file\n", elf->filename); 1122 printf("%s: scanning file\n", elf->filename);
924 1123
925 /* init output buffer */ 1124 /* init output buffer */
926 if (!out_buffer) { 1125 if (!out_buffer) {
927 out_len = sizeof(char) * 80; 1126 out_len = sizeof(char) * 80;
928 out_buffer = (char*)xmalloc(out_len); 1127 out_buffer = xmalloc(out_len);
929 } 1128 }
930 *out_buffer = '\0'; 1129 *out_buffer = '\0';
931 1130
932 /* show the header */ 1131 /* show the header */
933 if (!be_quiet && show_banner) { 1132 if (!be_quiet && show_banner) {
934 for (i = 0; out_format[i]; ++i) { 1133 for (i = 0; out_format[i]; ++i) {
935 if (!IS_MODIFIER(out_format[i])) continue; 1134 if (!IS_MODIFIER(out_format[i])) continue;
936 1135
937 switch (out_format[++i]) { 1136 switch (out_format[++i]) {
1137 case '+': break;
938 case '%': break; 1138 case '%': break;
939 case '#': break; 1139 case '#': break;
940 case 'F': 1140 case 'F':
941 case 'p': 1141 case 'p':
942 case 'f': prints("FILE "); found_file = 1; break; 1142 case 'f': prints("FILE "); found_file = 1; break;
943 case 'o': prints(" TYPE "); break; 1143 case 'o': prints(" TYPE "); break;
944 case 'x': prints(" PAX "); break; 1144 case 'x': prints(" PAX "); break;
945 case 'e': prints("STK/REL/PTL "); break; 1145 case 'e': prints("STK/REL/PTL "); break;
946 case 't': prints("TEXTREL "); break; 1146 case 't': prints("TEXTREL "); break;
947 case 'r': prints("RPATH "); break; 1147 case 'r': prints("RPATH "); break;
1148 case 'M': prints("CLASS "); break;
948 case 'n': prints("NEEDED "); break; 1149 case 'n': prints("NEEDED "); break;
949 case 'i': prints("INTERP "); break; 1150 case 'i': prints("INTERP "); break;
950 case 'b': prints("BIND "); break; 1151 case 'b': prints("BIND "); break;
951 case 'S': prints("SONAME "); break; 1152 case 'S': prints("SONAME "); break;
952 case 's': prints("SYM "); break; 1153 case 's': prints("SYM "); break;
953 case 'N': prints("LIB "); break; 1154 case 'N': prints("LIB "); break;
954 case 'T': prints("TEXTRELS "); break; 1155 case 'T': prints("TEXTRELS "); break;
955 case 'k': prints("SECTION "); 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;
956 default: warnf("'%c' has no title ?", out_format[i]); 1160 default: warnf("'%c' has no title ?", out_format[i]);
957 } 1161 }
958 } 1162 }
959 if (!found_file) prints("FILE "); 1163 if (!found_file) prints("FILE ");
960 prints("\n"); 1164 prints("\n");
971 xchrcat(&out_buffer, out_format[i], &out_len); 1175 xchrcat(&out_buffer, out_format[i], &out_len);
972 continue; 1176 continue;
973 } 1177 }
974 1178
975 out = NULL; 1179 out = NULL;
976 be_very_quiet = (out_format[i] == '#'); 1180 be_wewy_wewy_quiet = (out_format[i] == '#');
1181 be_semi_verbose = (out_format[i] == '+');
977 switch (out_format[++i]) { 1182 switch (out_format[++i]) {
1183 case '+':
978 case '%': 1184 case '%':
979 case '#': 1185 case '#':
980 xchrcat(&out_buffer, out_format[i], &out_len); break; 1186 xchrcat(&out_buffer, out_format[i], &out_len); break;
981 case 'F': 1187 case 'F':
982 found_file = 1; 1188 found_file = 1;
983 if (be_very_quiet) break; 1189 if (be_wewy_wewy_quiet) break;
984 xstrcat(&out_buffer, elf->filename, &out_len); 1190 xstrcat(&out_buffer, elf->filename, &out_len);
985 break; 1191 break;
986 case 'p': 1192 case 'p':
987 found_file = 1; 1193 found_file = 1;
988 if (be_very_quiet) break; 1194 if (be_wewy_wewy_quiet) break;
989 tmp = elf->filename; 1195 tmp = elf->filename;
990 if (search_path) { 1196 if (search_path) {
991 ssize_t len_search = strlen(search_path); 1197 ssize_t len_search = strlen(search_path);
992 ssize_t len_file = strlen(elf->filename); 1198 ssize_t len_file = strlen(elf->filename);
993 if (!strncmp(elf->filename, search_path, len_search) && \ 1199 if (!strncmp(elf->filename, search_path, len_search) && \
997 } 1203 }
998 xstrcat(&out_buffer, tmp, &out_len); 1204 xstrcat(&out_buffer, tmp, &out_len);
999 break; 1205 break;
1000 case 'f': 1206 case 'f':
1001 found_file = 1; 1207 found_file = 1;
1002 if (be_very_quiet) break; 1208 if (be_wewy_wewy_quiet) break;
1003 tmp = strrchr(elf->filename, '/'); 1209 tmp = strrchr(elf->filename, '/');
1004 tmp = (tmp == NULL ? elf->filename : tmp+1); 1210 tmp = (tmp == NULL ? elf->filename : tmp+1);
1005 xstrcat(&out_buffer, tmp, &out_len); 1211 xstrcat(&out_buffer, tmp, &out_len);
1006 break; 1212 break;
1007 case 'o': out = get_elfetype(elf); break; 1213 case 'o': out = get_elfetype(elf); break;
1008 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1214 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1009 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;
1010 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1216 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1011 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;
1012 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;
1013 case 'n': 1222 case 'n':
1014 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;
1015 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1224 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1016 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1225 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1017 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1226 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1018 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1227 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1019 case 'k': out = scanelf_file_sections(elf, &found_section); break; 1228 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1229 case 'a': out = get_elfemtype(elf); break;
1020 default: warnf("'%c' has no scan code?", out_format[i]); 1230 default: warnf("'%c' has no scan code?", out_format[i]);
1021 } 1231 }
1022 if (out) { 1232 if (out) {
1023 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1233 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1024 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1234 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1070 if (strlen(match_etypes)) { 1280 if (strlen(match_etypes)) {
1071 char sbuf[126]; 1281 char sbuf[126];
1072 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1282 strncpy(sbuf, match_etypes, sizeof(sbuf));
1073 if (strchr(match_etypes, ',') != NULL) { 1283 if (strchr(match_etypes, ',') != NULL) {
1074 char *p; 1284 char *p;
1075 while((p = strrchr(sbuf, ',')) != NULL) { 1285 while ((p = strrchr(sbuf, ',')) != NULL) {
1076 *p = 0; 1286 *p = 0;
1077 if (atoi(p+1) == get_etype(elf)) 1287 if (etype_lookup(p+1) == get_etype(elf))
1078 goto label_ret; 1288 goto label_ret;
1079 } 1289 }
1080 } 1290 }
1081 if (atoi(sbuf) != get_etype(elf)) 1291 if (etype_lookup(sbuf) != get_etype(elf))
1082 goto label_done; 1292 goto label_done;
1083 } 1293 }
1084 1294
1085label_ret: 1295label_ret:
1086 ret = scanelf_elfobj(elf); 1296 ret = scanelf_elfobj(elf);
1113 munmap(ar_buffer, len); 1323 munmap(ar_buffer, len);
1114 1324
1115 return 0; 1325 return 0;
1116} 1326}
1117/* 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 */
1118static void scanelf_file(const char *filename) 1328static int scanelf_file(const char *filename, const struct stat *st_cache)
1119{ 1329{
1330 const struct stat *st = st_cache;
1120 struct stat st; 1331 struct stat symlink_st;
1121 int fd; 1332 int fd;
1122 1333
1123 /* make sure 'filename' exists */
1124 if (lstat(filename, &st) == -1) {
1125 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1126 return;
1127 }
1128
1129 /* always handle regular files and handle symlinked files if no -y */ 1334 /* always handle regular files and handle symlinked files if no -y */
1130 if (S_ISLNK(st.st_mode)) { 1335 if (S_ISLNK(st->st_mode)) {
1131 if (!scan_symlink) return; 1336 if (!scan_symlink) return 1;
1132 stat(filename, &st); 1337 stat(filename, &symlink_st);
1338 st = &symlink_st;
1133 } 1339 }
1340
1134 if (!S_ISREG(st.st_mode)) { 1341 if (!S_ISREG(st->st_mode)) {
1135 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1342 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1136 return; 1343 return 1;
1137 } 1344 }
1138 1345
1346 if (match_perms) {
1347 if ((st->st_mode | match_perms) != st->st_mode)
1348 return 1;
1349 }
1139 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1350 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1140 return; 1351 return 1;
1141 1352
1142 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1353 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1143 /* 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 */
1144 scanelf_archive(filename, fd, st.st_size); 1355 scanelf_archive(filename, fd, st->st_size);
1145 1356
1146 close(fd); 1357 close(fd);
1358 return 0;
1147} 1359}
1148 1360
1149/* 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 */
1150static void scanelf_dir(const char *path) 1362static int scanelf_dir(const char *path)
1151{ 1363{
1152 register DIR *dir; 1364 register DIR *dir;
1153 register struct dirent *dentry; 1365 register struct dirent *dentry;
1154 struct stat st_top, st; 1366 struct stat st_top, st;
1155 char buf[__PAX_UTILS_PATH_MAX]; 1367 char buf[__PAX_UTILS_PATH_MAX];
1156 size_t pathlen = 0, len = 0; 1368 size_t pathlen = 0, len = 0;
1369 int ret = 0;
1157 1370
1158 /* make sure path exists */ 1371 /* make sure path exists */
1159 if (lstat(path, &st_top) == -1) { 1372 if (lstat(path, &st_top) == -1) {
1160 if (be_verbose > 2) printf("%s: does not exist\n", path); 1373 if (be_verbose > 2) printf("%s: does not exist\n", path);
1161 return; 1374 return 1;
1162 } 1375 }
1163 1376
1164 /* 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 */
1165 if (!S_ISDIR(st_top.st_mode)) { 1378 if (!S_ISDIR(st_top.st_mode)) {
1166 scanelf_file(path); 1379 return scanelf_file(path, &st_top);
1167 return;
1168 } 1380 }
1169 1381
1170 /* now scan the dir looking for fun stuff */ 1382 /* now scan the dir looking for fun stuff */
1171 if ((dir = opendir(path)) == NULL) { 1383 if ((dir = opendir(path)) == NULL) {
1172 warnf("could not opendir %s: %s", path, strerror(errno)); 1384 warnf("could not opendir %s: %s", path, strerror(errno));
1173 return; 1385 return 1;
1174 } 1386 }
1175 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1387 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1176 1388
1177 pathlen = strlen(path); 1389 pathlen = strlen(path);
1178 while ((dentry = readdir(dir))) { 1390 while ((dentry = readdir(dir))) {
1182 if (len >= sizeof(buf)) { 1394 if (len >= sizeof(buf)) {
1183 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1395 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1184 (unsigned long)len, (unsigned long)sizeof(buf)); 1396 (unsigned long)len, (unsigned long)sizeof(buf));
1185 continue; 1397 continue;
1186 } 1398 }
1187 sprintf(buf, "%s/%s", path, dentry->d_name); 1399 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1188 if (lstat(buf, &st) != -1) { 1400 if (lstat(buf, &st) != -1) {
1189 if (S_ISREG(st.st_mode)) 1401 if (S_ISREG(st.st_mode))
1190 scanelf_file(buf); 1402 ret = scanelf_file(buf, &st);
1191 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1403 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1192 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1404 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1193 scanelf_dir(buf); 1405 ret = scanelf_dir(buf);
1194 } 1406 }
1195 } 1407 }
1196 } 1408 }
1197 closedir(dir); 1409 closedir(dir);
1410 return ret;
1198} 1411}
1199 1412
1200static int scanelf_from_file(char *filename) 1413static int scanelf_from_file(const char *filename)
1201{ 1414{
1202 FILE *fp = NULL; 1415 FILE *fp = NULL;
1203 char *p; 1416 char *p;
1204 char path[__PAX_UTILS_PATH_MAX]; 1417 char path[__PAX_UTILS_PATH_MAX];
1418 int ret = 0;
1205 1419
1206 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1420 if (strcmp(filename, "-") == 0)
1207 fp = stdin; 1421 fp = stdin;
1208 else if ((fp = fopen(filename, "r")) == NULL) 1422 else if ((fp = fopen(filename, "r")) == NULL)
1209 return 1; 1423 return 1;
1210 1424
1211 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1425 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1212 if ((p = strchr(path, '\n')) != NULL) 1426 if ((p = strchr(path, '\n')) != NULL)
1213 *p = 0; 1427 *p = 0;
1214 search_path = path; 1428 search_path = path;
1215 scanelf_dir(path); 1429 ret = scanelf_dir(path);
1216 } 1430 }
1217 if (fp != stdin) 1431 if (fp != stdin)
1218 fclose(fp); 1432 fclose(fp);
1219 return 0; 1433 return ret;
1220} 1434}
1221 1435
1436#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1437
1222static int load_ld_so_conf(int i, const char *fname) 1438static int load_ld_cache_config(int i, const char *fname)
1223{ 1439{
1224 FILE *fp = NULL; 1440 FILE *fp = NULL;
1225 char *p; 1441 char *p;
1226 char path[__PAX_UTILS_PATH_MAX]; 1442 char path[__PAX_UTILS_PATH_MAX];
1227 1443
1228 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1444 if (i + 1 == ARRAY_SIZE(ldpaths))
1229 return i; 1445 return i;
1230 1446
1231 if ((fp = fopen(fname, "r")) == NULL) 1447 if ((fp = fopen(fname, "r")) == NULL)
1232 return i; 1448 return i;
1233 1449
1234 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1450 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1235 if ((p = strrchr(path, '\r')) != NULL) 1451 if ((p = strrchr(path, '\r')) != NULL)
1236 *p = 0; 1452 *p = 0;
1237 if ((p = strchr(path, '\n')) != NULL) 1453 if ((p = strchr(path, '\n')) != NULL)
1238 *p = 0; 1454 *p = 0;
1239#ifdef HAVE_GLOB 1455#ifdef __linux__
1240 // recursive includes of the same file will make this segfault. 1456 /* recursive includes of the same file will make this segfault. */
1241 if ((*path == 'i') && (strncmp(path, "include", 7) == 0) && isblank(path[7])) { 1457 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1242 glob64_t gl; 1458 glob64_t gl;
1243 size_t x; 1459 size_t x;
1244 char gpath[__PAX_UTILS_PATH_MAX]; 1460 char gpath[__PAX_UTILS_PATH_MAX];
1245 1461
1246 gpath[sizeof(gpath)] = 0; 1462 memset(gpath, 0, sizeof(gpath));
1247 1463
1248 if (path[8] != '/') 1464 if (path[8] != '/')
1249 snprintf(gpath, sizeof(gpath)-1, "/etc/%s", &path[8]); 1465 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1250 else 1466 else
1251 strncpy(gpath, &path[8], sizeof(gpath)-1); 1467 strncpy(gpath, &path[8], sizeof(gpath));
1252 1468
1253 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1469 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1254 for (x = 0; x < gl.gl_pathc; ++x) { 1470 for (x = 0; x < gl.gl_pathc; ++x) {
1255 /* try to avoid direct loops */ 1471 /* try to avoid direct loops */
1256 if (strcmp(gl.gl_pathv[x], fname) == 0) 1472 if (strcmp(gl.gl_pathv[x], fname) == 0)
1257 continue; 1473 continue;
1258 i = load_ld_so_conf(i, gl.gl_pathv[x]); 1474 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1259 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) { 1475 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1260 globfree64(&gl); 1476 globfree64(&gl);
1261 return i; 1477 return i;
1262 } 1478 }
1263 } 1479 }
1264 globfree64 (&gl); 1480 globfree64 (&gl);
1265 continue; 1481 continue;
1266 } else 1482 }
1267 abort();
1268 } 1483 }
1269#endif 1484#endif
1270 if (*path != '/') 1485 if (*path != '/')
1271 continue; 1486 continue;
1272 1487
1273 ldpaths[i++] = xstrdup(path); 1488 ldpaths[i++] = xstrdup(path);
1274 1489
1275 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1490 if (i + 1 == ARRAY_SIZE(ldpaths))
1276 break; 1491 break;
1277 } 1492 }
1278 ldpaths[i] = NULL; 1493 ldpaths[i] = NULL;
1279 1494
1280 fclose(fp); 1495 fclose(fp);
1281 return i; 1496 return i;
1282} 1497}
1283 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
1551
1284/* scan /etc/ld.so.conf for paths */ 1552/* scan /etc/ld.so.conf for paths */
1285static void scanelf_ldpath() 1553static void scanelf_ldpath(void)
1286{ 1554{
1287 char scan_l, scan_ul, scan_ull; 1555 char scan_l, scan_ul, scan_ull;
1288 int i = 0; 1556 int i = 0;
1289 1557
1290 if (!ldpaths[0]) 1558 if (!ldpaths[0])
1304 if (!scan_ul) scanelf_dir("/usr/lib"); 1572 if (!scan_ul) scanelf_dir("/usr/lib");
1305 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1573 if (!scan_ull) scanelf_dir("/usr/local/lib");
1306} 1574}
1307 1575
1308/* scan env PATH for paths */ 1576/* scan env PATH for paths */
1309static void scanelf_envpath() 1577static void scanelf_envpath(void)
1310{ 1578{
1311 char *path, *p; 1579 char *path, *p;
1312 1580
1313 path = getenv("PATH"); 1581 path = getenv("PATH");
1314 if (!path) 1582 if (!path)
1322 1590
1323 free(path); 1591 free(path);
1324} 1592}
1325 1593
1326 1594
1327/* 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 */
1328#define PARSE_FLAGS "plRmyAXxetrnLibSs:k:gN:TaqvF:f:o:M:E:BhV" 1596#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DO:BhV"
1329#define a_argument required_argument 1597#define a_argument required_argument
1330static struct option const long_opts[] = { 1598static struct option const long_opts[] = {
1331 {"path", no_argument, NULL, 'p'}, 1599 {"path", no_argument, NULL, 'p'},
1332 {"ldpath", no_argument, NULL, 'l'}, 1600 {"ldpath", no_argument, NULL, 'l'},
1333 {"recursive", no_argument, NULL, 'R'}, 1601 {"recursive", no_argument, NULL, 'R'},
1334 {"mount", no_argument, NULL, 'm'}, 1602 {"mount", no_argument, NULL, 'm'},
1335 {"symlink", no_argument, NULL, 'y'}, 1603 {"symlink", no_argument, NULL, 'y'},
1336 {"archives", no_argument, NULL, 'A'}, 1604 {"archives", no_argument, NULL, 'A'},
1337 {"ldcache", no_argument, NULL, 'L'}, 1605 {"ldcache", no_argument, NULL, 'L'},
1338 {"fix", no_argument, NULL, 'X'}, 1606 {"fix", no_argument, NULL, 'X'},
1607 {"setpax", a_argument, NULL, 'z'},
1339 {"pax", no_argument, NULL, 'x'}, 1608 {"pax", no_argument, NULL, 'x'},
1340 {"header", no_argument, NULL, 'e'}, 1609 {"header", no_argument, NULL, 'e'},
1341 {"textrel", no_argument, NULL, 't'}, 1610 {"textrel", no_argument, NULL, 't'},
1342 {"rpath", no_argument, NULL, 'r'}, 1611 {"rpath", no_argument, NULL, 'r'},
1343 {"needed", no_argument, NULL, 'n'}, 1612 {"needed", no_argument, NULL, 'n'},
1349 {"lib", a_argument, NULL, 'N'}, 1618 {"lib", a_argument, NULL, 'N'},
1350 {"gmatch", no_argument, NULL, 'g'}, 1619 {"gmatch", no_argument, NULL, 'g'},
1351 {"textrels", no_argument, NULL, 'T'}, 1620 {"textrels", no_argument, NULL, 'T'},
1352 {"etype", a_argument, NULL, 'E'}, 1621 {"etype", a_argument, NULL, 'E'},
1353 {"bits", a_argument, NULL, 'M'}, 1622 {"bits", a_argument, NULL, 'M'},
1623 {"endian", no_argument, NULL, 'D'},
1624 {"perms", a_argument, NULL, 'O'},
1354 {"all", no_argument, NULL, 'a'}, 1625 {"all", no_argument, NULL, 'a'},
1355 {"quiet", no_argument, NULL, 'q'}, 1626 {"quiet", no_argument, NULL, 'q'},
1356 {"verbose", no_argument, NULL, 'v'}, 1627 {"verbose", no_argument, NULL, 'v'},
1357 {"format", a_argument, NULL, 'F'}, 1628 {"format", a_argument, NULL, 'F'},
1358 {"from", a_argument, NULL, 'f'}, 1629 {"from", a_argument, NULL, 'f'},
1369 "Scan directories recursively", 1640 "Scan directories recursively",
1370 "Don't recursively cross mount points", 1641 "Don't recursively cross mount points",
1371 "Don't scan symlinks", 1642 "Don't scan symlinks",
1372 "Scan archives (.a files)", 1643 "Scan archives (.a files)",
1373 "Utilize ld.so.cache information (use with -r/-n)", 1644 "Utilize ld.so.cache information (use with -r/-n)",
1374 "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",
1375 "Print PaX markings", 1647 "Print PaX markings",
1376 "Print GNU_STACK/PT_LOAD markings", 1648 "Print GNU_STACK/PT_LOAD markings",
1377 "Print TEXTREL information", 1649 "Print TEXTREL information",
1378 "Print RPATH information", 1650 "Print RPATH information",
1379 "Print NEEDED information", 1651 "Print NEEDED information",
1383 "Find a specified symbol", 1655 "Find a specified symbol",
1384 "Find a specified section", 1656 "Find a specified section",
1385 "Find a specified library", 1657 "Find a specified library",
1386 "Use strncmp to match libraries. (use with -N)", 1658 "Use strncmp to match libraries. (use with -N)",
1387 "Locate cause of TEXTREL", 1659 "Locate cause of TEXTREL",
1388 "Print only ELF files matching numeric constant type", 1660 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1389 "Print only ELF files matching numeric bits", 1661 "Print only ELF files matching numeric bits",
1662 "Print Endianness",
1663 "Print only ELF files matching octal permissions",
1390 "Print all scanned info (-x -e -t -r -b)\n", 1664 "Print all scanned info (-x -e -t -r -b)\n",
1391 "Only output 'bad' things", 1665 "Only output 'bad' things",
1392 "Be verbose (can be specified more than once)", 1666 "Be verbose (can be specified more than once)",
1393 "Use specified format for output", 1667 "Use specified format for output",
1394 "Read input stream from a filename", 1668 "Read input stream from a filename",
1406 printf("* Scan ELF binaries for stuff\n\n" 1680 printf("* Scan ELF binaries for stuff\n\n"
1407 "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);
1408 printf("Options: -[%s]\n", PARSE_FLAGS); 1682 printf("Options: -[%s]\n", PARSE_FLAGS);
1409 for (i = 0; long_opts[i].name; ++i) 1683 for (i = 0; long_opts[i].name; ++i)
1410 if (long_opts[i].has_arg == no_argument) 1684 if (long_opts[i].has_arg == no_argument)
1411 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 1685 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1412 long_opts[i].name, opts_help[i]); 1686 long_opts[i].name, opts_help[i]);
1413 else 1687 else
1414 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 1688 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1415 long_opts[i].name, opts_help[i]); 1689 long_opts[i].name, opts_help[i]);
1416 1690
1417 if (status != EXIT_SUCCESS) 1691 puts("\nFor more information, see the scanelf(1) manpage");
1418 exit(status);
1419
1420 puts("\nThe format modifiers for the -F option are:");
1421 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1422 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1423 puts(" i INTERP \tb BIND \ts symbol");
1424 puts(" N library \to Type \tT TEXTRELs");
1425 puts(" S SONAME \tk section");
1426 puts(" p filename (with search path removed)");
1427 puts(" f filename (short name/basename)");
1428 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1429
1430 puts("\nELF Etypes:");
1431 print_etypes(stdout);
1432
1433 exit(status); 1692 exit(status);
1434} 1693}
1435 1694
1436/* 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 }
1437static void parseargs(int argc, char *argv[]) 1704static int parseargs(int argc, char *argv[])
1438{ 1705{
1439 int i; 1706 int i;
1440 char *from_file = NULL; 1707 const char *from_file = NULL;
1708 int ret = 0;
1441 1709
1442 opterr = 0; 1710 opterr = 0;
1443 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) {
1444 switch (i) { 1712 switch (i) {
1445 1713
1457 case 'E': 1725 case 'E':
1458 strncpy(match_etypes, optarg, sizeof(match_etypes)); 1726 strncpy(match_etypes, optarg, sizeof(match_etypes));
1459 break; 1727 break;
1460 case 'M': 1728 case 'M':
1461 match_bits = atoi(optarg); 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;
1462 break; 1740 break;
1463 case 'o': { 1741 case 'o': {
1464 FILE *fp = NULL;
1465 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1742 if (freopen(optarg, "w", stdout) == NULL)
1466 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1743 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1467 SET_STDOUT(fp);
1468 break; 1744 break;
1469 } 1745 }
1470 case 'k': 1746 case 'k':
1471 if (find_section) warn("You prob don't want to specify -k twice"); 1747 if (find_section) warn("You prob don't want to specify -k twice");
1472 find_section = optarg; 1748 find_section = optarg;
1473 break; 1749 break;
1474 case 's': { 1750 case 's': {
1475 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");
1476 find_sym = optarg; 1752 find_sym = optarg;
1477 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1753 versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1478 sprintf(versioned_symname, "%s@", find_sym); 1754 sprintf(versioned_symname, "%s@", find_sym);
1479 break; 1755 break;
1480 } 1756 }
1481 case 'N': { 1757 case 'N': {
1482 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");
1487 case 'F': { 1763 case 'F': {
1488 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");
1489 out_format = optarg; 1765 out_format = optarg;
1490 break; 1766 break;
1491 } 1767 }
1768 case 'z': {
1769 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1770 size_t x;
1492 1771
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 }
1493 case 'g': gmatch = 1; break; 1811 case 'g': g_match = 1; break;
1494 case 'L': use_ldcache = 1; break; 1812 case 'L': use_ldcache = 1; break;
1495 case 'y': scan_symlink = 0; break; 1813 case 'y': scan_symlink = 0; break;
1496 case 'A': scan_archives = 1; break; 1814 case 'A': scan_archives = 1; break;
1497 case 'B': show_banner = 0; break; 1815 case 'B': show_banner = 0; break;
1498 case 'l': scan_ldpath = 1; break; 1816 case 'l': scan_ldpath = 1; break;
1509 case 'b': show_bind = 1; break; 1827 case 'b': show_bind = 1; break;
1510 case 'S': show_soname = 1; break; 1828 case 'S': show_soname = 1; break;
1511 case 'T': show_textrels = 1; break; 1829 case 'T': show_textrels = 1; break;
1512 case 'q': be_quiet = 1; break; 1830 case 'q': be_quiet = 1; break;
1513 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1831 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1514 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;
1515 1833 case 'D': show_endian = 1; break;
1516 case ':': 1834 case ':':
1517 err("Option '%c' is missing parameter", optopt); 1835 err("Option '%c' is missing parameter", optopt);
1518 case '?': 1836 case '?':
1519 err("Unknown option '%c' or argument missing", optopt); 1837 err("Unknown option '%c' or argument missing", optopt);
1520 default: 1838 default:
1521 err("Unhandled option '%c'; please report this", i); 1839 err("Unhandled option '%c'; please report this", i);
1522 } 1840 }
1523 } 1841 }
1524 1842 if (show_textrels && be_verbose) {
1843 if (which("objdump") != NULL)
1844 has_objdump = 1;
1845 }
1525 /* let the format option override all other options */ 1846 /* let the format option override all other options */
1526 if (out_format) { 1847 if (out_format) {
1527 show_pax = show_phdr = show_textrel = show_rpath = \ 1848 show_pax = show_phdr = show_textrel = show_rpath = \
1528 show_needed = show_interp = show_bind = show_soname = \ 1849 show_needed = show_interp = show_bind = show_soname = \
1529 show_textrels = 0; 1850 show_textrels = show_perms = show_endian = 0;
1530 for (i = 0; out_format[i]; ++i) { 1851 for (i = 0; out_format[i]; ++i) {
1531 if (!IS_MODIFIER(out_format[i])) continue; 1852 if (!IS_MODIFIER(out_format[i])) continue;
1532 1853
1533 switch (out_format[++i]) { 1854 switch (out_format[++i]) {
1855 case '+': break;
1534 case '%': break; 1856 case '%': break;
1535 case '#': break; 1857 case '#': break;
1536 case 'F': break; 1858 case 'F': break;
1537 case 'p': break; 1859 case 'p': break;
1538 case 'f': break; 1860 case 'f': break;
1539 case 'k': break; 1861 case 'k': break;
1540 case 's': break; 1862 case 's': break;
1541 case 'N': break; 1863 case 'N': break;
1542 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;
1543 case 'x': show_pax = 1; break; 1869 case 'x': show_pax = 1; break;
1544 case 'e': show_phdr = 1; break; 1870 case 'e': show_phdr = 1; break;
1545 case 't': show_textrel = 1; break; 1871 case 't': show_textrel = 1; break;
1546 case 'r': show_rpath = 1; break; 1872 case 'r': show_rpath = 1; break;
1547 case 'n': show_needed = 1; break; 1873 case 'n': show_needed = 1; break;
1548 case 'i': show_interp = 1; break; 1874 case 'i': show_interp = 1; break;
1549 case 'b': show_bind = 1; break; 1875 case 'b': show_bind = 1; break;
1550 case 'S': show_soname = 1; break; 1876 case 'S': show_soname = 1; break;
1551 case 'T': show_textrels = 1; break; 1877 case 'T': show_textrels = 1; break;
1552 default: 1878 default:
1553 err("Invalid format specifier '%c' (byte %i)", 1879 err("Invalid format specifier '%c' (byte %i)",
1554 out_format[i], i+1); 1880 out_format[i], i+1);
1555 } 1881 }
1556 } 1882 }
1557 1883
1558 /* construct our default format */ 1884 /* construct our default format */
1559 } else { 1885 } else {
1560 size_t fmt_len = 30; 1886 size_t fmt_len = 30;
1561 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1887 out_format = xmalloc(sizeof(char) * fmt_len);
1562 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1888 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1563 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);
1564 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1892 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1565 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1893 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1566 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1894 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1567 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1895 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1568 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1896 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1576 } 1904 }
1577 if (be_verbose > 2) printf("Format: %s\n", out_format); 1905 if (be_verbose > 2) printf("Format: %s\n", out_format);
1578 1906
1579 /* now lets actually do the scanning */ 1907 /* now lets actually do the scanning */
1580 if (scan_ldpath || use_ldcache) 1908 if (scan_ldpath || use_ldcache)
1581 load_ld_so_conf(0, "/etc/ld.so.conf"); 1909 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1582 if (scan_ldpath) scanelf_ldpath(); 1910 if (scan_ldpath) scanelf_ldpath();
1583 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 = "-";
1584 if (from_file) { 1914 if (from_file) {
1585 scanelf_from_file(from_file); 1915 scanelf_from_file(from_file);
1586 from_file = *argv; 1916 from_file = *argv;
1587 } 1917 }
1588 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1918 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1589 err("Nothing to scan !?"); 1919 err("Nothing to scan !?");
1590 while (optind < argc) { 1920 while (optind < argc) {
1591 search_path = argv[optind++]; 1921 search_path = argv[optind++];
1592 scanelf_dir(search_path); 1922 ret = scanelf_dir(search_path);
1593 } 1923 }
1594 1924
1595 /* clean up */ 1925 /* clean up */
1596 if (versioned_symname) free(versioned_symname); 1926 free(versioned_symname);
1597 for (i = 0; ldpaths[i]; ++i) 1927 for (i = 0; ldpaths[i]; ++i)
1598 free(ldpaths[i]); 1928 free(ldpaths[i]);
1599 1929
1600 if (ldcache != 0) 1930 if (ldcache != 0)
1601 munmap(ldcache, ldcache_size); 1931 munmap(ldcache, ldcache_size);
1602}
1603
1604
1605
1606/* utility funcs */
1607static char *xstrdup(const char *s)
1608{
1609 char *ret = strdup(s);
1610 if (!ret) err("Could not strdup(): %s", strerror(errno));
1611 return ret; 1932 return ret;
1612} 1933}
1613static void *xmalloc(size_t size)
1614{
1615 void *ret = malloc(size);
1616 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1617 return ret;
1618}
1619static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1620{
1621 size_t new_len;
1622 1934
1623 new_len = strlen(*dst) + strlen(src); 1935static char **get_split_env(const char *envvar)
1624 if (*curr_len <= new_len) {
1625 *curr_len = new_len + (*curr_len / 2);
1626 *dst = realloc(*dst, *curr_len);
1627 if (!*dst)
1628 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1629 }
1630
1631 if (n)
1632 strncat(*dst, src, n);
1633 else
1634 strcat(*dst, src);
1635}
1636static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1637{ 1936{
1638 static char my_app[2]; 1937 const char *delims = " \t\n";
1639 my_app[0] = append; 1938 char **envvals = NULL;
1640 my_app[1] = '\0'; 1939 char *env, *s;
1641 xstrcat(dst, my_app, curr_len); 1940 int nentry;
1642}
1643 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
1644 1985
1645 1986
1646int main(int argc, char *argv[]) 1987int main(int argc, char *argv[])
1647{ 1988{
1989 int ret;
1648 if (argc < 2) 1990 if (argc < 2)
1649 usage(EXIT_FAILURE); 1991 usage(EXIT_FAILURE);
1992 parseenv();
1650 parseargs(argc, argv); 1993 ret = parseargs(argc, argv);
1651 fclose(stdout); 1994 fclose(stdout);
1652#ifdef __BOUNDS_CHECKING_ON 1995#ifdef __PAX_UTILS_CLEANUP
1653 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");
1654#endif 2000#endif
1655 return EXIT_SUCCESS; 2001 return ret;
1656} 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.126  
changed lines
  Added in v.1.188

  ViewVC Help
Powered by ViewVC 1.1.20