/[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.127 Revision 1.209
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.127 2006/02/17 07:13:54 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.209 2009/03/15 08:53:29 vapier 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.209 2009/03/15 08:53:29 vapier 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.127 2006/02/17 07:13:54 solar 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;
43static char show_size = 0;
45static char show_phdr = 0; 44static char show_phdr = 0;
46static char show_textrel = 0; 45static char show_textrel = 0;
47static char show_rpath = 0; 46static char show_rpath = 0;
48static char show_needed = 0; 47static char show_needed = 0;
49static char show_interp = 0; 48static char show_interp = 0;
50static char show_bind = 0; 49static char show_bind = 0;
51static char show_soname = 0; 50static char show_soname = 0;
52static char show_textrels = 0; 51static char show_textrels = 0;
53static char show_banner = 1; 52static char show_banner = 1;
53static char show_endian = 0;
54static char show_osabi = 0;
55static char show_eabi = 0;
54static char be_quiet = 0; 56static char be_quiet = 0;
55static char be_verbose = 0; 57static char be_verbose = 0;
56static char be_wewy_wewy_quiet = 0; 58static char be_wewy_wewy_quiet = 0;
57static char *find_sym = NULL, *versioned_symname = NULL; 59static char be_semi_verbose = 0;
60static char *find_sym = NULL;
58static char *find_lib = NULL; 61static char *find_lib = NULL;
59static char *find_section = NULL; 62static char *find_section = NULL;
60static char *out_format = NULL; 63static char *out_format = NULL;
61static char *search_path = NULL; 64static char *search_path = NULL;
62static char fix_elf = 0; 65static char fix_elf = 0;
63static char gmatch = 0; 66static char g_match = 0;
64static char use_ldcache = 0; 67static char use_ldcache = 0;
65 68
69static char **qa_textrels = NULL;
70static char **qa_execstack = NULL;
71static char **qa_wx_load = NULL;
72
66int match_bits = 0; 73static int match_bits = 0;
74static unsigned int match_perms = 0;
67caddr_t ldcache = 0; 75static caddr_t ldcache = 0;
68size_t ldcache_size = 0; 76static size_t ldcache_size = 0;
69unsigned long setpax = 0UL; 77static unsigned long setpax = 0UL;
78
79static int has_objdump = 0;
80
81/* find the path to a file by name */
82static char *which(const char *fname)
83{
84 static char fullpath[__PAX_UTILS_PATH_MAX];
85 char *path, *p;
86
87 path = getenv("PATH");
88 if (!path)
89 return NULL;
90
91 path = xstrdup(path);
92 while ((p = strrchr(path, ':')) != NULL) {
93 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
94 *p = 0;
95 if (access(fullpath, R_OK) != -1) {
96 free(path);
97 return fullpath;
98 }
99 }
100 free(path);
101 return NULL;
102}
103
104/* 1 on failure. 0 otherwise */
105static int rematch(const char *regex, const char *match, int cflags)
106{
107 regex_t preg;
108 int ret;
109
110 if ((match == NULL) || (regex == NULL))
111 return EXIT_FAILURE;
112
113 if ((ret = regcomp(&preg, regex, cflags))) {
114 char err[256];
115
116 if (regerror(ret, &preg, err, sizeof(err)))
117 fprintf(stderr, "regcomp failed: %s", err);
118 else
119 fprintf(stderr, "regcomp failed");
120
121 return EXIT_FAILURE;
122 }
123 ret = regexec(&preg, match, 0, NULL, 0);
124 regfree(&preg);
125
126 return ret;
127}
70 128
71/* sub-funcs for scanelf_file() */ 129/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 130static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{ 131{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 132 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
116 continue; \ 174 continue; \
117 if (fix_elf && setpax) { \ 175 if (fix_elf && setpax) { \
118 /* set the paxctl flags */ \ 176 /* set the paxctl flags */ \
119 ESET(phdr[i].p_flags, setpax); \ 177 ESET(phdr[i].p_flags, setpax); \
120 } \ 178 } \
121 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 179 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
122 continue; \ 180 continue; \
123 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 181 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
124 *found_pax = 1; \ 182 *found_pax = 1; \
125 ++shown; \ 183 ++shown; \
126 break; \ 184 break; \
128 } 186 }
129 SHOW_PAX(32) 187 SHOW_PAX(32)
130 SHOW_PAX(64) 188 SHOW_PAX(64)
131 } 189 }
132 190
191 if (fix_elf && setpax) {
192 /* set the chpax settings */
193 if (elf->elf_class == ELFCLASS32) {
194 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
195 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
196 } else {
197 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
198 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
199 }
200 }
201
133 /* fall back to EI_PAX if no PT_PAX was found */ 202 /* fall back to EI_PAX if no PT_PAX was found */
134 if (!*ret) { 203 if (!*ret) {
135 static char *paxflags; 204 static char *paxflags;
136
137 if (fix_elf && setpax) {
138 /* set the chpax settings */
139 // ESET(EHDR ## B (elf->ehdr)->e_ident[EI_PAX]), setpax);
140 }
141
142 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 205 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
143 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 206 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
144 *found_pax = 1; 207 *found_pax = 1;
145 return (be_wewy_wewy_quiet ? NULL : paxflags); 208 return (be_wewy_wewy_quiet ? NULL : paxflags);
146 } 209 }
176 uint32_t flags, check_flags; \ 239 uint32_t flags, check_flags; \
177 if (elf->phdr != NULL) { \ 240 if (elf->phdr != NULL) { \
178 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 241 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
179 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 242 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
180 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 243 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
244 if (multi_stack++) \
181 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 245 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
246 if (file_matches_list(elf->filename, qa_execstack)) \
247 continue; \
182 found = found_phdr; \ 248 found = found_phdr; \
183 offset = 0; \ 249 offset = 0; \
184 check_flags = PF_X; \ 250 check_flags = PF_X; \
185 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 251 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
252 if (multi_relro++) \
186 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 253 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
187 found = found_relro; \ 254 found = found_relro; \
188 offset = 4; \ 255 offset = 4; \
189 check_flags = PF_X; \ 256 check_flags = PF_X; \
190 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 257 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
191 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \ 258 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
259 if (multi_load++ > max_pt_load) \
192 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \ 260 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
261 if (file_matches_list(elf->filename, qa_wx_load)) \
262 continue; \
193 found = found_load; \ 263 found = found_load; \
194 offset = 8; \ 264 offset = 8; \
195 check_flags = PF_W|PF_X; \ 265 check_flags = PF_W|PF_X; \
196 } else \ 266 } else \
197 continue; \ 267 continue; \
198 flags = EGET(phdr[i].p_flags); \ 268 flags = EGET(phdr[i].p_flags); \
199 if (be_quiet && ((flags & check_flags) != check_flags)) \ 269 if (be_quiet && ((flags & check_flags) != check_flags)) \
200 continue; \ 270 continue; \
201 if (fix_elf && ((flags & PF_X) != flags)) { \ 271 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
202 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \ 272 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
203 ret[3] = ret[7] = '!'; \ 273 ret[3] = ret[7] = '!'; \
204 flags = EGET(phdr[i].p_flags); \ 274 flags = EGET(phdr[i].p_flags); \
205 } \ 275 } \
206 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 276 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
234 break; \ 304 break; \
235 } \ 305 } \
236 } \ 306 } \
237 skip_this_shdr##B: \ 307 skip_this_shdr##B: \
238 if (!multi_stack) { \ 308 if (!multi_stack) { \
309 if (file_matches_list(elf->filename, qa_execstack)) \
310 return NULL; \
239 *found_phdr = 1; \ 311 *found_phdr = 1; \
240 shown = 1; \ 312 shown = 1; \
241 memcpy(ret, "!WX", 3); \ 313 memcpy(ret, "!WX", 3); \
242 } \ 314 } \
243 } \ 315 } \
248 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 320 if (be_wewy_wewy_quiet || (be_quiet && !shown))
249 return NULL; 321 return NULL;
250 else 322 else
251 return ret; 323 return ret;
252} 324}
325
326/*
327 * See if this ELF contains a DT_TEXTREL tag in any of its
328 * PT_DYNAMIC sections.
329 */
253static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 330static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
254{ 331{
255 static const char *ret = "TEXTREL"; 332 static const char *ret = "TEXTREL";
256 unsigned long i; 333 unsigned long i;
257 334
258 if (!show_textrel && !show_textrels) return NULL; 335 if (!show_textrel && !show_textrels) return NULL;
336
337 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
259 338
260 if (elf->phdr) { 339 if (elf->phdr) {
261#define SHOW_TEXTREL(B) \ 340#define SHOW_TEXTREL(B) \
262 if (elf->elf_class == ELFCLASS ## B) { \ 341 if (elf->elf_class == ELFCLASS ## B) { \
263 Elf ## B ## _Dyn *dyn; \ 342 Elf ## B ## _Dyn *dyn; \
264 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 343 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
265 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 344 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
266 Elf ## B ## _Off offset; \ 345 Elf ## B ## _Off offset; \
267 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 346 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
268 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 347 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
269 offset = EGET(phdr[i].p_offset); \ 348 offset = EGET(phdr[i].p_offset); \
270 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 349 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
271 dyn = DYN ## B (elf->data + offset); \ 350 dyn = DYN ## B (elf->data + offset); \
272 while (EGET(dyn->d_tag) != DT_NULL) { \ 351 while (EGET(dyn->d_tag) != DT_NULL) { \
273 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 352 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
285 if (be_quiet || be_wewy_wewy_quiet) 364 if (be_quiet || be_wewy_wewy_quiet)
286 return NULL; 365 return NULL;
287 else 366 else
288 return " - "; 367 return " - ";
289} 368}
369
370/*
371 * Scan the .text section to see if there are any relocations in it.
372 * Should rewrite this to check PT_LOAD sections that are marked
373 * Executable rather than the section named '.text'.
374 */
290static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 375static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
291{ 376{
292 unsigned long s, r, rmax; 377 unsigned long s, r, rmax;
293 void *symtab_void, *strtab_void, *text_void; 378 void *symtab_void, *strtab_void, *text_void;
294 379
361 /* show the raw details about this reloc */ \ 446 /* show the raw details about this reloc */ \
362 printf(" %s: ", elf->base_filename); \ 447 printf(" %s: ", elf->base_filename); \
363 if (sym && sym->st_name) \ 448 if (sym && sym->st_name) \
364 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 449 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
365 else \ 450 else \
366 printf("(memory/fake?)"); \ 451 printf("(memory/data?)"); \
367 printf(" [0x%lX]", (unsigned long)r_offset); \ 452 printf(" [0x%lX]", (unsigned long)r_offset); \
368 /* now try to find the closest symbol that this rel is probably in */ \ 453 /* now try to find the closest symbol that this rel is probably in */ \
369 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 454 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
370 func = NULL; \ 455 func = NULL; \
371 offset_tmp = 0; \ 456 offset_tmp = 0; \
375 offset_tmp = EGET(sym->st_value); \ 460 offset_tmp = EGET(sym->st_value); \
376 } \ 461 } \
377 ++sym; \ 462 ++sym; \
378 } \ 463 } \
379 printf(" in "); \ 464 printf(" in "); \
380 if (func && func->st_name) \ 465 if (func && func->st_name) { \
381 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ 466 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
467 if (r_offset > EGET(func->st_size)) \
468 printf("(optimized out: previous %s)", func_name); \
382 else \ 469 else \
383 printf("(NULL: fake?)"); \ 470 printf("%s", func_name); \
471 } else \
472 printf("(optimized out)"); \
384 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 473 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
474 if (be_verbose && has_objdump) { \
475 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
476 char *sysbuf; \
477 size_t syslen; \
478 int sysret; \
479 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"; \
480 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
481 sysbuf = xmalloc(syslen); \
482 if (end_addr < r_offset) \
483 /* not uncommon when things are optimized out */ \
484 end_addr = r_offset + 0x100; \
485 snprintf(sysbuf, syslen, sysfmt, \
486 (unsigned long)offset_tmp, \
487 (unsigned long)end_addr, \
488 elf->filename, \
489 (unsigned long)r_offset); \
490 fflush(stdout); \
491 sysret = system(sysbuf); \
492 fflush(stdout); \
493 free(sysbuf); \
494 } \
385 } \ 495 } \
386 } } 496 } }
387 SHOW_TEXTRELS(32) 497 SHOW_TEXTRELS(32)
388 SHOW_TEXTRELS(64) 498 SHOW_TEXTRELS(64)
389 } 499 }
407 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 517 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
408 break; 518 break;
409 case '$': 519 case '$':
410 if (fstat(elf->fd, &st) != -1) 520 if (fstat(elf->fd, &st) != -1)
411 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 521 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
412 warnf("Security problem with %s='%s' in %s with mode set of %o", 522 warnf("Security problem with %s='%s' in %s with mode set of %o",
413 dt_type, item, elf->filename, st.st_mode & 07777); 523 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
414 break; 524 break;
415 default: 525 default:
416 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename); 526 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
417 break; 527 break;
418 } 528 }
438 Elf ## B ## _Off offset; \ 548 Elf ## B ## _Off offset; \
439 Elf ## B ## _Xword word; \ 549 Elf ## B ## _Xword word; \
440 /* Scan all the program headers */ \ 550 /* Scan all the program headers */ \
441 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 551 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
442 /* Just scan dynamic headers */ \ 552 /* Just scan dynamic headers */ \
443 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 553 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
444 offset = EGET(phdr[i].p_offset); \ 554 offset = EGET(phdr[i].p_offset); \
445 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 555 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
446 /* Just scan dynamic RPATH/RUNPATH headers */ \ 556 /* Just scan dynamic RPATH/RUNPATH headers */ \
447 dyn = DYN ## B (elf->data + offset); \ 557 dyn = DYN ## B (elf->data + offset); \
448 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 558 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
577#define FLAG_POWERPC_LIB64 0x0500 687#define FLAG_POWERPC_LIB64 0x0500
578#define FLAG_MIPS64_LIBN32 0x0600 688#define FLAG_MIPS64_LIBN32 0x0600
579#define FLAG_MIPS64_LIBN64 0x0700 689#define FLAG_MIPS64_LIBN64 0x0700
580 690
581static char *lookup_cache_lib(elfobj *, char *); 691static char *lookup_cache_lib(elfobj *, char *);
692
693#if defined(__GLIBC__) || defined(__UCLIBC__)
694
582static char *lookup_cache_lib(elfobj *elf, char *fname) 695static char *lookup_cache_lib(elfobj *elf, char *fname)
583{ 696{
584 int fd = 0; 697 int fd = 0;
585 char *strs; 698 char *strs;
586 static char buf[__PAX_UTILS_PATH_MAX] = ""; 699 static char buf[__PAX_UTILS_PATH_MAX] = "";
612 ldcache_size = st.st_size; 725 ldcache_size = st.st_size;
613 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); 726 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
614 727
615 close(fd); 728 close(fd);
616 729
617 if (ldcache == (caddr_t)-1) { 730 if (ldcache == MAP_FAILED) {
618 ldcache = 0; 731 ldcache = 0;
619 return NULL; 732 return NULL;
620 } 733 }
621 734
622 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 735 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
642 continue; 755 continue;
643 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 756 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
644 } 757 }
645 return buf; 758 return buf;
646} 759}
760#elif defined(__NetBSD__)
761static char *lookup_cache_lib(elfobj *elf, char *fname)
762{
763 static char buf[__PAX_UTILS_PATH_MAX] = "";
764 static struct stat st;
647 765
766 char **ldpath;
767 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
768 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
769 continue; /* if the pathname is too long, or something went wrong, ignore */
770
771 if (stat(buf, &st) != 0)
772 continue; /* if the lib doesn't exist in *ldpath, look further */
773
774 /* NetBSD doesn't actually do sanity checks, it just loads the file
775 * and if that doesn't work, continues looking in other directories.
776 * This cannot easily be safely emulated, unfortunately. For now,
777 * just assume that if it exists, it's a valid library. */
778
779 return buf;
780 }
781
782 /* not found in any path */
783 return NULL;
784}
785#else
786#ifdef __ELF__
787#warning Cache support not implemented for your target
788#endif
789static char *lookup_cache_lib(elfobj *elf, char *fname)
790{
791 return NULL;
792}
793#endif
648 794
649static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 795static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
650{ 796{
651 unsigned long i; 797 unsigned long i;
652 char *needed; 798 char *needed;
664 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 810 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
665 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 811 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
666 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 812 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
667 Elf ## B ## _Off offset; \ 813 Elf ## B ## _Off offset; \
668 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 814 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
669 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 815 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
670 offset = EGET(phdr[i].p_offset); \ 816 offset = EGET(phdr[i].p_offset); \
671 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 817 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
672 dyn = DYN ## B (elf->data + offset); \ 818 dyn = DYN ## B (elf->data + offset); \
673 while (EGET(dyn->d_tag) != DT_NULL) { \ 819 while (EGET(dyn->d_tag) != DT_NULL) { \
674 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 820 if (EGET(dyn->d_tag) == DT_NEEDED) { \
686 needed = p; \ 832 needed = p; \
687 xstrcat(ret, needed, ret_len); \ 833 xstrcat(ret, needed, ret_len); \
688 } \ 834 } \
689 *found_needed = 1; \ 835 *found_needed = 1; \
690 } else { \ 836 } else { \
691 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 837 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
692 *found_lib = 1; \ 838 *found_lib = 1; \
693 return (be_wewy_wewy_quiet ? NULL : needed); \ 839 return (be_wewy_wewy_quiet ? NULL : needed); \
694 } \ 840 } \
695 } \ 841 } \
696 } \ 842 } \
727} 873}
728static char *scanelf_file_bind(elfobj *elf, char *found_bind) 874static char *scanelf_file_bind(elfobj *elf, char *found_bind)
729{ 875{
730 unsigned long i; 876 unsigned long i;
731 struct stat s; 877 struct stat s;
878 char dynamic = 0;
732 879
733 if (!show_bind) return NULL; 880 if (!show_bind) return NULL;
734 if (!elf->phdr) return NULL; 881 if (!elf->phdr) return NULL;
735 882
736#define SHOW_BIND(B) \ 883#define SHOW_BIND(B) \
738 Elf ## B ## _Dyn *dyn; \ 885 Elf ## B ## _Dyn *dyn; \
739 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 886 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
740 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 887 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
741 Elf ## B ## _Off offset; \ 888 Elf ## B ## _Off offset; \
742 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 889 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
743 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 890 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
891 dynamic = 1; \
744 offset = EGET(phdr[i].p_offset); \ 892 offset = EGET(phdr[i].p_offset); \
745 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 893 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
746 dyn = DYN ## B (elf->data + offset); \ 894 dyn = DYN ## B (elf->data + offset); \
747 while (EGET(dyn->d_tag) != DT_NULL) { \ 895 while (EGET(dyn->d_tag) != DT_NULL) { \
748 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 896 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
759 SHOW_BIND(32) 907 SHOW_BIND(32)
760 SHOW_BIND(64) 908 SHOW_BIND(64)
761 909
762 if (be_wewy_wewy_quiet) return NULL; 910 if (be_wewy_wewy_quiet) return NULL;
763 911
912 /* don't output anything if quiet mode and the ELF is static or not setuid */
764 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 913 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
765 return NULL; 914 return NULL;
766 } else { 915 } else {
767 *found_bind = 1; 916 *found_bind = 1;
768 return (char *) "LAZY"; 917 return (char *) (dynamic ? "LAZY" : "STATIC");
769 } 918 }
770} 919}
771static char *scanelf_file_soname(elfobj *elf, char *found_soname) 920static char *scanelf_file_soname(elfobj *elf, char *found_soname)
772{ 921{
773 unsigned long i; 922 unsigned long i;
785 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 934 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
786 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 935 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
787 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 936 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
788 Elf ## B ## _Off offset; \ 937 Elf ## B ## _Off offset; \
789 /* only look for soname in shared objects */ \ 938 /* only look for soname in shared objects */ \
790 if (ehdr->e_type != ET_DYN) \ 939 if (EGET(ehdr->e_type) != ET_DYN) \
791 return NULL; \ 940 return NULL; \
792 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 941 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
793 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 942 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
794 offset = EGET(phdr[i].p_offset); \ 943 offset = EGET(phdr[i].p_offset); \
795 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 944 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
796 dyn = DYN ## B (elf->data + offset); \ 945 dyn = DYN ## B (elf->data + offset); \
797 while (EGET(dyn->d_tag) != DT_NULL) { \ 946 while (EGET(dyn->d_tag) != DT_NULL) { \
798 if (EGET(dyn->d_tag) == DT_SONAME) { \ 947 if (EGET(dyn->d_tag) == DT_SONAME) { \
812 SHOW_SONAME(64) 961 SHOW_SONAME(64)
813 } 962 }
814 963
815 return NULL; 964 return NULL;
816} 965}
966
967static int scanelf_match_symname(const char *symname, const char *tomatch) {
968 /* We do things differently when checking with regexp */
969 if (g_match) {
970 return rematch(symname, tomatch, REG_EXTENDED) == 0;
971 } else {
972 const size_t symname_len = strlen(symname);
973 return (strncmp(symname, tomatch, symname_len) == 0 &&
974 /* Accept unversioned symbol names */
975 (tomatch[symname_len] == '\0' || tomatch[symname_len] == '@'));
976 }
977}
978
817static char *scanelf_file_sym(elfobj *elf, char *found_sym) 979static char *scanelf_file_sym(elfobj *elf, char *found_sym)
818{ 980{
819 unsigned long i; 981 unsigned long i;
820 char *ret; 982 char *ret;
821 void *symtab_void, *strtab_void; 983 void *symtab_void, *strtab_void;
834 unsigned long cnt = EGET(symtab->sh_entsize); \ 996 unsigned long cnt = EGET(symtab->sh_entsize); \
835 char *symname; \ 997 char *symname; \
836 if (cnt) \ 998 if (cnt) \
837 cnt = EGET(symtab->sh_size) / cnt; \ 999 cnt = EGET(symtab->sh_size) / cnt; \
838 for (i = 0; i < cnt; ++i) { \ 1000 for (i = 0; i < cnt; ++i) { \
1001 if ((void*)sym > (void*)elf->data_end) { \
1002 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1003 goto break_out; \
1004 } \
839 if (sym->st_name) { \ 1005 if (sym->st_name) { \
1006 /* make sure the symbol name is in acceptable memory range */ \
840 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1007 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
841 if ((void*)symname > (void*)elf->data_end) { \ 1008 if ((void*)symname > (void*)elf->data_end) { \
842 warnf("%s: corrupt ELF symbols", elf->filename); \ 1009 warnf("%s: corrupt ELF symbols", elf->filename); \
1010 ++sym; \
843 continue; \ 1011 continue; \
844 } \ 1012 } \
845 if (*find_sym == '*') { \ 1013 /* debug display ... show all symbols and some extra info */ \
1014 if (0 && g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
846 printf("%s(%s) %5lX %15s %s\n", \ 1015 printf("%s(%s) %5lX %15s %s %s\n", \
847 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1016 ((*found_sym == 0) ? "\n\t" : "\t"), \
848 elf->base_filename, \ 1017 elf->base_filename, \
849 (unsigned long)sym->st_size, \ 1018 (unsigned long)sym->st_size, \
850 get_elfstttype(sym->st_info), \ 1019 get_elfstttype(sym->st_info), \
851 symname); \ 1020 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
852 *found_sym = 1; \ 1021 *found_sym = 1; \
853 } else { \ 1022 } else { \
1023 /* allow the user to specify a comma delimited list of symbols to search for */ \
854 char *this_sym, *next_sym; \ 1024 char *this_sym, *next_sym; \
1025 next_sym = ret; \
1026 while (next_sym) { \
855 this_sym = find_sym; \ 1027 this_sym = next_sym; \
856 do { \
857 next_sym = strchr(this_sym, ','); \ 1028 if ((next_sym = strchr(this_sym, ','))) \
858 if (next_sym == NULL) \ 1029 next_sym += 1; /* Skip the comma */ \
859 next_sym = this_sym + strlen(this_sym); \ 1030 /* do we want a defined symbol ? */ \
860 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \ 1031 if (*this_sym == '+') { \
861 (strcmp(symname, versioned_symname) == 0)) { \ 1032 if (sym->st_shndx == SHN_UNDEF) \
1033 continue; \
862 ret = this_sym; \ 1034 ++this_sym; \
1035 /* do we want an undefined symbol ? */ \
1036 } else if (*this_sym == '-') { \
1037 if (sym->st_shndx != SHN_UNDEF) \
1038 continue; \
1039 ++this_sym; \
1040 } \
1041 if (next_sym) /* Copy it so that we don't have to worry about the final , */ \
1042 this_sym = xstrndup(this_sym, next_sym-this_sym); \
1043 /* ok, lets compare the name now */ \
1044 if (scanelf_match_symname(this_sym, symname)) { \
1045 if (be_semi_verbose) { \
1046 char buf[126]; \
1047 snprintf(buf, sizeof(buf), "%lX %s %s", \
1048 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1049 ret = buf; \
1050 } else \
1051 ret = symname; \
863 (*found_sym)++; \ 1052 (*found_sym)++; \
864 goto break_out; \ 1053 goto break_out; \
865 } \ 1054 } \
866 this_sym = next_sym + 1; \ 1055 if (next_sym) free(this_sym); \
867 } while (*next_sym != '\0'); \ 1056 } \
868 } \ 1057 } \
869 } \ 1058 } \
870 ++sym; \ 1059 ++sym; \
871 } } 1060 } }
872 FIND_SYM(32) 1061 FIND_SYM(32)
882 return NULL; 1071 return NULL;
883 else 1072 else
884 return (char *)" - "; 1073 return (char *)" - ";
885} 1074}
886 1075
887
888static char *scanelf_file_sections(elfobj *elf, char *found_section) 1076static char *scanelf_file_sections(elfobj *elf, char *found_section)
889{ 1077{
890 if (!find_section) 1078 if (!find_section)
891 return NULL; 1079 return NULL;
892 1080
893#define FIND_SECTION(B) \ 1081#define FIND_SECTION(B) \
894 if (elf->elf_class == ELFCLASS ## B) { \ 1082 if (elf->elf_class == ELFCLASS ## B) { \
1083 int invert; \
895 Elf ## B ## _Shdr *section; \ 1084 Elf ## B ## _Shdr *section; \
1085 invert = (*find_section == '!' ? 1 : 0); \
896 section = SHDR ## B (elf_findsecbyname(elf, find_section)); \ 1086 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
897 if (section != NULL) \ 1087 if ((section == NULL && invert) || (section != NULL && !invert)) \
898 *found_section = 1; \ 1088 *found_section = 1; \
899 } 1089 }
900 FIND_SECTION(32) 1090 FIND_SECTION(32)
901 FIND_SECTION(64) 1091 FIND_SECTION(64)
902 1092
903
904 if (be_wewy_wewy_quiet) return NULL; 1093 if (be_wewy_wewy_quiet)
1094 return NULL;
905 1095
906 if (*found_section) 1096 if (*found_section)
907 return find_section; 1097 return find_section;
908 1098
909 if (be_quiet) 1099 if (be_quiet)
915/* scan an elf file and show all the fun stuff */ 1105/* scan an elf file and show all the fun stuff */
916#define prints(str) write(fileno(stdout), str, strlen(str)) 1106#define prints(str) write(fileno(stdout), str, strlen(str))
917static int scanelf_elfobj(elfobj *elf) 1107static int scanelf_elfobj(elfobj *elf)
918{ 1108{
919 unsigned long i; 1109 unsigned long i;
920 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1110 char found_pax, found_phdr, found_relro, found_load, found_textrel,
921 found_rpath, found_needed, found_interp, found_bind, found_soname, 1111 found_rpath, found_needed, found_interp, found_bind, found_soname,
922 found_sym, found_lib, found_file, found_textrels, found_section; 1112 found_sym, found_lib, found_file, found_textrels, found_section;
923 static char *out_buffer = NULL; 1113 static char *out_buffer = NULL;
924 static size_t out_len; 1114 static size_t out_len;
925 1115
926 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1116 found_pax = found_phdr = found_relro = found_load = found_textrel = \
935 printf("%s: scanning file\n", elf->filename); 1125 printf("%s: scanning file\n", elf->filename);
936 1126
937 /* init output buffer */ 1127 /* init output buffer */
938 if (!out_buffer) { 1128 if (!out_buffer) {
939 out_len = sizeof(char) * 80; 1129 out_len = sizeof(char) * 80;
940 out_buffer = (char*)xmalloc(out_len); 1130 out_buffer = xmalloc(out_len);
941 } 1131 }
942 *out_buffer = '\0'; 1132 *out_buffer = '\0';
943 1133
944 /* show the header */ 1134 /* show the header */
945 if (!be_quiet && show_banner) { 1135 if (!be_quiet && show_banner) {
946 for (i = 0; out_format[i]; ++i) { 1136 for (i = 0; out_format[i]; ++i) {
947 if (!IS_MODIFIER(out_format[i])) continue; 1137 if (!IS_MODIFIER(out_format[i])) continue;
948 1138
949 switch (out_format[++i]) { 1139 switch (out_format[++i]) {
1140 case '+': break;
950 case '%': break; 1141 case '%': break;
951 case '#': break; 1142 case '#': break;
952 case 'F': 1143 case 'F':
953 case 'p': 1144 case 'p':
954 case 'f': prints("FILE "); found_file = 1; break; 1145 case 'f': prints("FILE "); found_file = 1; break;
955 case 'o': prints(" TYPE "); break; 1146 case 'o': prints(" TYPE "); break;
956 case 'x': prints(" PAX "); break; 1147 case 'x': prints(" PAX "); break;
957 case 'e': prints("STK/REL/PTL "); break; 1148 case 'e': prints("STK/REL/PTL "); break;
958 case 't': prints("TEXTREL "); break; 1149 case 't': prints("TEXTREL "); break;
959 case 'r': prints("RPATH "); break; 1150 case 'r': prints("RPATH "); break;
1151 case 'M': prints("CLASS "); break;
960 case 'n': prints("NEEDED "); break; 1152 case 'n': prints("NEEDED "); break;
961 case 'i': prints("INTERP "); break; 1153 case 'i': prints("INTERP "); break;
962 case 'b': prints("BIND "); break; 1154 case 'b': prints("BIND "); break;
1155 case 'Z': prints("SIZE "); break;
963 case 'S': prints("SONAME "); break; 1156 case 'S': prints("SONAME "); break;
964 case 's': prints("SYM "); break; 1157 case 's': prints("SYM "); break;
965 case 'N': prints("LIB "); break; 1158 case 'N': prints("LIB "); break;
966 case 'T': prints("TEXTRELS "); break; 1159 case 'T': prints("TEXTRELS "); break;
967 case 'k': prints("SECTION "); break; 1160 case 'k': prints("SECTION "); break;
1161 case 'a': prints("ARCH "); break;
1162 case 'I': prints("OSABI "); break;
1163 case 'Y': prints("EABI "); break;
1164 case 'O': prints("PERM "); break;
1165 case 'D': prints("ENDIAN "); break;
968 default: warnf("'%c' has no title ?", out_format[i]); 1166 default: warnf("'%c' has no title ?", out_format[i]);
969 } 1167 }
970 } 1168 }
971 if (!found_file) prints("FILE "); 1169 if (!found_file) prints("FILE ");
972 prints("\n"); 1170 prints("\n");
976 1174
977 /* dump all the good stuff */ 1175 /* dump all the good stuff */
978 for (i = 0; out_format[i]; ++i) { 1176 for (i = 0; out_format[i]; ++i) {
979 const char *out; 1177 const char *out;
980 const char *tmp; 1178 const char *tmp;
981 1179 static char ubuf[sizeof(unsigned long)*2];
982 if (!IS_MODIFIER(out_format[i])) { 1180 if (!IS_MODIFIER(out_format[i])) {
983 xchrcat(&out_buffer, out_format[i], &out_len); 1181 xchrcat(&out_buffer, out_format[i], &out_len);
984 continue; 1182 continue;
985 } 1183 }
986 1184
987 out = NULL; 1185 out = NULL;
988 be_wewy_wewy_quiet = (out_format[i] == '#'); 1186 be_wewy_wewy_quiet = (out_format[i] == '#');
1187 be_semi_verbose = (out_format[i] == '+');
989 switch (out_format[++i]) { 1188 switch (out_format[++i]) {
1189 case '+':
990 case '%': 1190 case '%':
991 case '#': 1191 case '#':
992 xchrcat(&out_buffer, out_format[i], &out_len); break; 1192 xchrcat(&out_buffer, out_format[i], &out_len); break;
993 case 'F': 1193 case 'F':
994 found_file = 1; 1194 found_file = 1;
1020 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1220 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1021 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1221 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1022 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1222 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1023 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; 1223 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1024 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1224 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1225 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1226 case 'D': out = get_endian(elf); break;
1227 case 'O': out = strfileperms(elf->filename); break;
1025 case 'n': 1228 case 'n':
1026 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1229 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1027 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1230 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1028 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1231 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1029 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1232 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1030 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1233 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1031 case 'k': out = scanelf_file_sections(elf, &found_section); break; 1234 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1235 case 'a': out = get_elfemtype(elf); break;
1236 case 'I': out = get_elfosabi(elf); break;
1237 case 'Y': out = get_elf_eabi(elf); break;
1238 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;;
1032 default: warnf("'%c' has no scan code?", out_format[i]); 1239 default: warnf("'%c' has no scan code?", out_format[i]);
1033 } 1240 }
1034 if (out) { 1241 if (out) {
1035 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1242 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1036 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1243 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1082 if (strlen(match_etypes)) { 1289 if (strlen(match_etypes)) {
1083 char sbuf[126]; 1290 char sbuf[126];
1084 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1291 strncpy(sbuf, match_etypes, sizeof(sbuf));
1085 if (strchr(match_etypes, ',') != NULL) { 1292 if (strchr(match_etypes, ',') != NULL) {
1086 char *p; 1293 char *p;
1087 while((p = strrchr(sbuf, ',')) != NULL) { 1294 while ((p = strrchr(sbuf, ',')) != NULL) {
1088 *p = 0; 1295 *p = 0;
1089 if (atoi(p+1) == get_etype(elf)) 1296 if (etype_lookup(p+1) == get_etype(elf))
1090 goto label_ret; 1297 goto label_ret;
1091 } 1298 }
1092 } 1299 }
1093 if (atoi(sbuf) != get_etype(elf)) 1300 if (etype_lookup(sbuf) != get_etype(elf))
1094 goto label_done; 1301 goto label_done;
1095 } 1302 }
1096 1303
1097label_ret: 1304label_ret:
1098 ret = scanelf_elfobj(elf); 1305 ret = scanelf_elfobj(elf);
1112 1319
1113 ar = ar_open_fd(filename, fd); 1320 ar = ar_open_fd(filename, fd);
1114 if (ar == NULL) 1321 if (ar == NULL)
1115 return 1; 1322 return 1;
1116 1323
1117 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0); 1324 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1118 while ((m=ar_next(ar)) != NULL) { 1325 while ((m=ar_next(ar)) != NULL) {
1119 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size); 1326 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1120 if (elf) { 1327 if (elf) {
1121 scanelf_elfobj(elf); 1328 scanelf_elfobj(elf);
1122 unreadelf(elf); 1329 unreadelf(elf);
1125 munmap(ar_buffer, len); 1332 munmap(ar_buffer, len);
1126 1333
1127 return 0; 1334 return 0;
1128} 1335}
1129/* scan a file which may be an elf or an archive or some other magical beast */ 1336/* scan a file which may be an elf or an archive or some other magical beast */
1130static void scanelf_file(const char *filename) 1337static int scanelf_file(const char *filename, const struct stat *st_cache)
1131{ 1338{
1339 const struct stat *st = st_cache;
1132 struct stat st; 1340 struct stat symlink_st;
1133 int fd; 1341 int fd;
1134 1342
1135 /* make sure 'filename' exists */
1136 if (lstat(filename, &st) == -1) {
1137 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1138 return;
1139 }
1140
1141 /* always handle regular files and handle symlinked files if no -y */ 1343 /* always handle regular files and handle symlinked files if no -y */
1142 if (S_ISLNK(st.st_mode)) { 1344 if (S_ISLNK(st->st_mode)) {
1143 if (!scan_symlink) return; 1345 if (!scan_symlink) return 1;
1144 stat(filename, &st); 1346 stat(filename, &symlink_st);
1347 st = &symlink_st;
1145 } 1348 }
1349
1146 if (!S_ISREG(st.st_mode)) { 1350 if (!S_ISREG(st->st_mode)) {
1147 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1351 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1148 return; 1352 return 1;
1149 } 1353 }
1150 1354
1355 if (match_perms) {
1356 if ((st->st_mode | match_perms) != st->st_mode)
1357 return 1;
1358 }
1151 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1359 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1152 return; 1360 return 1;
1153 1361
1154 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1362 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1155 /* if it isn't an ELF, maybe it's an .a archive */ 1363 /* if it isn't an ELF, maybe it's an .a archive */
1156 scanelf_archive(filename, fd, st.st_size); 1364 scanelf_archive(filename, fd, st->st_size);
1157 1365
1158 close(fd); 1366 close(fd);
1367 return 0;
1159} 1368}
1160 1369
1161/* scan a directory for ET_EXEC files and print when we find one */ 1370/* scan a directory for ET_EXEC files and print when we find one */
1162static void scanelf_dir(const char *path) 1371static int scanelf_dir(const char *path)
1163{ 1372{
1164 register DIR *dir; 1373 register DIR *dir;
1165 register struct dirent *dentry; 1374 register struct dirent *dentry;
1166 struct stat st_top, st; 1375 struct stat st_top, st;
1167 char buf[__PAX_UTILS_PATH_MAX]; 1376 char buf[__PAX_UTILS_PATH_MAX];
1168 size_t pathlen = 0, len = 0; 1377 size_t pathlen = 0, len = 0;
1378 int ret = 0;
1169 1379
1170 /* make sure path exists */ 1380 /* make sure path exists */
1171 if (lstat(path, &st_top) == -1) { 1381 if (lstat(path, &st_top) == -1) {
1172 if (be_verbose > 2) printf("%s: does not exist\n", path); 1382 if (be_verbose > 2) printf("%s: does not exist\n", path);
1173 return; 1383 return 1;
1174 } 1384 }
1175 1385
1176 /* ok, if it isn't a directory, assume we can open it */ 1386 /* ok, if it isn't a directory, assume we can open it */
1177 if (!S_ISDIR(st_top.st_mode)) { 1387 if (!S_ISDIR(st_top.st_mode)) {
1178 scanelf_file(path); 1388 return scanelf_file(path, &st_top);
1179 return;
1180 } 1389 }
1181 1390
1182 /* now scan the dir looking for fun stuff */ 1391 /* now scan the dir looking for fun stuff */
1183 if ((dir = opendir(path)) == NULL) { 1392 if ((dir = opendir(path)) == NULL) {
1184 warnf("could not opendir %s: %s", path, strerror(errno)); 1393 warnf("could not opendir %s: %s", path, strerror(errno));
1185 return; 1394 return 1;
1186 } 1395 }
1187 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1396 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1188 1397
1189 pathlen = strlen(path); 1398 pathlen = strlen(path);
1190 while ((dentry = readdir(dir))) { 1399 while ((dentry = readdir(dir))) {
1194 if (len >= sizeof(buf)) { 1403 if (len >= sizeof(buf)) {
1195 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1404 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1196 (unsigned long)len, (unsigned long)sizeof(buf)); 1405 (unsigned long)len, (unsigned long)sizeof(buf));
1197 continue; 1406 continue;
1198 } 1407 }
1199 sprintf(buf, "%s/%s", path, dentry->d_name); 1408 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1200 if (lstat(buf, &st) != -1) { 1409 if (lstat(buf, &st) != -1) {
1201 if (S_ISREG(st.st_mode)) 1410 if (S_ISREG(st.st_mode))
1202 scanelf_file(buf); 1411 ret = scanelf_file(buf, &st);
1203 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1412 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1204 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1413 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1205 scanelf_dir(buf); 1414 ret = scanelf_dir(buf);
1206 } 1415 }
1207 } 1416 }
1208 } 1417 }
1209 closedir(dir); 1418 closedir(dir);
1419 return ret;
1210} 1420}
1211 1421
1212static int scanelf_from_file(char *filename) 1422static int scanelf_from_file(const char *filename)
1213{ 1423{
1214 FILE *fp = NULL; 1424 FILE *fp = NULL;
1215 char *p; 1425 char *p;
1216 char path[__PAX_UTILS_PATH_MAX]; 1426 char path[__PAX_UTILS_PATH_MAX];
1427 int ret = 0;
1217 1428
1218 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1429 if (strcmp(filename, "-") == 0)
1219 fp = stdin; 1430 fp = stdin;
1220 else if ((fp = fopen(filename, "r")) == NULL) 1431 else if ((fp = fopen(filename, "r")) == NULL)
1221 return 1; 1432 return 1;
1222 1433
1223 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1434 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1224 if ((p = strchr(path, '\n')) != NULL) 1435 if ((p = strchr(path, '\n')) != NULL)
1225 *p = 0; 1436 *p = 0;
1226 search_path = path; 1437 search_path = path;
1227 scanelf_dir(path); 1438 ret = scanelf_dir(path);
1228 } 1439 }
1229 if (fp != stdin) 1440 if (fp != stdin)
1230 fclose(fp); 1441 fclose(fp);
1231 return 0; 1442 return ret;
1232} 1443}
1233 1444
1445#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1446
1234static int load_ld_so_conf(int i, const char *fname) 1447static int load_ld_cache_config(int i, const char *fname)
1235{ 1448{
1236 FILE *fp = NULL; 1449 FILE *fp = NULL;
1237 char *p; 1450 char *p;
1238 char path[__PAX_UTILS_PATH_MAX]; 1451 char path[__PAX_UTILS_PATH_MAX];
1239 1452
1240 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1453 if (i + 1 == ARRAY_SIZE(ldpaths))
1241 return i; 1454 return i;
1242 1455
1243 if ((fp = fopen(fname, "r")) == NULL) 1456 if ((fp = fopen(fname, "r")) == NULL)
1244 return i; 1457 return i;
1245 1458
1246 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1459 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1247 if ((p = strrchr(path, '\r')) != NULL) 1460 if ((p = strrchr(path, '\r')) != NULL)
1248 *p = 0; 1461 *p = 0;
1249 if ((p = strchr(path, '\n')) != NULL) 1462 if ((p = strchr(path, '\n')) != NULL)
1250 *p = 0; 1463 *p = 0;
1251#ifdef HAVE_GLOB 1464#ifdef __linux__
1252 // recursive includes of the same file will make this segfault. 1465 /* recursive includes of the same file will make this segfault. */
1253 if ((*path == 'i') && (strncmp(path, "include", 7) == 0) && isblank(path[7])) { 1466 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1254 glob64_t gl; 1467 glob64_t gl;
1255 size_t x; 1468 size_t x;
1256 char gpath[__PAX_UTILS_PATH_MAX]; 1469 char gpath[__PAX_UTILS_PATH_MAX];
1257 1470
1258 gpath[sizeof(gpath)] = 0; 1471 memset(gpath, 0, sizeof(gpath));
1259 1472
1260 if (path[8] != '/') 1473 if (path[8] != '/')
1261 snprintf(gpath, sizeof(gpath)-1, "/etc/%s", &path[8]); 1474 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1262 else 1475 else
1263 strncpy(gpath, &path[8], sizeof(gpath)-1); 1476 strncpy(gpath, &path[8], sizeof(gpath));
1264 1477
1265 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1478 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1266 for (x = 0; x < gl.gl_pathc; ++x) { 1479 for (x = 0; x < gl.gl_pathc; ++x) {
1267 /* try to avoid direct loops */ 1480 /* try to avoid direct loops */
1268 if (strcmp(gl.gl_pathv[x], fname) == 0) 1481 if (strcmp(gl.gl_pathv[x], fname) == 0)
1269 continue; 1482 continue;
1270 i = load_ld_so_conf(i, gl.gl_pathv[x]); 1483 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1271 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) { 1484 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1272 globfree64(&gl); 1485 globfree64(&gl);
1273 return i; 1486 return i;
1274 } 1487 }
1275 } 1488 }
1276 globfree64 (&gl); 1489 globfree64 (&gl);
1277 continue; 1490 continue;
1278 } else 1491 }
1279 abort();
1280 } 1492 }
1281#endif 1493#endif
1282 if (*path != '/') 1494 if (*path != '/')
1283 continue; 1495 continue;
1284 1496
1285 ldpaths[i++] = xstrdup(path); 1497 ldpaths[i++] = xstrdup(path);
1286 1498
1287 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1499 if (i + 1 == ARRAY_SIZE(ldpaths))
1288 break; 1500 break;
1289 } 1501 }
1290 ldpaths[i] = NULL; 1502 ldpaths[i] = NULL;
1291 1503
1292 fclose(fp); 1504 fclose(fp);
1293 return i; 1505 return i;
1294} 1506}
1295 1507
1508#elif defined(__FreeBSD__) || (__DragonFly__)
1509
1510static int load_ld_cache_config(int i, const char *fname)
1511{
1512 FILE *fp = NULL;
1513 char *b = NULL, *p;
1514 struct elfhints_hdr hdr;
1515
1516 if (i + 1 == ARRAY_SIZE(ldpaths))
1517 return i;
1518
1519 if ((fp = fopen(fname, "r")) == NULL)
1520 return i;
1521
1522 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1523 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1524 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1525 {
1526 fclose(fp);
1527 return i;
1528 }
1529
1530 b = xmalloc(hdr.dirlistlen + 1);
1531 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1532 fclose(fp);
1533 free(b);
1534 return i;
1535 }
1536
1537 while ((p = strsep(&b, ":"))) {
1538 if (*p == '\0') continue;
1539 ldpaths[i++] = xstrdup(p);
1540
1541 if (i + 1 == ARRAY_SIZE(ldpaths))
1542 break;
1543 }
1544 ldpaths[i] = NULL;
1545
1546 free(b);
1547 fclose(fp);
1548 return i;
1549}
1550
1551#else
1552#ifdef __ELF__
1553#warning Cache config support not implemented for your target
1554#endif
1555static int load_ld_cache_config(int i, const char *fname)
1556{
1557 memset(ldpaths, 0x00, sizeof(ldpaths));
1558 return 0;
1559}
1560#endif
1561
1296/* scan /etc/ld.so.conf for paths */ 1562/* scan /etc/ld.so.conf for paths */
1297static void scanelf_ldpath() 1563static void scanelf_ldpath(void)
1298{ 1564{
1299 char scan_l, scan_ul, scan_ull; 1565 char scan_l, scan_ul, scan_ull;
1300 int i = 0; 1566 int i = 0;
1301 1567
1302 if (!ldpaths[0]) 1568 if (!ldpaths[0])
1316 if (!scan_ul) scanelf_dir("/usr/lib"); 1582 if (!scan_ul) scanelf_dir("/usr/lib");
1317 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1583 if (!scan_ull) scanelf_dir("/usr/local/lib");
1318} 1584}
1319 1585
1320/* scan env PATH for paths */ 1586/* scan env PATH for paths */
1321static void scanelf_envpath() 1587static void scanelf_envpath(void)
1322{ 1588{
1323 char *path, *p; 1589 char *path, *p;
1324 1590
1325 path = getenv("PATH"); 1591 path = getenv("PATH");
1326 if (!path) 1592 if (!path)
1333 } 1599 }
1334 1600
1335 free(path); 1601 free(path);
1336} 1602}
1337 1603
1338/* usage / invocation handling functions */ 1604/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H J K P Q U W */
1339#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV" 1605#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZBhV"
1340#define a_argument required_argument 1606#define a_argument required_argument
1341static struct option const long_opts[] = { 1607static struct option const long_opts[] = {
1342 {"path", no_argument, NULL, 'p'}, 1608 {"path", no_argument, NULL, 'p'},
1343 {"ldpath", no_argument, NULL, 'l'}, 1609 {"ldpath", no_argument, NULL, 'l'},
1344 {"recursive", no_argument, NULL, 'R'}, 1610 {"recursive", no_argument, NULL, 'R'},
1361 {"lib", a_argument, NULL, 'N'}, 1627 {"lib", a_argument, NULL, 'N'},
1362 {"gmatch", no_argument, NULL, 'g'}, 1628 {"gmatch", no_argument, NULL, 'g'},
1363 {"textrels", no_argument, NULL, 'T'}, 1629 {"textrels", no_argument, NULL, 'T'},
1364 {"etype", a_argument, NULL, 'E'}, 1630 {"etype", a_argument, NULL, 'E'},
1365 {"bits", a_argument, NULL, 'M'}, 1631 {"bits", a_argument, NULL, 'M'},
1632 {"endian", no_argument, NULL, 'D'},
1633 {"osabi", no_argument, NULL, 'I'},
1634 {"eabi", no_argument, NULL, 'Y'},
1635 {"perms", a_argument, NULL, 'O'},
1636 {"size", no_argument, NULL, 'Z'},
1366 {"all", no_argument, NULL, 'a'}, 1637 {"all", no_argument, NULL, 'a'},
1367 {"quiet", no_argument, NULL, 'q'}, 1638 {"quiet", no_argument, NULL, 'q'},
1368 {"verbose", no_argument, NULL, 'v'}, 1639 {"verbose", no_argument, NULL, 'v'},
1369 {"format", a_argument, NULL, 'F'}, 1640 {"format", a_argument, NULL, 'F'},
1370 {"from", a_argument, NULL, 'f'}, 1641 {"from", a_argument, NULL, 'f'},
1396 "Find a specified symbol", 1667 "Find a specified symbol",
1397 "Find a specified section", 1668 "Find a specified section",
1398 "Find a specified library", 1669 "Find a specified library",
1399 "Use strncmp to match libraries. (use with -N)", 1670 "Use strncmp to match libraries. (use with -N)",
1400 "Locate cause of TEXTREL", 1671 "Locate cause of TEXTREL",
1401 "Print only ELF files matching numeric constant type", 1672 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1402 "Print only ELF files matching numeric bits", 1673 "Print only ELF files matching numeric bits",
1674 "Print Endianness",
1675 "Print OSABI",
1676 "Print EABI (EM_ARM Only)",
1677 "Print only ELF files matching octal permissions",
1678 "Print ELF file size",
1403 "Print all scanned info (-x -e -t -r -b)\n", 1679 "Print all scanned info (-x -e -t -r -b)\n",
1404 "Only output 'bad' things", 1680 "Only output 'bad' things",
1405 "Be verbose (can be specified more than once)", 1681 "Be verbose (can be specified more than once)",
1406 "Use specified format for output", 1682 "Use specified format for output",
1407 "Read input stream from a filename", 1683 "Read input stream from a filename",
1419 printf("* Scan ELF binaries for stuff\n\n" 1695 printf("* Scan ELF binaries for stuff\n\n"
1420 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 1696 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1421 printf("Options: -[%s]\n", PARSE_FLAGS); 1697 printf("Options: -[%s]\n", PARSE_FLAGS);
1422 for (i = 0; long_opts[i].name; ++i) 1698 for (i = 0; long_opts[i].name; ++i)
1423 if (long_opts[i].has_arg == no_argument) 1699 if (long_opts[i].has_arg == no_argument)
1424 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 1700 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1425 long_opts[i].name, opts_help[i]); 1701 long_opts[i].name, opts_help[i]);
1426 else 1702 else
1427 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 1703 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1428 long_opts[i].name, opts_help[i]); 1704 long_opts[i].name, opts_help[i]);
1429 1705
1430 if (status != EXIT_SUCCESS) 1706 puts("\nFor more information, see the scanelf(1) manpage");
1431 exit(status);
1432
1433 puts("\nThe format modifiers for the -F option are:");
1434 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1435 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1436 puts(" i INTERP \tb BIND \ts symbol");
1437 puts(" N library \to Type \tT TEXTRELs");
1438 puts(" S SONAME \tk section");
1439 puts(" p filename (with search path removed)");
1440 puts(" f filename (short name/basename)");
1441 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1442
1443 puts("\nELF Etypes:");
1444 print_etypes(stdout);
1445
1446 exit(status); 1707 exit(status);
1447} 1708}
1448 1709
1449/* parse command line arguments and preform needed actions */ 1710/* parse command line arguments and preform needed actions */
1711#define do_pax_state(option, flag) \
1712 if (islower(option)) { \
1713 flags &= ~PF_##flag; \
1714 flags |= PF_NO##flag; \
1715 } else { \
1716 flags &= ~PF_NO##flag; \
1717 flags |= PF_##flag; \
1718 }
1450static void parseargs(int argc, char *argv[]) 1719static int parseargs(int argc, char *argv[])
1451{ 1720{
1452 int i; 1721 int i;
1453 char *from_file = NULL; 1722 const char *from_file = NULL;
1723 int ret = 0;
1454 1724
1455 opterr = 0; 1725 opterr = 0;
1456 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1726 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1457 switch (i) { 1727 switch (i) {
1458 1728
1470 case 'E': 1740 case 'E':
1471 strncpy(match_etypes, optarg, sizeof(match_etypes)); 1741 strncpy(match_etypes, optarg, sizeof(match_etypes));
1472 break; 1742 break;
1473 case 'M': 1743 case 'M':
1474 match_bits = atoi(optarg); 1744 match_bits = atoi(optarg);
1745 if (match_bits == 0) {
1746 if (strcmp(optarg, "ELFCLASS32") == 0)
1747 match_bits = 32;
1748 if (strcmp(optarg, "ELFCLASS64") == 0)
1749 match_bits = 64;
1750 }
1751 break;
1752 case 'O':
1753 if (sscanf(optarg, "%o", &match_perms) == -1)
1754 match_bits = 0;
1475 break; 1755 break;
1476 case 'o': { 1756 case 'o': {
1477 FILE *fp = NULL;
1478 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1757 if (freopen(optarg, "w", stdout) == NULL)
1479 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1758 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1480 SET_STDOUT(fp);
1481 break; 1759 break;
1482 } 1760 }
1483 case 'k': 1761 case 'k':
1484 if (find_section) warn("You prob don't want to specify -k twice"); 1762 if (find_section) warn("You prob don't want to specify -k twice");
1485 find_section = optarg; 1763 find_section = optarg;
1486 break; 1764 break;
1487 case 's': { 1765 case 's': {
1488 if (find_sym) warn("You prob don't want to specify -s twice"); 1766 if (find_sym) warn("You prob don't want to specify -s twice");
1489 find_sym = optarg; 1767 find_sym = optarg;
1490 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1491 sprintf(versioned_symname, "%s@", find_sym);
1492 break; 1768 break;
1493 } 1769 }
1494 case 'N': { 1770 case 'N': {
1495 if (find_lib) warn("You prob don't want to specify -N twice"); 1771 if (find_lib) warn("You prob don't want to specify -N twice");
1496 find_lib = optarg; 1772 find_lib = optarg;
1501 if (out_format) warn("You prob don't want to specify -F twice"); 1777 if (out_format) warn("You prob don't want to specify -F twice");
1502 out_format = optarg; 1778 out_format = optarg;
1503 break; 1779 break;
1504 } 1780 }
1505 case 'z': { 1781 case 'z': {
1506 unsigned long flags = 10240; 1782 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1507 size_t x; 1783 size_t x;
1508 1784
1509#define do_state(option, flag) \
1510 if (islower(option)) { \
1511 flags &= ~PF_##flag; \
1512 flags |= PF_NO##flag; \
1513 } else { \
1514 flags &= ~PF_NO##flag; \
1515 flags |= PF_##flag; \
1516 }
1517
1518 for (x = 0 ; x < strlen(optarg); x++) { 1785 for (x = 0; x < strlen(optarg); x++) {
1519 switch(optarg[x]) { 1786 switch (optarg[x]) {
1520 case 'p': 1787 case 'p':
1521 case 'P': 1788 case 'P':
1522 do_state(optarg[x], PAGEEXEC); 1789 do_pax_state(optarg[x], PAGEEXEC);
1523 break; 1790 break;
1524 case 's': 1791 case 's':
1525 case 'S': 1792 case 'S':
1526 do_state(optarg[x], SEGMEXEC); 1793 do_pax_state(optarg[x], SEGMEXEC);
1527 break; 1794 break;
1528 case 'm': 1795 case 'm':
1529 case 'M': 1796 case 'M':
1530 do_state(optarg[x], MPROTECT); 1797 do_pax_state(optarg[x], MPROTECT);
1531 break; 1798 break;
1532 case 'e': 1799 case 'e':
1533 case 'E': 1800 case 'E':
1534 do_state(optarg[x], EMUTRAMP); 1801 do_pax_state(optarg[x], EMUTRAMP);
1535 break; 1802 break;
1536 case 'r': 1803 case 'r':
1537 case 'R': 1804 case 'R':
1538 do_state(optarg[x], RANDMMAP); 1805 do_pax_state(optarg[x], RANDMMAP);
1539 break; 1806 break;
1540 case 'x': 1807 case 'x':
1541 case 'X': 1808 case 'X':
1542 do_state(optarg[x], RANDEXEC); 1809 do_pax_state(optarg[x], RANDEXEC);
1543 break; 1810 break;
1544 default: 1811 default:
1545 break; 1812 break;
1546 } 1813 }
1547 } 1814 }
1552 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) || 1819 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1553 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)))) 1820 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1554 setpax = flags; 1821 setpax = flags;
1555 break; 1822 break;
1556 } 1823 }
1824 case 'Z': show_size = 1; break;
1557 case 'g': gmatch = 1; break; 1825 case 'g': g_match = 1; break;
1558 case 'L': use_ldcache = 1; break; 1826 case 'L': use_ldcache = 1; break;
1559 case 'y': scan_symlink = 0; break; 1827 case 'y': scan_symlink = 0; break;
1560 case 'A': scan_archives = 1; break; 1828 case 'A': scan_archives = 1; break;
1561 case 'B': show_banner = 0; break; 1829 case 'B': show_banner = 0; break;
1562 case 'l': scan_ldpath = 1; break; 1830 case 'l': scan_ldpath = 1; break;
1573 case 'b': show_bind = 1; break; 1841 case 'b': show_bind = 1; break;
1574 case 'S': show_soname = 1; break; 1842 case 'S': show_soname = 1; break;
1575 case 'T': show_textrels = 1; break; 1843 case 'T': show_textrels = 1; break;
1576 case 'q': be_quiet = 1; break; 1844 case 'q': be_quiet = 1; break;
1577 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1845 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1578 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1846 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1579 1847 case 'D': show_endian = 1; break;
1848 case 'I': show_osabi = 1; break;
1849 case 'Y': show_eabi = 1; break;
1580 case ':': 1850 case ':':
1581 err("Option '%c' is missing parameter", optopt); 1851 err("Option '%c' is missing parameter", optopt);
1582 case '?': 1852 case '?':
1583 err("Unknown option '%c' or argument missing", optopt); 1853 err("Unknown option '%c' or argument missing", optopt);
1584 default: 1854 default:
1585 err("Unhandled option '%c'; please report this", i); 1855 err("Unhandled option '%c'; please report this", i);
1586 } 1856 }
1587 } 1857 }
1588 1858 if (show_textrels && be_verbose) {
1859 if (which("objdump") != NULL)
1860 has_objdump = 1;
1861 }
1589 /* let the format option override all other options */ 1862 /* let the format option override all other options */
1590 if (out_format) { 1863 if (out_format) {
1591 show_pax = show_phdr = show_textrel = show_rpath = \ 1864 show_pax = show_phdr = show_textrel = show_rpath = \
1592 show_needed = show_interp = show_bind = show_soname = \ 1865 show_needed = show_interp = show_bind = show_soname = \
1593 show_textrels = 0; 1866 show_textrels = show_perms = show_endian = show_size = \
1867 show_osabi = show_eabi = 0;
1594 for (i = 0; out_format[i]; ++i) { 1868 for (i = 0; out_format[i]; ++i) {
1595 if (!IS_MODIFIER(out_format[i])) continue; 1869 if (!IS_MODIFIER(out_format[i])) continue;
1596 1870
1597 switch (out_format[++i]) { 1871 switch (out_format[++i]) {
1872 case '+': break;
1598 case '%': break; 1873 case '%': break;
1599 case '#': break; 1874 case '#': break;
1600 case 'F': break; 1875 case 'F': break;
1601 case 'p': break; 1876 case 'p': break;
1602 case 'f': break; 1877 case 'f': break;
1603 case 'k': break; 1878 case 'k': break;
1604 case 's': break; 1879 case 's': break;
1605 case 'N': break; 1880 case 'N': break;
1606 case 'o': break; 1881 case 'o': break;
1882 case 'a': break;
1883 case 'M': break;
1884 case 'Z': show_size = 1; break;
1885 case 'D': show_endian = 1; break;
1886 case 'I': show_osabi = 1; break;
1887 case 'Y': show_eabi = 1; break;
1888 case 'O': show_perms = 1; break;
1607 case 'x': show_pax = 1; break; 1889 case 'x': show_pax = 1; break;
1608 case 'e': show_phdr = 1; break; 1890 case 'e': show_phdr = 1; break;
1609 case 't': show_textrel = 1; break; 1891 case 't': show_textrel = 1; break;
1610 case 'r': show_rpath = 1; break; 1892 case 'r': show_rpath = 1; break;
1611 case 'n': show_needed = 1; break; 1893 case 'n': show_needed = 1; break;
1612 case 'i': show_interp = 1; break; 1894 case 'i': show_interp = 1; break;
1613 case 'b': show_bind = 1; break; 1895 case 'b': show_bind = 1; break;
1614 case 'S': show_soname = 1; break; 1896 case 'S': show_soname = 1; break;
1615 case 'T': show_textrels = 1; break; 1897 case 'T': show_textrels = 1; break;
1616 default: 1898 default:
1617 err("Invalid format specifier '%c' (byte %i)", 1899 err("Invalid format specifier '%c' (byte %i)",
1618 out_format[i], i+1); 1900 out_format[i], i+1);
1619 } 1901 }
1620 } 1902 }
1621 1903
1622 /* construct our default format */ 1904 /* construct our default format */
1623 } else { 1905 } else {
1624 size_t fmt_len = 30; 1906 size_t fmt_len = 30;
1625 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1907 out_format = xmalloc(sizeof(char) * fmt_len);
1908 *out_format = '\0';
1626 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1909 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1627 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1910 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1911 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1912 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
1913 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1914 if (show_osabi) xstrcat(&out_format, "%I ", &fmt_len);
1915 if (show_eabi) xstrcat(&out_format, "%Y ", &fmt_len);
1628 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1916 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1629 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1917 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1630 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1918 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1631 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1919 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1632 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1920 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1640 } 1928 }
1641 if (be_verbose > 2) printf("Format: %s\n", out_format); 1929 if (be_verbose > 2) printf("Format: %s\n", out_format);
1642 1930
1643 /* now lets actually do the scanning */ 1931 /* now lets actually do the scanning */
1644 if (scan_ldpath || use_ldcache) 1932 if (scan_ldpath || use_ldcache)
1645 load_ld_so_conf(0, "/etc/ld.so.conf"); 1933 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1646 if (scan_ldpath) scanelf_ldpath(); 1934 if (scan_ldpath) scanelf_ldpath();
1647 if (scan_envpath) scanelf_envpath(); 1935 if (scan_envpath) scanelf_envpath();
1936 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1937 from_file = "-";
1648 if (from_file) { 1938 if (from_file) {
1649 scanelf_from_file(from_file); 1939 scanelf_from_file(from_file);
1650 from_file = *argv; 1940 from_file = *argv;
1651 } 1941 }
1652 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1942 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1653 err("Nothing to scan !?"); 1943 err("Nothing to scan !?");
1654 while (optind < argc) { 1944 while (optind < argc) {
1655 search_path = argv[optind++]; 1945 search_path = argv[optind++];
1656 scanelf_dir(search_path); 1946 ret = scanelf_dir(search_path);
1657 } 1947 }
1658 1948
1659 /* clean up */ 1949 /* clean up */
1660 if (versioned_symname) free(versioned_symname);
1661 for (i = 0; ldpaths[i]; ++i) 1950 for (i = 0; ldpaths[i]; ++i)
1662 free(ldpaths[i]); 1951 free(ldpaths[i]);
1663 1952
1664 if (ldcache != 0) 1953 if (ldcache != 0)
1665 munmap(ldcache, ldcache_size); 1954 munmap(ldcache, ldcache_size);
1666}
1667
1668
1669
1670/* utility funcs */
1671static char *xstrdup(const char *s)
1672{
1673 char *ret = strdup(s);
1674 if (!ret) err("Could not strdup(): %s", strerror(errno));
1675 return ret; 1955 return ret;
1676} 1956}
1677static void *xmalloc(size_t size)
1678{
1679 void *ret = malloc(size);
1680 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1681 return ret;
1682}
1683static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1684{
1685 size_t new_len;
1686 1957
1687 new_len = strlen(*dst) + strlen(src); 1958static char **get_split_env(const char *envvar)
1688 if (*curr_len <= new_len) {
1689 *curr_len = new_len + (*curr_len / 2);
1690 *dst = realloc(*dst, *curr_len);
1691 if (!*dst)
1692 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1693 }
1694
1695 if (n)
1696 strncat(*dst, src, n);
1697 else
1698 strcat(*dst, src);
1699}
1700static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1701{ 1959{
1702 static char my_app[2]; 1960 const char *delims = " \t\n";
1703 my_app[0] = append; 1961 char **envvals = NULL;
1704 my_app[1] = '\0'; 1962 char *env, *s;
1705 xstrcat(dst, my_app, curr_len); 1963 int nentry;
1706}
1707 1964
1965 if ((env = getenv(envvar)) == NULL)
1966 return NULL;
1708 1967
1968 env = xstrdup(env);
1969 if (env == NULL)
1970 return NULL;
1971
1972 s = strtok(env, delims);
1973 if (s == NULL) {
1974 free(env);
1975 return NULL;
1976 }
1977
1978 nentry = 0;
1979 while (s != NULL) {
1980 ++nentry;
1981 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1982 envvals[nentry-1] = s;
1983 s = strtok(NULL, delims);
1984 }
1985 envvals[nentry] = NULL;
1986
1987 /* don't want to free(env) as it contains the memory that backs
1988 * the envvals array of strings */
1989 return envvals;
1990}
1991
1992static void parseenv(void)
1993{
1994 qa_textrels = get_split_env("QA_TEXTRELS");
1995 qa_execstack = get_split_env("QA_EXECSTACK");
1996 qa_wx_load = get_split_env("QA_WX_LOAD");
1997}
1998
1999#ifdef __PAX_UTILS_CLEANUP
2000static void cleanup(void)
2001{
2002 free(out_format);
2003 free(qa_textrels);
2004 free(qa_execstack);
2005 free(qa_wx_load);
2006}
2007#endif
1709 2008
1710int main(int argc, char *argv[]) 2009int main(int argc, char *argv[])
1711{ 2010{
2011 int ret;
1712 if (argc < 2) 2012 if (argc < 2)
1713 usage(EXIT_FAILURE); 2013 usage(EXIT_FAILURE);
2014 parseenv();
1714 parseargs(argc, argv); 2015 ret = parseargs(argc, argv);
1715 fclose(stdout); 2016 fclose(stdout);
1716#ifdef __BOUNDS_CHECKING_ON 2017#ifdef __PAX_UTILS_CLEANUP
1717 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 2018 cleanup();
2019 warn("The calls to add/delete heap should be off:\n"
2020 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
2021 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1718#endif 2022#endif
1719 return EXIT_SUCCESS; 2023 return ret;
1720} 2024}
2025
2026/* Match filename against entries in matchlist, return TRUE
2027 * if the file is listed */
2028static int file_matches_list(const char *filename, char **matchlist)
2029{
2030 char **file;
2031 char *match;
2032 char buf[__PAX_UTILS_PATH_MAX];
2033
2034 if (matchlist == NULL)
2035 return 0;
2036
2037 for (file = matchlist; *file != NULL; file++) {
2038 if (search_path) {
2039 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2040 match = buf;
2041 } else {
2042 match = *file;
2043 }
2044 if (fnmatch(match, filename, 0) == 0)
2045 return 1;
2046 }
2047 return 0;
2048}

Legend:
Removed from v.1.127  
changed lines
  Added in v.1.209

  ViewVC Help
Powered by ViewVC 1.1.20