/[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.216
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.216 2009/12/20 20:25:04 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.216 2009/12/20 20:25:04 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 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 30
35/* variables to control behavior */ 31/* variables to control behavior */
36static char match_etypes[126] = ""; 32static char match_etypes[126] = "";
37static char *ldpaths[256]; 33static char *ldpaths[256];
38static char scan_ldpath = 0; 34static char scan_ldpath = 0;
40static char scan_symlink = 1; 36static char scan_symlink = 1;
41static char scan_archives = 0; 37static char scan_archives = 0;
42static char dir_recurse = 0; 38static char dir_recurse = 0;
43static char dir_crossmount = 1; 39static char dir_crossmount = 1;
44static char show_pax = 0; 40static char show_pax = 0;
41static char show_perms = 0;
42static char show_size = 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;
53static char show_osabi = 0;
54static char show_eabi = 0;
54static char be_quiet = 0; 55static char be_quiet = 0;
55static char be_verbose = 0; 56static char be_verbose = 0;
56static char be_wewy_wewy_quiet = 0; 57static char be_wewy_wewy_quiet = 0;
57static char *find_sym = NULL, *versioned_symname = NULL; 58static char be_semi_verbose = 0;
59static char *find_sym = NULL;
58static char *find_lib = NULL; 60static char *find_lib = NULL;
59static char *find_section = NULL; 61static char *find_section = NULL;
60static char *out_format = NULL; 62static char *out_format = NULL;
61static char *search_path = NULL; 63static char *search_path = NULL;
62static char fix_elf = 0; 64static char fix_elf = 0;
63static char gmatch = 0; 65static char g_match = 0;
64static char use_ldcache = 0; 66static char use_ldcache = 0;
65 67
68static char **qa_textrels = NULL;
69static char **qa_execstack = NULL;
70static char **qa_wx_load = NULL;
71
66int match_bits = 0; 72static int match_bits = 0;
67caddr_t ldcache = 0; 73static unsigned int match_perms = 0;
74static void *ldcache = NULL;
68size_t ldcache_size = 0; 75static size_t ldcache_size = 0;
69unsigned long setpax = 0UL; 76static unsigned long setpax = 0UL;
77
78static int has_objdump = 0;
79
80/* find the path to a file by name */
81static char *which(const char *fname)
82{
83 static char fullpath[__PAX_UTILS_PATH_MAX];
84 char *path, *p;
85
86 path = getenv("PATH");
87 if (!path)
88 return NULL;
89
90 path = xstrdup(path);
91 while ((p = strrchr(path, ':')) != NULL) {
92 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
93 *p = 0;
94 if (access(fullpath, R_OK) != -1) {
95 free(path);
96 return fullpath;
97 }
98 }
99 free(path);
100 return NULL;
101}
102
103/* 1 on failure. 0 otherwise */
104static int rematch(const char *regex, const char *match, int cflags)
105{
106 regex_t preg;
107 int ret;
108
109 if ((match == NULL) || (regex == NULL))
110 return EXIT_FAILURE;
111
112 if ((ret = regcomp(&preg, regex, cflags))) {
113 char err[256];
114
115 if (regerror(ret, &preg, err, sizeof(err)))
116 fprintf(stderr, "regcomp failed: %s", err);
117 else
118 fprintf(stderr, "regcomp failed");
119
120 return EXIT_FAILURE;
121 }
122 ret = regexec(&preg, match, 0, NULL, 0);
123 regfree(&preg);
124
125 return ret;
126}
70 127
71/* sub-funcs for scanelf_file() */ 128/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 129static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{ 130{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 131 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
132
133 /* debug sections */
134 void *symtab = elf_findsecbyname(elf, ".symtab");
135 void *strtab = elf_findsecbyname(elf, ".strtab");
136 /* runtime sections */
137 void *dynsym = elf_findsecbyname(elf, ".dynsym");
138 void *dynstr = elf_findsecbyname(elf, ".dynstr");
139
75#define GET_SYMTABS(B) \ 140#define GET_SYMTABS(B) \
76 if (elf->elf_class == ELFCLASS ## B) { \ 141 if (elf->elf_class == ELFCLASS ## B) { \
77 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
78 /* debug sections */ \
79 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
80 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
81 /* runtime sections */ \
82 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
83 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
84 if (symtab && dynsym) { \ 142 if (symtab && dynsym) { \
143 Elf ## B ## _Shdr *esymtab = symtab; \
144 Elf ## B ## _Shdr *edynsym = dynsym; \
85 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \ 145 *sym = (EGET(esymtab->sh_size) > EGET(edynsym->sh_size)) ? symtab : dynsym; \
86 } else { \ 146 } else \
87 *sym = (void*)(symtab ? symtab : dynsym); \ 147 *sym = symtab ? symtab : dynsym; \
88 } \
89 if (strtab && dynstr) { \ 148 if (strtab && dynstr) { \
149 Elf ## B ## _Shdr *estrtab = strtab; \
150 Elf ## B ## _Shdr *edynstr = dynstr; \
90 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \ 151 *tab = (EGET(estrtab->sh_size) > EGET(edynstr->sh_size)) ? strtab : dynstr; \
91 } else { \ 152 } else \
92 *tab = (void*)(strtab ? strtab : dynstr); \ 153 *tab = strtab ? strtab : dynstr; \
93 } \
94 } 154 }
95 GET_SYMTABS(32) 155 GET_SYMTABS(32)
96 GET_SYMTABS(64) 156 GET_SYMTABS(64)
97} 157}
98 158
116 continue; \ 176 continue; \
117 if (fix_elf && setpax) { \ 177 if (fix_elf && setpax) { \
118 /* set the paxctl flags */ \ 178 /* set the paxctl flags */ \
119 ESET(phdr[i].p_flags, setpax); \ 179 ESET(phdr[i].p_flags, setpax); \
120 } \ 180 } \
121 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 181 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
122 continue; \ 182 continue; \
123 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 183 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
124 *found_pax = 1; \ 184 *found_pax = 1; \
125 ++shown; \ 185 ++shown; \
126 break; \ 186 break; \
128 } 188 }
129 SHOW_PAX(32) 189 SHOW_PAX(32)
130 SHOW_PAX(64) 190 SHOW_PAX(64)
131 } 191 }
132 192
193 if (fix_elf && setpax) {
194 /* set the chpax settings */
195 if (elf->elf_class == ELFCLASS32) {
196 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
197 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
198 } else {
199 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
200 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
201 }
202 }
203
133 /* fall back to EI_PAX if no PT_PAX was found */ 204 /* fall back to EI_PAX if no PT_PAX was found */
134 if (!*ret) { 205 if (!*ret) {
135 static char *paxflags; 206 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)); 207 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
143 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 208 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
144 *found_pax = 1; 209 *found_pax = 1;
145 return (be_wewy_wewy_quiet ? NULL : paxflags); 210 return (be_wewy_wewy_quiet ? NULL : paxflags);
146 } 211 }
176 uint32_t flags, check_flags; \ 241 uint32_t flags, check_flags; \
177 if (elf->phdr != NULL) { \ 242 if (elf->phdr != NULL) { \
178 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 243 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
179 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 244 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
180 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 245 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
246 if (multi_stack++) \
181 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 247 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
248 if (file_matches_list(elf->filename, qa_execstack)) \
249 continue; \
182 found = found_phdr; \ 250 found = found_phdr; \
183 offset = 0; \ 251 offset = 0; \
184 check_flags = PF_X; \ 252 check_flags = PF_X; \
185 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 253 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
254 if (multi_relro++) \
186 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 255 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
187 found = found_relro; \ 256 found = found_relro; \
188 offset = 4; \ 257 offset = 4; \
189 check_flags = PF_X; \ 258 check_flags = PF_X; \
190 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 259 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
191 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \ 260 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
261 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); \ 262 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
263 if (file_matches_list(elf->filename, qa_wx_load)) \
264 continue; \
193 found = found_load; \ 265 found = found_load; \
194 offset = 8; \ 266 offset = 8; \
195 check_flags = PF_W|PF_X; \ 267 check_flags = PF_W|PF_X; \
196 } else \ 268 } else \
197 continue; \ 269 continue; \
198 flags = EGET(phdr[i].p_flags); \ 270 flags = EGET(phdr[i].p_flags); \
199 if (be_quiet && ((flags & check_flags) != check_flags)) \ 271 if (be_quiet && ((flags & check_flags) != check_flags)) \
200 continue; \ 272 continue; \
201 if (fix_elf && ((flags & PF_X) != flags)) { \ 273 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)); \ 274 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
203 ret[3] = ret[7] = '!'; \ 275 ret[3] = ret[7] = '!'; \
204 flags = EGET(phdr[i].p_flags); \ 276 flags = EGET(phdr[i].p_flags); \
205 } \ 277 } \
206 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 278 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
234 break; \ 306 break; \
235 } \ 307 } \
236 } \ 308 } \
237 skip_this_shdr##B: \ 309 skip_this_shdr##B: \
238 if (!multi_stack) { \ 310 if (!multi_stack) { \
311 if (file_matches_list(elf->filename, qa_execstack)) \
312 return NULL; \
239 *found_phdr = 1; \ 313 *found_phdr = 1; \
240 shown = 1; \ 314 shown = 1; \
241 memcpy(ret, "!WX", 3); \ 315 memcpy(ret, "!WX", 3); \
242 } \ 316 } \
243 } \ 317 } \
248 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 322 if (be_wewy_wewy_quiet || (be_quiet && !shown))
249 return NULL; 323 return NULL;
250 else 324 else
251 return ret; 325 return ret;
252} 326}
327
328/*
329 * See if this ELF contains a DT_TEXTREL tag in any of its
330 * PT_DYNAMIC sections.
331 */
253static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 332static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
254{ 333{
255 static const char *ret = "TEXTREL"; 334 static const char *ret = "TEXTREL";
256 unsigned long i; 335 unsigned long i;
257 336
258 if (!show_textrel && !show_textrels) return NULL; 337 if (!show_textrel && !show_textrels) return NULL;
338
339 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
259 340
260 if (elf->phdr) { 341 if (elf->phdr) {
261#define SHOW_TEXTREL(B) \ 342#define SHOW_TEXTREL(B) \
262 if (elf->elf_class == ELFCLASS ## B) { \ 343 if (elf->elf_class == ELFCLASS ## B) { \
263 Elf ## B ## _Dyn *dyn; \ 344 Elf ## B ## _Dyn *dyn; \
264 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 345 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
265 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 346 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
266 Elf ## B ## _Off offset; \ 347 Elf ## B ## _Off offset; \
267 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 348 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
268 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 349 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
269 offset = EGET(phdr[i].p_offset); \ 350 offset = EGET(phdr[i].p_offset); \
270 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 351 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
271 dyn = DYN ## B (elf->data + offset); \ 352 dyn = DYN ## B (elf->data + offset); \
272 while (EGET(dyn->d_tag) != DT_NULL) { \ 353 while (EGET(dyn->d_tag) != DT_NULL) { \
273 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 354 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
285 if (be_quiet || be_wewy_wewy_quiet) 366 if (be_quiet || be_wewy_wewy_quiet)
286 return NULL; 367 return NULL;
287 else 368 else
288 return " - "; 369 return " - ";
289} 370}
371
372/*
373 * Scan the .text section to see if there are any relocations in it.
374 * Should rewrite this to check PT_LOAD sections that are marked
375 * Executable rather than the section named '.text'.
376 */
290static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 377static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
291{ 378{
292 unsigned long s, r, rmax; 379 unsigned long s, r, rmax;
293 void *symtab_void, *strtab_void, *text_void; 380 void *symtab_void, *strtab_void, *text_void;
294 381
361 /* show the raw details about this reloc */ \ 448 /* show the raw details about this reloc */ \
362 printf(" %s: ", elf->base_filename); \ 449 printf(" %s: ", elf->base_filename); \
363 if (sym && sym->st_name) \ 450 if (sym && sym->st_name) \
364 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 451 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
365 else \ 452 else \
366 printf("(memory/fake?)"); \ 453 printf("(memory/data?)"); \
367 printf(" [0x%lX]", (unsigned long)r_offset); \ 454 printf(" [0x%lX]", (unsigned long)r_offset); \
368 /* now try to find the closest symbol that this rel is probably in */ \ 455 /* now try to find the closest symbol that this rel is probably in */ \
369 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 456 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
370 func = NULL; \ 457 func = NULL; \
371 offset_tmp = 0; \ 458 offset_tmp = 0; \
375 offset_tmp = EGET(sym->st_value); \ 462 offset_tmp = EGET(sym->st_value); \
376 } \ 463 } \
377 ++sym; \ 464 ++sym; \
378 } \ 465 } \
379 printf(" in "); \ 466 printf(" in "); \
380 if (func && func->st_name) \ 467 if (func && func->st_name) { \
381 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ 468 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
469 if (r_offset > EGET(func->st_size)) \
470 printf("(optimized out: previous %s)", func_name); \
382 else \ 471 else \
383 printf("(NULL: fake?)"); \ 472 printf("%s", func_name); \
473 } else \
474 printf("(optimized out)"); \
384 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 475 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
476 if (be_verbose && has_objdump) { \
477 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
478 char *sysbuf; \
479 size_t syslen; \
480 int sysret; \
481 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"; \
482 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
483 sysbuf = xmalloc(syslen); \
484 if (end_addr < r_offset) \
485 /* not uncommon when things are optimized out */ \
486 end_addr = r_offset + 0x100; \
487 snprintf(sysbuf, syslen, sysfmt, \
488 (unsigned long)offset_tmp, \
489 (unsigned long)end_addr, \
490 elf->filename, \
491 (unsigned long)r_offset); \
492 fflush(stdout); \
493 sysret = system(sysbuf); \
494 fflush(stdout); \
495 free(sysbuf); \
496 } \
385 } \ 497 } \
386 } } 498 } }
387 SHOW_TEXTRELS(32) 499 SHOW_TEXTRELS(32)
388 SHOW_TEXTRELS(64) 500 SHOW_TEXTRELS(64)
389 } 501 }
407 warnf("Security problem NULL %s in %s", dt_type, elf->filename); 519 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
408 break; 520 break;
409 case '$': 521 case '$':
410 if (fstat(elf->fd, &st) != -1) 522 if (fstat(elf->fd, &st) != -1)
411 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 523 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", 524 warnf("Security problem with %s='%s' in %s with mode set of %o",
413 dt_type, item, elf->filename, st.st_mode & 07777); 525 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
414 break; 526 break;
415 default: 527 default:
416 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename); 528 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
417 break; 529 break;
418 } 530 }
438 Elf ## B ## _Off offset; \ 550 Elf ## B ## _Off offset; \
439 Elf ## B ## _Xword word; \ 551 Elf ## B ## _Xword word; \
440 /* Scan all the program headers */ \ 552 /* Scan all the program headers */ \
441 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 553 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
442 /* Just scan dynamic headers */ \ 554 /* Just scan dynamic headers */ \
443 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 555 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
444 offset = EGET(phdr[i].p_offset); \ 556 offset = EGET(phdr[i].p_offset); \
445 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 557 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
446 /* Just scan dynamic RPATH/RUNPATH headers */ \ 558 /* Just scan dynamic RPATH/RUNPATH headers */ \
447 dyn = DYN ## B (elf->data + offset); \ 559 dyn = DYN ## B (elf->data + offset); \
448 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 560 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
577#define FLAG_POWERPC_LIB64 0x0500 689#define FLAG_POWERPC_LIB64 0x0500
578#define FLAG_MIPS64_LIBN32 0x0600 690#define FLAG_MIPS64_LIBN32 0x0600
579#define FLAG_MIPS64_LIBN64 0x0700 691#define FLAG_MIPS64_LIBN64 0x0700
580 692
581static char *lookup_cache_lib(elfobj *, char *); 693static char *lookup_cache_lib(elfobj *, char *);
694
695#if defined(__GLIBC__) || defined(__UCLIBC__)
696
582static char *lookup_cache_lib(elfobj *elf, char *fname) 697static char *lookup_cache_lib(elfobj *elf, char *fname)
583{ 698{
584 int fd = 0; 699 int fd;
585 char *strs; 700 char *strs;
586 static char buf[__PAX_UTILS_PATH_MAX] = ""; 701 static char buf[__PAX_UTILS_PATH_MAX] = "";
587 const char *cachefile = "/etc/ld.so.cache"; 702 const char cachefile[] = "/etc/ld.so.cache";
588 struct stat st; 703 struct stat st;
589 704
590 typedef struct { 705 typedef struct {
591 char magic[LDSO_CACHE_MAGIC_LEN]; 706 char magic[LDSO_CACHE_MAGIC_LEN];
592 char version[LDSO_CACHE_VER_LEN]; 707 char version[LDSO_CACHE_VER_LEN];
602 libentry_t *libent; 717 libentry_t *libent;
603 718
604 if (fname == NULL) 719 if (fname == NULL)
605 return NULL; 720 return NULL;
606 721
607 if (ldcache == 0) { 722 if (ldcache == NULL) {
608 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1) 723 if (stat(cachefile, &st))
724 return NULL;
725
726 fd = open(cachefile, O_RDONLY);
727 if (fd == -1)
609 return NULL; 728 return NULL;
610 729
611 /* cache these values so we only map/unmap the cache file once */ 730 /* cache these values so we only map/unmap the cache file once */
612 ldcache_size = st.st_size; 731 ldcache_size = st.st_size;
613 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); 732 header = ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
614
615 close(fd); 733 close(fd);
616 734
617 if (ldcache == (caddr_t)-1) { 735 if (ldcache == MAP_FAILED) {
618 ldcache = 0; 736 ldcache = NULL;
619 return NULL; 737 return NULL;
620 } 738 }
621 739
622 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 740 if (memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
741 memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
742 {
743 munmap(ldcache, ldcache_size);
744 ldcache = NULL;
623 return NULL; 745 return NULL;
624 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
625 return NULL;
626 } 746 }
747 } else
748 header = ldcache;
627 749
628 header = (header_t *) ldcache;
629 libent = (libentry_t *) (ldcache + sizeof(header_t)); 750 libent = ldcache + sizeof(header_t);
630 strs = (char *) &libent[header->nlibs]; 751 strs = (char *) &libent[header->nlibs];
631 752
632 for (fd = 0; fd < header->nlibs; fd++) { 753 for (fd = 0; fd < header->nlibs; ++fd) {
633 /* this should be more fine grained, but for now we assume that 754 /* This should be more fine grained, but for now we assume that
634 * diff arches will not be cached together. and we ignore the 755 * diff arches will not be cached together, and we ignore the
635 * the different multilib mips cases. */ 756 * the different multilib mips cases.
757 */
636 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK)) 758 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
637 continue; 759 continue;
638 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK)) 760 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
639 continue; 761 continue;
640 762
641 if (strcmp(fname, strs + libent[fd].sooffset) != 0) 763 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
642 continue; 764 continue;
765
766 /* Return first hit because that is how the ldso rolls */
643 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 767 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
768 break;
644 } 769 }
770
645 return buf; 771 return buf;
646} 772}
647 773
774#elif defined(__NetBSD__)
775static char *lookup_cache_lib(elfobj *elf, char *fname)
776{
777 static char buf[__PAX_UTILS_PATH_MAX] = "";
778 static struct stat st;
779
780 char **ldpath;
781 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
782 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
783 continue; /* if the pathname is too long, or something went wrong, ignore */
784
785 if (stat(buf, &st) != 0)
786 continue; /* if the lib doesn't exist in *ldpath, look further */
787
788 /* NetBSD doesn't actually do sanity checks, it just loads the file
789 * and if that doesn't work, continues looking in other directories.
790 * This cannot easily be safely emulated, unfortunately. For now,
791 * just assume that if it exists, it's a valid library. */
792
793 return buf;
794 }
795
796 /* not found in any path */
797 return NULL;
798}
799#else
800#ifdef __ELF__
801#warning Cache support not implemented for your target
802#endif
803static char *lookup_cache_lib(elfobj *elf, char *fname)
804{
805 return NULL;
806}
807#endif
648 808
649static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 809static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
650{ 810{
651 unsigned long i; 811 unsigned long i;
652 char *needed; 812 char *needed;
664 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 824 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
665 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 825 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
666 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 826 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
667 Elf ## B ## _Off offset; \ 827 Elf ## B ## _Off offset; \
668 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 828 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
669 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 829 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
670 offset = EGET(phdr[i].p_offset); \ 830 offset = EGET(phdr[i].p_offset); \
671 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 831 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
672 dyn = DYN ## B (elf->data + offset); \ 832 dyn = DYN ## B (elf->data + offset); \
673 while (EGET(dyn->d_tag) != DT_NULL) { \ 833 while (EGET(dyn->d_tag) != DT_NULL) { \
674 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 834 if (EGET(dyn->d_tag) == DT_NEEDED) { \
686 needed = p; \ 846 needed = p; \
687 xstrcat(ret, needed, ret_len); \ 847 xstrcat(ret, needed, ret_len); \
688 } \ 848 } \
689 *found_needed = 1; \ 849 *found_needed = 1; \
690 } else { \ 850 } else { \
691 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 851 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
692 *found_lib = 1; \ 852 *found_lib = 1; \
693 return (be_wewy_wewy_quiet ? NULL : needed); \ 853 return (be_wewy_wewy_quiet ? NULL : needed); \
694 } \ 854 } \
695 } \ 855 } \
696 } \ 856 } \
727} 887}
728static char *scanelf_file_bind(elfobj *elf, char *found_bind) 888static char *scanelf_file_bind(elfobj *elf, char *found_bind)
729{ 889{
730 unsigned long i; 890 unsigned long i;
731 struct stat s; 891 struct stat s;
892 char dynamic = 0;
732 893
733 if (!show_bind) return NULL; 894 if (!show_bind) return NULL;
734 if (!elf->phdr) return NULL; 895 if (!elf->phdr) return NULL;
735 896
736#define SHOW_BIND(B) \ 897#define SHOW_BIND(B) \
738 Elf ## B ## _Dyn *dyn; \ 899 Elf ## B ## _Dyn *dyn; \
739 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 900 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
740 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 901 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
741 Elf ## B ## _Off offset; \ 902 Elf ## B ## _Off offset; \
742 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 903 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
743 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 904 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
905 dynamic = 1; \
744 offset = EGET(phdr[i].p_offset); \ 906 offset = EGET(phdr[i].p_offset); \
745 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 907 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
746 dyn = DYN ## B (elf->data + offset); \ 908 dyn = DYN ## B (elf->data + offset); \
747 while (EGET(dyn->d_tag) != DT_NULL) { \ 909 while (EGET(dyn->d_tag) != DT_NULL) { \
748 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 910 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
759 SHOW_BIND(32) 921 SHOW_BIND(32)
760 SHOW_BIND(64) 922 SHOW_BIND(64)
761 923
762 if (be_wewy_wewy_quiet) return NULL; 924 if (be_wewy_wewy_quiet) return NULL;
763 925
926 /* 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)) { 927 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
765 return NULL; 928 return NULL;
766 } else { 929 } else {
767 *found_bind = 1; 930 *found_bind = 1;
768 return (char *) "LAZY"; 931 return (char *) (dynamic ? "LAZY" : "STATIC");
769 } 932 }
770} 933}
771static char *scanelf_file_soname(elfobj *elf, char *found_soname) 934static char *scanelf_file_soname(elfobj *elf, char *found_soname)
772{ 935{
773 unsigned long i; 936 unsigned long i;
785 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 948 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
786 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 949 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
787 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 950 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
788 Elf ## B ## _Off offset; \ 951 Elf ## B ## _Off offset; \
789 /* only look for soname in shared objects */ \ 952 /* only look for soname in shared objects */ \
790 if (ehdr->e_type != ET_DYN) \ 953 if (EGET(ehdr->e_type) != ET_DYN) \
791 return NULL; \ 954 return NULL; \
792 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 955 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
793 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 956 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
794 offset = EGET(phdr[i].p_offset); \ 957 offset = EGET(phdr[i].p_offset); \
795 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 958 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
796 dyn = DYN ## B (elf->data + offset); \ 959 dyn = DYN ## B (elf->data + offset); \
797 while (EGET(dyn->d_tag) != DT_NULL) { \ 960 while (EGET(dyn->d_tag) != DT_NULL) { \
798 if (EGET(dyn->d_tag) == DT_SONAME) { \ 961 if (EGET(dyn->d_tag) == DT_SONAME) { \
812 SHOW_SONAME(64) 975 SHOW_SONAME(64)
813 } 976 }
814 977
815 return NULL; 978 return NULL;
816} 979}
980
981/*
982 * We support the symbol form:
983 * [%[modifiers]%][[+-]<symbol name>][,[.....]]
984 * If the symbol name is empty, then all symbols are matched.
985 * If the symbol name is a glob ("*"), then all symbols are dumped (debug).
986 * Do not rely on this output format at all.
987 * Otherwise the symbol name is used to search (either regex or string compare).
988 * If the first char of the symbol name is a plus ("+"), then only match
989 * defined symbols. If it's a minus ("-"), only match undefined symbols.
990 * Putting modifiers in between the percent signs allows for more in depth
991 * filters. There are groups of modifiers. If you don't specify a member
992 * of a group, then all types in that group are matched. The current
993 * groups and their types are:
994 * STT group: STT_NOTYPE:n STT_OBJECT:o STT_FUNC:f SST_FILE:F
995 * STB group: STB_LOCAL:l STB_GLOBAL:g STB_WEAK:w
996 * SHN group: SHN_UNDEF:u SHN_ABS:a SHN_COMMON:c {defined}:d
997 * The "defined" value in the SHN group does not correspond to a SHN_xxx define.
998 * You can search for multiple symbols at once by seperating with a comma (",").
999 *
1000 * Some examples:
1001 * ELFs with a weak function "foo":
1002 * scanelf -s %wf%foo <ELFs>
1003 * ELFs that define the symbol "main":
1004 * scanelf -s +main <ELFs>
1005 * scanelf -s %d%main <ELFs>
1006 * ELFs that refer to the undefined symbol "brk":
1007 * scanelf -s -brk <ELFs>
1008 * scanelf -s %u%brk <ELFs>
1009 * All global defined objects in an ELF:
1010 * scanelf -s %ogd% <ELF>
1011 */
1012static void
1013scanelf_match_symname(elfobj *elf, char *found_sym, char **ret, size_t *ret_len, const char *symname,
1014 unsigned int stt, unsigned int stb, unsigned int shn, unsigned long size)
1015{
1016 char *this_sym, *next_sym, saved = saved;
1017
1018 /* allow the user to specify a comma delimited list of symbols to search for */
1019 next_sym = NULL;
1020 do {
1021 bool inc_notype, inc_object, inc_func, inc_file,
1022 inc_local, inc_global, inc_weak,
1023 inc_def, inc_undef, inc_abs, inc_common;
1024
1025 if (next_sym) {
1026 next_sym[-1] = saved;
1027 this_sym = next_sym;
1028 } else
1029 this_sym = find_sym;
1030 if ((next_sym = strchr(this_sym, ','))) {
1031 /* make parsing easier by killing the comma temporarily */
1032 saved = *next_sym;
1033 *next_sym = '\0';
1034 next_sym += 1;
1035 }
1036
1037 /* symbol selection! */
1038 inc_notype = inc_object = inc_func = inc_file = \
1039 inc_local = inc_global = inc_weak = \
1040 inc_def = inc_undef = inc_abs = inc_common = \
1041 (*this_sym != '%');
1042
1043 /* parse the contents of %...% */
1044 if (!inc_notype) {
1045 while (*(this_sym++)) {
1046 if (*this_sym == '%') {
1047 ++this_sym;
1048 break;
1049 }
1050 switch (*this_sym) {
1051 case 'n': inc_notype = true; break;
1052 case 'o': inc_object = true; break;
1053 case 'f': inc_func = true; break;
1054 case 'F': inc_file = true; break;
1055 case 'l': inc_local = true; break;
1056 case 'g': inc_global = true; break;
1057 case 'w': inc_weak = true; break;
1058 case 'd': inc_def = true; break;
1059 case 'u': inc_undef = true; break;
1060 case 'a': inc_abs = true; break;
1061 case 'c': inc_common = true; break;
1062 default: err("invalid symbol selector '%c'", *this_sym);
1063 }
1064 }
1065
1066 /* If no types are matched, not match all */
1067 if (!inc_notype && !inc_object && !inc_func && !inc_file)
1068 inc_notype = inc_object = inc_func = inc_file = true;
1069 if (!inc_local && !inc_global && !inc_weak)
1070 inc_local = inc_global = inc_weak = true;
1071 if (!inc_def && !inc_undef && !inc_abs && !inc_common)
1072 inc_def = inc_undef = inc_abs = inc_common = true;
1073
1074 /* backwards compat for defined/undefined short hand */
1075 } else if (*this_sym == '+') {
1076 inc_undef = false;
1077 ++this_sym;
1078 } else if (*this_sym == '-') {
1079 inc_def = inc_abs = inc_common = false;
1080 ++this_sym;
1081 }
1082
1083 /* filter symbols */
1084 if ((!inc_notype && stt == STT_NOTYPE) || \
1085 (!inc_object && stt == STT_OBJECT) || \
1086 (!inc_func && stt == STT_FUNC ) || \
1087 (!inc_file && stt == STT_FILE ) || \
1088 (!inc_local && stb == STB_LOCAL ) || \
1089 (!inc_global && stb == STB_GLOBAL) || \
1090 (!inc_weak && stb == STB_WEAK ) || \
1091 (!inc_def && shn && shn < SHN_LORESERVE) || \
1092 (!inc_undef && shn == SHN_UNDEF ) || \
1093 (!inc_abs && shn == SHN_ABS ) || \
1094 (!inc_common && shn == SHN_COMMON))
1095 continue;
1096
1097 if (*this_sym == '*') {
1098 /* a "*" symbol gets you debug output */
1099 printf("%s(%s) %5lX %15s %15s %15s %s\n",
1100 ((*found_sym == 0) ? "\n\t" : "\t"),
1101 elf->base_filename,
1102 size,
1103 get_elfstttype(stt),
1104 get_elfstbtype(stb),
1105 get_elfshntype(shn),
1106 symname);
1107 goto matched;
1108
1109 } else {
1110 if (g_match) {
1111 /* regex match the symbol */
1112 if (rematch(this_sym, symname, REG_EXTENDED) != 0)
1113 continue;
1114
1115 } else if (*this_sym) {
1116 /* give empty symbols a "pass", else do a normal compare */
1117 const size_t len = strlen(this_sym);
1118 if (!(strncmp(this_sym, symname, len) == 0 &&
1119 /* Accept unversioned symbol names */
1120 (symname[len] == '\0' || symname[len] == '@')))
1121 continue;
1122 }
1123
1124 if (be_semi_verbose) {
1125 char buf[1024];
1126 snprintf(buf, sizeof(buf), "%lX %s %s",
1127 size,
1128 get_elfstttype(stt),
1129 this_sym);
1130 *ret = xstrdup(buf);
1131 } else {
1132 if (*ret) xchrcat(ret, ',', ret_len);
1133 xstrcat(ret, symname, ret_len);
1134 }
1135
1136 goto matched;
1137 }
1138 } while (next_sym);
1139
1140 return;
1141
1142 matched:
1143 *found_sym = 1;
1144 if (next_sym)
1145 next_sym[-1] = saved;
1146}
1147
817static char *scanelf_file_sym(elfobj *elf, char *found_sym) 1148static char *scanelf_file_sym(elfobj *elf, char *found_sym)
818{ 1149{
819 unsigned long i; 1150 unsigned long i;
820 char *ret; 1151 char *ret;
821 void *symtab_void, *strtab_void; 1152 void *symtab_void, *strtab_void;
822 1153
823 if (!find_sym) return NULL; 1154 if (!find_sym) return NULL;
824 ret = find_sym; 1155 ret = NULL;
825 1156
826 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 1157 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
827 1158
828 if (symtab_void && strtab_void) { 1159 if (symtab_void && strtab_void) {
829#define FIND_SYM(B) \ 1160#define FIND_SYM(B) \
831 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 1162 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
832 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 1163 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
833 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 1164 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
834 unsigned long cnt = EGET(symtab->sh_entsize); \ 1165 unsigned long cnt = EGET(symtab->sh_entsize); \
835 char *symname; \ 1166 char *symname; \
1167 size_t ret_len = 0; \
836 if (cnt) \ 1168 if (cnt) \
837 cnt = EGET(symtab->sh_size) / cnt; \ 1169 cnt = EGET(symtab->sh_size) / cnt; \
838 for (i = 0; i < cnt; ++i) { \ 1170 for (i = 0; i < cnt; ++i) { \
1171 if ((void*)sym > (void*)elf->data_end) { \
1172 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1173 goto break_out; \
1174 } \
839 if (sym->st_name) { \ 1175 if (sym->st_name) { \
1176 /* make sure the symbol name is in acceptable memory range */ \
840 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1177 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
841 if ((void*)symname > (void*)elf->data_end) { \ 1178 if ((void*)symname > (void*)elf->data_end) { \
842 warnf("%s: corrupt ELF symbols", elf->filename); \ 1179 warnf("%s: corrupt ELF symbols", elf->filename); \
1180 ++sym; \
843 continue; \ 1181 continue; \
844 } \ 1182 } \
845 if (*find_sym == '*') { \ 1183 scanelf_match_symname(elf, found_sym, \
846 printf("%s(%s) %5lX %15s %s\n", \ 1184 &ret, &ret_len, symname, \
847 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1185 ELF##B##_ST_TYPE(EGET(sym->st_info)), \
848 elf->base_filename, \ 1186 ELF##B##_ST_BIND(EGET(sym->st_info)), \
849 (unsigned long)sym->st_size, \ 1187 EGET(sym->st_shndx), \
850 get_elfstttype(sym->st_info), \ 1188 /* st_size can be 64bit, but no one is really that big, so screw em */ \
851 symname); \ 1189 EGET(sym->st_size)); \
852 *found_sym = 1; \
853 } else { \
854 char *this_sym, *next_sym; \
855 this_sym = find_sym; \
856 do { \
857 next_sym = strchr(this_sym, ','); \
858 if (next_sym == NULL) \
859 next_sym = this_sym + strlen(this_sym); \
860 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
861 (strcmp(symname, versioned_symname) == 0)) { \
862 ret = this_sym; \
863 (*found_sym)++; \
864 goto break_out; \
865 } \
866 this_sym = next_sym + 1; \
867 } while (*next_sym != '\0'); \
868 } \
869 } \ 1190 } \
870 ++sym; \ 1191 ++sym; \
871 } } 1192 } }
872 FIND_SYM(32) 1193 FIND_SYM(32)
873 FIND_SYM(64) 1194 FIND_SYM(64)
882 return NULL; 1203 return NULL;
883 else 1204 else
884 return (char *)" - "; 1205 return (char *)" - ";
885} 1206}
886 1207
887
888static char *scanelf_file_sections(elfobj *elf, char *found_section) 1208static char *scanelf_file_sections(elfobj *elf, char *found_section)
889{ 1209{
890 if (!find_section) 1210 if (!find_section)
891 return NULL; 1211 return NULL;
892 1212
893#define FIND_SECTION(B) \ 1213#define FIND_SECTION(B) \
894 if (elf->elf_class == ELFCLASS ## B) { \ 1214 if (elf->elf_class == ELFCLASS ## B) { \
1215 int invert; \
895 Elf ## B ## _Shdr *section; \ 1216 Elf ## B ## _Shdr *section; \
1217 invert = (*find_section == '!' ? 1 : 0); \
896 section = SHDR ## B (elf_findsecbyname(elf, find_section)); \ 1218 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
897 if (section != NULL) \ 1219 if ((section == NULL && invert) || (section != NULL && !invert)) \
898 *found_section = 1; \ 1220 *found_section = 1; \
899 } 1221 }
900 FIND_SECTION(32) 1222 FIND_SECTION(32)
901 FIND_SECTION(64) 1223 FIND_SECTION(64)
902 1224
903
904 if (be_wewy_wewy_quiet) return NULL; 1225 if (be_wewy_wewy_quiet)
1226 return NULL;
905 1227
906 if (*found_section) 1228 if (*found_section)
907 return find_section; 1229 return find_section;
908 1230
909 if (be_quiet) 1231 if (be_quiet)
911 else 1233 else
912 return (char *)" - "; 1234 return (char *)" - ";
913} 1235}
914 1236
915/* scan an elf file and show all the fun stuff */ 1237/* scan an elf file and show all the fun stuff */
916#define prints(str) write(fileno(stdout), str, strlen(str)) 1238#define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
917static int scanelf_elfobj(elfobj *elf) 1239static int scanelf_elfobj(elfobj *elf)
918{ 1240{
919 unsigned long i; 1241 unsigned long i;
920 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1242 char found_pax, found_phdr, found_relro, found_load, found_textrel,
921 found_rpath, found_needed, found_interp, found_bind, found_soname, 1243 found_rpath, found_needed, found_interp, found_bind, found_soname,
922 found_sym, found_lib, found_file, found_textrels, found_section; 1244 found_sym, found_lib, found_file, found_textrels, found_section;
923 static char *out_buffer = NULL; 1245 static char *out_buffer = NULL;
924 static size_t out_len; 1246 static size_t out_len;
925 1247
926 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1248 found_pax = found_phdr = found_relro = found_load = found_textrel = \
935 printf("%s: scanning file\n", elf->filename); 1257 printf("%s: scanning file\n", elf->filename);
936 1258
937 /* init output buffer */ 1259 /* init output buffer */
938 if (!out_buffer) { 1260 if (!out_buffer) {
939 out_len = sizeof(char) * 80; 1261 out_len = sizeof(char) * 80;
940 out_buffer = (char*)xmalloc(out_len); 1262 out_buffer = xmalloc(out_len);
941 } 1263 }
942 *out_buffer = '\0'; 1264 *out_buffer = '\0';
943 1265
944 /* show the header */ 1266 /* show the header */
945 if (!be_quiet && show_banner) { 1267 if (!be_quiet && show_banner) {
946 for (i = 0; out_format[i]; ++i) { 1268 for (i = 0; out_format[i]; ++i) {
947 if (!IS_MODIFIER(out_format[i])) continue; 1269 if (!IS_MODIFIER(out_format[i])) continue;
948 1270
949 switch (out_format[++i]) { 1271 switch (out_format[++i]) {
1272 case '+': break;
950 case '%': break; 1273 case '%': break;
951 case '#': break; 1274 case '#': break;
952 case 'F': 1275 case 'F':
953 case 'p': 1276 case 'p':
954 case 'f': prints("FILE "); found_file = 1; break; 1277 case 'f': prints("FILE "); found_file = 1; break;
955 case 'o': prints(" TYPE "); break; 1278 case 'o': prints(" TYPE "); break;
956 case 'x': prints(" PAX "); break; 1279 case 'x': prints(" PAX "); break;
957 case 'e': prints("STK/REL/PTL "); break; 1280 case 'e': prints("STK/REL/PTL "); break;
958 case 't': prints("TEXTREL "); break; 1281 case 't': prints("TEXTREL "); break;
959 case 'r': prints("RPATH "); break; 1282 case 'r': prints("RPATH "); break;
1283 case 'M': prints("CLASS "); break;
960 case 'n': prints("NEEDED "); break; 1284 case 'n': prints("NEEDED "); break;
961 case 'i': prints("INTERP "); break; 1285 case 'i': prints("INTERP "); break;
962 case 'b': prints("BIND "); break; 1286 case 'b': prints("BIND "); break;
1287 case 'Z': prints("SIZE "); break;
963 case 'S': prints("SONAME "); break; 1288 case 'S': prints("SONAME "); break;
964 case 's': prints("SYM "); break; 1289 case 's': prints("SYM "); break;
965 case 'N': prints("LIB "); break; 1290 case 'N': prints("LIB "); break;
966 case 'T': prints("TEXTRELS "); break; 1291 case 'T': prints("TEXTRELS "); break;
967 case 'k': prints("SECTION "); break; 1292 case 'k': prints("SECTION "); break;
1293 case 'a': prints("ARCH "); break;
1294 case 'I': prints("OSABI "); break;
1295 case 'Y': prints("EABI "); break;
1296 case 'O': prints("PERM "); break;
1297 case 'D': prints("ENDIAN "); break;
968 default: warnf("'%c' has no title ?", out_format[i]); 1298 default: warnf("'%c' has no title ?", out_format[i]);
969 } 1299 }
970 } 1300 }
971 if (!found_file) prints("FILE "); 1301 if (!found_file) prints("FILE ");
972 prints("\n"); 1302 prints("\n");
976 1306
977 /* dump all the good stuff */ 1307 /* dump all the good stuff */
978 for (i = 0; out_format[i]; ++i) { 1308 for (i = 0; out_format[i]; ++i) {
979 const char *out; 1309 const char *out;
980 const char *tmp; 1310 const char *tmp;
981 1311 static char ubuf[sizeof(unsigned long)*2];
982 if (!IS_MODIFIER(out_format[i])) { 1312 if (!IS_MODIFIER(out_format[i])) {
983 xchrcat(&out_buffer, out_format[i], &out_len); 1313 xchrcat(&out_buffer, out_format[i], &out_len);
984 continue; 1314 continue;
985 } 1315 }
986 1316
987 out = NULL; 1317 out = NULL;
988 be_wewy_wewy_quiet = (out_format[i] == '#'); 1318 be_wewy_wewy_quiet = (out_format[i] == '#');
1319 be_semi_verbose = (out_format[i] == '+');
989 switch (out_format[++i]) { 1320 switch (out_format[++i]) {
1321 case '+':
990 case '%': 1322 case '%':
991 case '#': 1323 case '#':
992 xchrcat(&out_buffer, out_format[i], &out_len); break; 1324 xchrcat(&out_buffer, out_format[i], &out_len); break;
993 case 'F': 1325 case 'F':
994 found_file = 1; 1326 found_file = 1;
1020 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1352 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; 1353 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; 1354 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1023 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; 1355 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; 1356 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1357 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1358 case 'D': out = get_endian(elf); break;
1359 case 'O': out = strfileperms(elf->filename); break;
1025 case 'n': 1360 case 'n':
1026 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1361 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; 1362 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1028 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1363 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1029 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1364 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1030 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1365 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1031 case 'k': out = scanelf_file_sections(elf, &found_section); break; 1366 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1367 case 'a': out = get_elfemtype(elf); break;
1368 case 'I': out = get_elfosabi(elf); break;
1369 case 'Y': out = get_elf_eabi(elf); break;
1370 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]); 1371 default: warnf("'%c' has no scan code?", out_format[i]);
1033 } 1372 }
1034 if (out) { 1373 if (out)
1035 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1036 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1037 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1038 else
1039 xstrcat(&out_buffer, out, &out_len); 1374 xstrcat(&out_buffer, out, &out_len);
1040 }
1041 } 1375 }
1042 1376
1043#define FOUND_SOMETHING() \ 1377#define FOUND_SOMETHING() \
1044 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1378 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1045 found_rpath || found_needed || found_interp || found_bind || \ 1379 found_rpath || found_needed || found_interp || found_bind || \
1082 if (strlen(match_etypes)) { 1416 if (strlen(match_etypes)) {
1083 char sbuf[126]; 1417 char sbuf[126];
1084 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1418 strncpy(sbuf, match_etypes, sizeof(sbuf));
1085 if (strchr(match_etypes, ',') != NULL) { 1419 if (strchr(match_etypes, ',') != NULL) {
1086 char *p; 1420 char *p;
1087 while((p = strrchr(sbuf, ',')) != NULL) { 1421 while ((p = strrchr(sbuf, ',')) != NULL) {
1088 *p = 0; 1422 *p = 0;
1089 if (atoi(p+1) == get_etype(elf)) 1423 if (etype_lookup(p+1) == get_etype(elf))
1090 goto label_ret; 1424 goto label_ret;
1091 } 1425 }
1092 } 1426 }
1093 if (atoi(sbuf) != get_etype(elf)) 1427 if (etype_lookup(sbuf) != get_etype(elf))
1094 goto label_done; 1428 goto label_done;
1095 } 1429 }
1096 1430
1097label_ret: 1431label_ret:
1098 ret = scanelf_elfobj(elf); 1432 ret = scanelf_elfobj(elf);
1112 1446
1113 ar = ar_open_fd(filename, fd); 1447 ar = ar_open_fd(filename, fd);
1114 if (ar == NULL) 1448 if (ar == NULL)
1115 return 1; 1449 return 1;
1116 1450
1117 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0); 1451 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) { 1452 while ((m=ar_next(ar)) != NULL) {
1119 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size); 1453 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1120 if (elf) { 1454 if (elf) {
1121 scanelf_elfobj(elf); 1455 scanelf_elfobj(elf);
1122 unreadelf(elf); 1456 unreadelf(elf);
1125 munmap(ar_buffer, len); 1459 munmap(ar_buffer, len);
1126 1460
1127 return 0; 1461 return 0;
1128} 1462}
1129/* scan a file which may be an elf or an archive or some other magical beast */ 1463/* scan a file which may be an elf or an archive or some other magical beast */
1130static void scanelf_file(const char *filename) 1464static int scanelf_file(const char *filename, const struct stat *st_cache)
1131{ 1465{
1466 const struct stat *st = st_cache;
1132 struct stat st; 1467 struct stat symlink_st;
1133 int fd; 1468 int fd;
1134 1469
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 */ 1470 /* always handle regular files and handle symlinked files if no -y */
1142 if (S_ISLNK(st.st_mode)) { 1471 if (S_ISLNK(st->st_mode)) {
1143 if (!scan_symlink) return; 1472 if (!scan_symlink) return 1;
1144 stat(filename, &st); 1473 stat(filename, &symlink_st);
1474 st = &symlink_st;
1145 } 1475 }
1476
1146 if (!S_ISREG(st.st_mode)) { 1477 if (!S_ISREG(st->st_mode)) {
1147 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1478 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1148 return; 1479 return 1;
1149 } 1480 }
1150 1481
1482 if (match_perms) {
1483 if ((st->st_mode | match_perms) != st->st_mode)
1484 return 1;
1485 }
1151 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1486 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1152 return; 1487 return 1;
1153 1488
1154 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) 1489 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1155 /* if it isn't an ELF, maybe it's an .a archive */ 1490 /* if it isn't an ELF, maybe it's an .a archive */
1156 scanelf_archive(filename, fd, st.st_size); 1491 scanelf_archive(filename, fd, st->st_size);
1157 1492
1158 close(fd); 1493 close(fd);
1494 return 0;
1159} 1495}
1160 1496
1161/* scan a directory for ET_EXEC files and print when we find one */ 1497/* scan a directory for ET_EXEC files and print when we find one */
1162static void scanelf_dir(const char *path) 1498static int scanelf_dir(const char *path)
1163{ 1499{
1164 register DIR *dir; 1500 register DIR *dir;
1165 register struct dirent *dentry; 1501 register struct dirent *dentry;
1166 struct stat st_top, st; 1502 struct stat st_top, st;
1167 char buf[__PAX_UTILS_PATH_MAX]; 1503 char buf[__PAX_UTILS_PATH_MAX];
1168 size_t pathlen = 0, len = 0; 1504 size_t pathlen = 0, len = 0;
1505 int ret = 0;
1169 1506
1170 /* make sure path exists */ 1507 /* make sure path exists */
1171 if (lstat(path, &st_top) == -1) { 1508 if (lstat(path, &st_top) == -1) {
1172 if (be_verbose > 2) printf("%s: does not exist\n", path); 1509 if (be_verbose > 2) printf("%s: does not exist\n", path);
1173 return; 1510 return 1;
1174 } 1511 }
1175 1512
1176 /* ok, if it isn't a directory, assume we can open it */ 1513 /* ok, if it isn't a directory, assume we can open it */
1177 if (!S_ISDIR(st_top.st_mode)) { 1514 if (!S_ISDIR(st_top.st_mode)) {
1178 scanelf_file(path); 1515 return scanelf_file(path, &st_top);
1179 return;
1180 } 1516 }
1181 1517
1182 /* now scan the dir looking for fun stuff */ 1518 /* now scan the dir looking for fun stuff */
1183 if ((dir = opendir(path)) == NULL) { 1519 if ((dir = opendir(path)) == NULL) {
1184 warnf("could not opendir %s: %s", path, strerror(errno)); 1520 warnf("could not opendir %s: %s", path, strerror(errno));
1185 return; 1521 return 1;
1186 } 1522 }
1187 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1523 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1188 1524
1189 pathlen = strlen(path); 1525 pathlen = strlen(path);
1190 while ((dentry = readdir(dir))) { 1526 while ((dentry = readdir(dir))) {
1194 if (len >= sizeof(buf)) { 1530 if (len >= sizeof(buf)) {
1195 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1531 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1196 (unsigned long)len, (unsigned long)sizeof(buf)); 1532 (unsigned long)len, (unsigned long)sizeof(buf));
1197 continue; 1533 continue;
1198 } 1534 }
1199 sprintf(buf, "%s/%s", path, dentry->d_name); 1535 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1200 if (lstat(buf, &st) != -1) { 1536 if (lstat(buf, &st) != -1) {
1201 if (S_ISREG(st.st_mode)) 1537 if (S_ISREG(st.st_mode))
1202 scanelf_file(buf); 1538 ret = scanelf_file(buf, &st);
1203 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1539 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1204 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1540 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1205 scanelf_dir(buf); 1541 ret = scanelf_dir(buf);
1206 } 1542 }
1207 } 1543 }
1208 } 1544 }
1209 closedir(dir); 1545 closedir(dir);
1546 return ret;
1210} 1547}
1211 1548
1212static int scanelf_from_file(char *filename) 1549static int scanelf_from_file(const char *filename)
1213{ 1550{
1214 FILE *fp = NULL; 1551 FILE *fp = NULL;
1215 char *p; 1552 char *p;
1216 char path[__PAX_UTILS_PATH_MAX]; 1553 char path[__PAX_UTILS_PATH_MAX];
1554 int ret = 0;
1217 1555
1218 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1556 if (strcmp(filename, "-") == 0)
1219 fp = stdin; 1557 fp = stdin;
1220 else if ((fp = fopen(filename, "r")) == NULL) 1558 else if ((fp = fopen(filename, "r")) == NULL)
1221 return 1; 1559 return 1;
1222 1560
1223 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1561 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1224 if ((p = strchr(path, '\n')) != NULL) 1562 if ((p = strchr(path, '\n')) != NULL)
1225 *p = 0; 1563 *p = 0;
1226 search_path = path; 1564 search_path = path;
1227 scanelf_dir(path); 1565 ret = scanelf_dir(path);
1228 } 1566 }
1229 if (fp != stdin) 1567 if (fp != stdin)
1230 fclose(fp); 1568 fclose(fp);
1231 return 0; 1569 return ret;
1232} 1570}
1233 1571
1572#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1573
1234static int load_ld_so_conf(int i, const char *fname) 1574static int load_ld_cache_config(int i, const char *fname)
1235{ 1575{
1236 FILE *fp = NULL; 1576 FILE *fp = NULL;
1237 char *p; 1577 char *p;
1238 char path[__PAX_UTILS_PATH_MAX]; 1578 char path[__PAX_UTILS_PATH_MAX];
1239 1579
1240 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1580 if (i + 1 == ARRAY_SIZE(ldpaths))
1241 return i; 1581 return i;
1242 1582
1243 if ((fp = fopen(fname, "r")) == NULL) 1583 if ((fp = fopen(fname, "r")) == NULL)
1244 return i; 1584 return i;
1245 1585
1246 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1586 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1247 if ((p = strrchr(path, '\r')) != NULL) 1587 if ((p = strrchr(path, '\r')) != NULL)
1248 *p = 0; 1588 *p = 0;
1249 if ((p = strchr(path, '\n')) != NULL) 1589 if ((p = strchr(path, '\n')) != NULL)
1250 *p = 0; 1590 *p = 0;
1251#ifdef HAVE_GLOB 1591#ifdef __linux__
1252 // recursive includes of the same file will make this segfault. 1592 /* recursive includes of the same file will make this segfault. */
1253 if ((*path == 'i') && (strncmp(path, "include", 7) == 0) && isblank(path[7])) { 1593 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1254 glob64_t gl; 1594 glob64_t gl;
1255 size_t x; 1595 size_t x;
1256 char gpath[__PAX_UTILS_PATH_MAX]; 1596 char gpath[__PAX_UTILS_PATH_MAX];
1257 1597
1258 gpath[sizeof(gpath)] = 0; 1598 memset(gpath, 0, sizeof(gpath));
1259 1599
1260 if (path[8] != '/') 1600 if (path[8] != '/')
1261 snprintf(gpath, sizeof(gpath)-1, "/etc/%s", &path[8]); 1601 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1262 else 1602 else
1263 strncpy(gpath, &path[8], sizeof(gpath)-1); 1603 strncpy(gpath, &path[8], sizeof(gpath));
1264 1604
1265 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1605 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1266 for (x = 0; x < gl.gl_pathc; ++x) { 1606 for (x = 0; x < gl.gl_pathc; ++x) {
1267 /* try to avoid direct loops */ 1607 /* try to avoid direct loops */
1268 if (strcmp(gl.gl_pathv[x], fname) == 0) 1608 if (strcmp(gl.gl_pathv[x], fname) == 0)
1269 continue; 1609 continue;
1270 i = load_ld_so_conf(i, gl.gl_pathv[x]); 1610 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1271 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) { 1611 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1272 globfree64(&gl); 1612 globfree64(&gl);
1273 return i; 1613 return i;
1274 } 1614 }
1275 } 1615 }
1276 globfree64 (&gl); 1616 globfree64 (&gl);
1277 continue; 1617 continue;
1278 } else 1618 }
1279 abort();
1280 } 1619 }
1281#endif 1620#endif
1282 if (*path != '/') 1621 if (*path != '/')
1283 continue; 1622 continue;
1284 1623
1285 ldpaths[i++] = xstrdup(path); 1624 ldpaths[i++] = xstrdup(path);
1286 1625
1287 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1626 if (i + 1 == ARRAY_SIZE(ldpaths))
1288 break; 1627 break;
1289 } 1628 }
1290 ldpaths[i] = NULL; 1629 ldpaths[i] = NULL;
1291 1630
1292 fclose(fp); 1631 fclose(fp);
1293 return i; 1632 return i;
1294} 1633}
1295 1634
1635#elif defined(__FreeBSD__) || defined(__DragonFly__)
1636
1637static int load_ld_cache_config(int i, const char *fname)
1638{
1639 FILE *fp = NULL;
1640 char *b = NULL, *p;
1641 struct elfhints_hdr hdr;
1642
1643 if (i + 1 == ARRAY_SIZE(ldpaths))
1644 return i;
1645
1646 if ((fp = fopen(fname, "r")) == NULL)
1647 return i;
1648
1649 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1650 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1651 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1652 {
1653 fclose(fp);
1654 return i;
1655 }
1656
1657 b = xmalloc(hdr.dirlistlen + 1);
1658 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1659 fclose(fp);
1660 free(b);
1661 return i;
1662 }
1663
1664 while ((p = strsep(&b, ":"))) {
1665 if (*p == '\0') continue;
1666 ldpaths[i++] = xstrdup(p);
1667
1668 if (i + 1 == ARRAY_SIZE(ldpaths))
1669 break;
1670 }
1671 ldpaths[i] = NULL;
1672
1673 free(b);
1674 fclose(fp);
1675 return i;
1676}
1677
1678#else
1679#ifdef __ELF__
1680#warning Cache config support not implemented for your target
1681#endif
1682static int load_ld_cache_config(int i, const char *fname)
1683{
1684 memset(ldpaths, 0x00, sizeof(ldpaths));
1685 return 0;
1686}
1687#endif
1688
1296/* scan /etc/ld.so.conf for paths */ 1689/* scan /etc/ld.so.conf for paths */
1297static void scanelf_ldpath() 1690static void scanelf_ldpath(void)
1298{ 1691{
1299 char scan_l, scan_ul, scan_ull; 1692 char scan_l, scan_ul, scan_ull;
1300 int i = 0; 1693 int i = 0;
1301 1694
1302 if (!ldpaths[0]) 1695 if (!ldpaths[0])
1303 err("Unable to load any paths from ld.so.conf"); 1696 err("Unable to load any paths from ld.so.conf");
1304 1697
1305 scan_l = scan_ul = scan_ull = 0; 1698 scan_l = scan_ul = scan_ull = 0;
1306 1699
1307 while (ldpaths[i]) { 1700 while (ldpaths[i]) {
1308 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1; 1701 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1309 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1; 1702 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1310 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1; 1703 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1311 scanelf_dir(ldpaths[i]); 1704 scanelf_dir(ldpaths[i]);
1312 ++i; 1705 ++i;
1313 } 1706 }
1314 1707
1316 if (!scan_ul) scanelf_dir("/usr/lib"); 1709 if (!scan_ul) scanelf_dir("/usr/lib");
1317 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1710 if (!scan_ull) scanelf_dir("/usr/local/lib");
1318} 1711}
1319 1712
1320/* scan env PATH for paths */ 1713/* scan env PATH for paths */
1321static void scanelf_envpath() 1714static void scanelf_envpath(void)
1322{ 1715{
1323 char *path, *p; 1716 char *path, *p;
1324 1717
1325 path = getenv("PATH"); 1718 path = getenv("PATH");
1326 if (!path) 1719 if (!path)
1333 } 1726 }
1334 1727
1335 free(path); 1728 free(path);
1336} 1729}
1337 1730
1338/* usage / invocation handling functions */ 1731/* 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" 1732#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZBhV"
1340#define a_argument required_argument 1733#define a_argument required_argument
1341static struct option const long_opts[] = { 1734static struct option const long_opts[] = {
1342 {"path", no_argument, NULL, 'p'}, 1735 {"path", no_argument, NULL, 'p'},
1343 {"ldpath", no_argument, NULL, 'l'}, 1736 {"ldpath", no_argument, NULL, 'l'},
1344 {"recursive", no_argument, NULL, 'R'}, 1737 {"recursive", no_argument, NULL, 'R'},
1361 {"lib", a_argument, NULL, 'N'}, 1754 {"lib", a_argument, NULL, 'N'},
1362 {"gmatch", no_argument, NULL, 'g'}, 1755 {"gmatch", no_argument, NULL, 'g'},
1363 {"textrels", no_argument, NULL, 'T'}, 1756 {"textrels", no_argument, NULL, 'T'},
1364 {"etype", a_argument, NULL, 'E'}, 1757 {"etype", a_argument, NULL, 'E'},
1365 {"bits", a_argument, NULL, 'M'}, 1758 {"bits", a_argument, NULL, 'M'},
1759 {"endian", no_argument, NULL, 'D'},
1760 {"osabi", no_argument, NULL, 'I'},
1761 {"eabi", no_argument, NULL, 'Y'},
1762 {"perms", a_argument, NULL, 'O'},
1763 {"size", no_argument, NULL, 'Z'},
1366 {"all", no_argument, NULL, 'a'}, 1764 {"all", no_argument, NULL, 'a'},
1367 {"quiet", no_argument, NULL, 'q'}, 1765 {"quiet", no_argument, NULL, 'q'},
1368 {"verbose", no_argument, NULL, 'v'}, 1766 {"verbose", no_argument, NULL, 'v'},
1369 {"format", a_argument, NULL, 'F'}, 1767 {"format", a_argument, NULL, 'F'},
1370 {"from", a_argument, NULL, 'f'}, 1768 {"from", a_argument, NULL, 'f'},
1396 "Find a specified symbol", 1794 "Find a specified symbol",
1397 "Find a specified section", 1795 "Find a specified section",
1398 "Find a specified library", 1796 "Find a specified library",
1399 "Use strncmp to match libraries. (use with -N)", 1797 "Use strncmp to match libraries. (use with -N)",
1400 "Locate cause of TEXTREL", 1798 "Locate cause of TEXTREL",
1401 "Print only ELF files matching numeric constant type", 1799 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1402 "Print only ELF files matching numeric bits", 1800 "Print only ELF files matching numeric bits",
1403 "Print all scanned info (-x -e -t -r -b)\n", 1801 "Print Endianness",
1802 "Print OSABI",
1803 "Print EABI (EM_ARM Only)",
1804 "Print only ELF files matching octal permissions",
1805 "Print ELF file size",
1806 "Print all useful/simple info\n",
1404 "Only output 'bad' things", 1807 "Only output 'bad' things",
1405 "Be verbose (can be specified more than once)", 1808 "Be verbose (can be specified more than once)",
1406 "Use specified format for output", 1809 "Use specified format for output",
1407 "Read input stream from a filename", 1810 "Read input stream from a filename",
1408 "Write output stream to a filename", 1811 "Write output stream to a filename",
1419 printf("* Scan ELF binaries for stuff\n\n" 1822 printf("* Scan ELF binaries for stuff\n\n"
1420 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 1823 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1421 printf("Options: -[%s]\n", PARSE_FLAGS); 1824 printf("Options: -[%s]\n", PARSE_FLAGS);
1422 for (i = 0; long_opts[i].name; ++i) 1825 for (i = 0; long_opts[i].name; ++i)
1423 if (long_opts[i].has_arg == no_argument) 1826 if (long_opts[i].has_arg == no_argument)
1424 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 1827 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1425 long_opts[i].name, opts_help[i]); 1828 long_opts[i].name, opts_help[i]);
1426 else 1829 else
1427 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 1830 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1428 long_opts[i].name, opts_help[i]); 1831 long_opts[i].name, opts_help[i]);
1429 1832
1430 if (status != EXIT_SUCCESS) 1833 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); 1834 exit(status);
1447} 1835}
1448 1836
1449/* parse command line arguments and preform needed actions */ 1837/* parse command line arguments and preform needed actions */
1838#define do_pax_state(option, flag) \
1839 if (islower(option)) { \
1840 flags &= ~PF_##flag; \
1841 flags |= PF_NO##flag; \
1842 } else { \
1843 flags &= ~PF_NO##flag; \
1844 flags |= PF_##flag; \
1845 }
1450static void parseargs(int argc, char *argv[]) 1846static int parseargs(int argc, char *argv[])
1451{ 1847{
1452 int i; 1848 int i;
1453 char *from_file = NULL; 1849 const char *from_file = NULL;
1850 int ret = 0;
1454 1851
1455 opterr = 0; 1852 opterr = 0;
1456 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1853 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1457 switch (i) { 1854 switch (i) {
1458 1855
1470 case 'E': 1867 case 'E':
1471 strncpy(match_etypes, optarg, sizeof(match_etypes)); 1868 strncpy(match_etypes, optarg, sizeof(match_etypes));
1472 break; 1869 break;
1473 case 'M': 1870 case 'M':
1474 match_bits = atoi(optarg); 1871 match_bits = atoi(optarg);
1872 if (match_bits == 0) {
1873 if (strcmp(optarg, "ELFCLASS32") == 0)
1874 match_bits = 32;
1875 if (strcmp(optarg, "ELFCLASS64") == 0)
1876 match_bits = 64;
1877 }
1878 break;
1879 case 'O':
1880 if (sscanf(optarg, "%o", &match_perms) == -1)
1881 match_bits = 0;
1475 break; 1882 break;
1476 case 'o': { 1883 case 'o': {
1477 FILE *fp = NULL;
1478 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1884 if (freopen(optarg, "w", stdout) == NULL)
1479 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1885 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1480 SET_STDOUT(fp);
1481 break; 1886 break;
1482 } 1887 }
1483 case 'k': 1888 case 'k':
1484 if (find_section) warn("You prob don't want to specify -k twice"); 1889 if (find_section) warn("You prob don't want to specify -k twice");
1485 find_section = optarg; 1890 find_section = optarg;
1486 break; 1891 break;
1487 case 's': { 1892 case 's': {
1488 if (find_sym) warn("You prob don't want to specify -s twice"); 1893 if (find_sym) warn("You prob don't want to specify -s twice");
1489 find_sym = optarg; 1894 find_sym = optarg;
1490 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1491 sprintf(versioned_symname, "%s@", find_sym);
1492 break; 1895 break;
1493 } 1896 }
1494 case 'N': { 1897 case 'N': {
1495 if (find_lib) warn("You prob don't want to specify -N twice"); 1898 if (find_lib) warn("You prob don't want to specify -N twice");
1496 find_lib = optarg; 1899 find_lib = optarg;
1501 if (out_format) warn("You prob don't want to specify -F twice"); 1904 if (out_format) warn("You prob don't want to specify -F twice");
1502 out_format = optarg; 1905 out_format = optarg;
1503 break; 1906 break;
1504 } 1907 }
1505 case 'z': { 1908 case 'z': {
1506 unsigned long flags = 10240; 1909 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1507 size_t x; 1910 size_t x;
1508 1911
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++) { 1912 for (x = 0; x < strlen(optarg); x++) {
1519 switch(optarg[x]) { 1913 switch (optarg[x]) {
1520 case 'p': 1914 case 'p':
1521 case 'P': 1915 case 'P':
1522 do_state(optarg[x], PAGEEXEC); 1916 do_pax_state(optarg[x], PAGEEXEC);
1523 break; 1917 break;
1524 case 's': 1918 case 's':
1525 case 'S': 1919 case 'S':
1526 do_state(optarg[x], SEGMEXEC); 1920 do_pax_state(optarg[x], SEGMEXEC);
1527 break; 1921 break;
1528 case 'm': 1922 case 'm':
1529 case 'M': 1923 case 'M':
1530 do_state(optarg[x], MPROTECT); 1924 do_pax_state(optarg[x], MPROTECT);
1531 break; 1925 break;
1532 case 'e': 1926 case 'e':
1533 case 'E': 1927 case 'E':
1534 do_state(optarg[x], EMUTRAMP); 1928 do_pax_state(optarg[x], EMUTRAMP);
1535 break; 1929 break;
1536 case 'r': 1930 case 'r':
1537 case 'R': 1931 case 'R':
1538 do_state(optarg[x], RANDMMAP); 1932 do_pax_state(optarg[x], RANDMMAP);
1539 break; 1933 break;
1540 case 'x': 1934 case 'x':
1541 case 'X': 1935 case 'X':
1542 do_state(optarg[x], RANDEXEC); 1936 do_pax_state(optarg[x], RANDEXEC);
1543 break; 1937 break;
1544 default: 1938 default:
1545 break; 1939 break;
1546 } 1940 }
1547 } 1941 }
1552 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) || 1946 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1553 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)))) 1947 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1554 setpax = flags; 1948 setpax = flags;
1555 break; 1949 break;
1556 } 1950 }
1951 case 'Z': show_size = 1; break;
1557 case 'g': gmatch = 1; break; 1952 case 'g': g_match = 1; break;
1558 case 'L': use_ldcache = 1; break; 1953 case 'L': use_ldcache = 1; break;
1559 case 'y': scan_symlink = 0; break; 1954 case 'y': scan_symlink = 0; break;
1560 case 'A': scan_archives = 1; break; 1955 case 'A': scan_archives = 1; break;
1561 case 'B': show_banner = 0; break; 1956 case 'B': show_banner = 0; break;
1562 case 'l': scan_ldpath = 1; break; 1957 case 'l': scan_ldpath = 1; break;
1573 case 'b': show_bind = 1; break; 1968 case 'b': show_bind = 1; break;
1574 case 'S': show_soname = 1; break; 1969 case 'S': show_soname = 1; break;
1575 case 'T': show_textrels = 1; break; 1970 case 'T': show_textrels = 1; break;
1576 case 'q': be_quiet = 1; break; 1971 case 'q': be_quiet = 1; break;
1577 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1972 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1578 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1973 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1579 1974 case 'D': show_endian = 1; break;
1975 case 'I': show_osabi = 1; break;
1976 case 'Y': show_eabi = 1; break;
1580 case ':': 1977 case ':':
1581 err("Option '%c' is missing parameter", optopt); 1978 err("Option '%c' is missing parameter", optopt);
1582 case '?': 1979 case '?':
1583 err("Unknown option '%c' or argument missing", optopt); 1980 err("Unknown option '%c' or argument missing", optopt);
1584 default: 1981 default:
1585 err("Unhandled option '%c'; please report this", i); 1982 err("Unhandled option '%c'; please report this", i);
1586 } 1983 }
1587 } 1984 }
1588 1985 if (show_textrels && be_verbose) {
1986 if (which("objdump") != NULL)
1987 has_objdump = 1;
1988 }
1589 /* let the format option override all other options */ 1989 /* let the format option override all other options */
1590 if (out_format) { 1990 if (out_format) {
1591 show_pax = show_phdr = show_textrel = show_rpath = \ 1991 show_pax = show_phdr = show_textrel = show_rpath = \
1592 show_needed = show_interp = show_bind = show_soname = \ 1992 show_needed = show_interp = show_bind = show_soname = \
1593 show_textrels = 0; 1993 show_textrels = show_perms = show_endian = show_size = \
1994 show_osabi = show_eabi = 0;
1594 for (i = 0; out_format[i]; ++i) { 1995 for (i = 0; out_format[i]; ++i) {
1595 if (!IS_MODIFIER(out_format[i])) continue; 1996 if (!IS_MODIFIER(out_format[i])) continue;
1596 1997
1597 switch (out_format[++i]) { 1998 switch (out_format[++i]) {
1999 case '+': break;
1598 case '%': break; 2000 case '%': break;
1599 case '#': break; 2001 case '#': break;
1600 case 'F': break; 2002 case 'F': break;
1601 case 'p': break; 2003 case 'p': break;
1602 case 'f': break; 2004 case 'f': break;
1603 case 'k': break; 2005 case 'k': break;
1604 case 's': break; 2006 case 's': break;
1605 case 'N': break; 2007 case 'N': break;
1606 case 'o': break; 2008 case 'o': break;
2009 case 'a': break;
2010 case 'M': break;
2011 case 'Z': show_size = 1; break;
2012 case 'D': show_endian = 1; break;
2013 case 'I': show_osabi = 1; break;
2014 case 'Y': show_eabi = 1; break;
2015 case 'O': show_perms = 1; break;
1607 case 'x': show_pax = 1; break; 2016 case 'x': show_pax = 1; break;
1608 case 'e': show_phdr = 1; break; 2017 case 'e': show_phdr = 1; break;
1609 case 't': show_textrel = 1; break; 2018 case 't': show_textrel = 1; break;
1610 case 'r': show_rpath = 1; break; 2019 case 'r': show_rpath = 1; break;
1611 case 'n': show_needed = 1; break; 2020 case 'n': show_needed = 1; break;
1612 case 'i': show_interp = 1; break; 2021 case 'i': show_interp = 1; break;
1613 case 'b': show_bind = 1; break; 2022 case 'b': show_bind = 1; break;
1614 case 'S': show_soname = 1; break; 2023 case 'S': show_soname = 1; break;
1615 case 'T': show_textrels = 1; break; 2024 case 'T': show_textrels = 1; break;
1616 default: 2025 default:
1617 err("Invalid format specifier '%c' (byte %i)", 2026 err("Invalid format specifier '%c' (byte %i)",
1618 out_format[i], i+1); 2027 out_format[i], i+1);
1619 } 2028 }
1620 } 2029 }
1621 2030
1622 /* construct our default format */ 2031 /* construct our default format */
1623 } else { 2032 } else {
1624 size_t fmt_len = 30; 2033 size_t fmt_len = 30;
1625 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 2034 out_format = xmalloc(sizeof(char) * fmt_len);
2035 *out_format = '\0';
1626 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 2036 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1627 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 2037 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
2038 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
2039 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
2040 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
2041 if (show_osabi) xstrcat(&out_format, "%I ", &fmt_len);
2042 if (show_eabi) xstrcat(&out_format, "%Y ", &fmt_len);
1628 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 2043 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1629 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 2044 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1630 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 2045 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1631 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 2046 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1632 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 2047 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1640 } 2055 }
1641 if (be_verbose > 2) printf("Format: %s\n", out_format); 2056 if (be_verbose > 2) printf("Format: %s\n", out_format);
1642 2057
1643 /* now lets actually do the scanning */ 2058 /* now lets actually do the scanning */
1644 if (scan_ldpath || use_ldcache) 2059 if (scan_ldpath || use_ldcache)
1645 load_ld_so_conf(0, "/etc/ld.so.conf"); 2060 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1646 if (scan_ldpath) scanelf_ldpath(); 2061 if (scan_ldpath) scanelf_ldpath();
1647 if (scan_envpath) scanelf_envpath(); 2062 if (scan_envpath) scanelf_envpath();
2063 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
2064 from_file = "-";
1648 if (from_file) { 2065 if (from_file) {
1649 scanelf_from_file(from_file); 2066 scanelf_from_file(from_file);
1650 from_file = *argv; 2067 from_file = *argv;
1651 } 2068 }
1652 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 2069 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1653 err("Nothing to scan !?"); 2070 err("Nothing to scan !?");
1654 while (optind < argc) { 2071 while (optind < argc) {
1655 search_path = argv[optind++]; 2072 search_path = argv[optind++];
1656 scanelf_dir(search_path); 2073 ret = scanelf_dir(search_path);
1657 } 2074 }
1658 2075
1659 /* clean up */ 2076 /* clean up */
1660 if (versioned_symname) free(versioned_symname);
1661 for (i = 0; ldpaths[i]; ++i) 2077 for (i = 0; ldpaths[i]; ++i)
1662 free(ldpaths[i]); 2078 free(ldpaths[i]);
1663 2079
1664 if (ldcache != 0) 2080 if (ldcache != 0)
1665 munmap(ldcache, ldcache_size); 2081 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; 2082 return ret;
1676} 2083}
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 2084
1687 new_len = strlen(*dst) + strlen(src); 2085static 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{ 2086{
1702 static char my_app[2]; 2087 const char *delims = " \t\n";
1703 my_app[0] = append; 2088 char **envvals = NULL;
1704 my_app[1] = '\0'; 2089 char *env, *s;
1705 xstrcat(dst, my_app, curr_len); 2090 int nentry;
1706}
1707 2091
2092 if ((env = getenv(envvar)) == NULL)
2093 return NULL;
1708 2094
2095 env = xstrdup(env);
2096 if (env == NULL)
2097 return NULL;
2098
2099 s = strtok(env, delims);
2100 if (s == NULL) {
2101 free(env);
2102 return NULL;
2103 }
2104
2105 nentry = 0;
2106 while (s != NULL) {
2107 ++nentry;
2108 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
2109 envvals[nentry-1] = s;
2110 s = strtok(NULL, delims);
2111 }
2112 envvals[nentry] = NULL;
2113
2114 /* don't want to free(env) as it contains the memory that backs
2115 * the envvals array of strings */
2116 return envvals;
2117}
2118
2119static void parseenv(void)
2120{
2121 qa_textrels = get_split_env("QA_TEXTRELS");
2122 qa_execstack = get_split_env("QA_EXECSTACK");
2123 qa_wx_load = get_split_env("QA_WX_LOAD");
2124}
2125
2126#ifdef __PAX_UTILS_CLEANUP
2127static void cleanup(void)
2128{
2129 free(out_format);
2130 free(qa_textrels);
2131 free(qa_execstack);
2132 free(qa_wx_load);
2133}
2134#endif
1709 2135
1710int main(int argc, char *argv[]) 2136int main(int argc, char *argv[])
1711{ 2137{
2138 int ret;
1712 if (argc < 2) 2139 if (argc < 2)
1713 usage(EXIT_FAILURE); 2140 usage(EXIT_FAILURE);
2141 parseenv();
1714 parseargs(argc, argv); 2142 ret = parseargs(argc, argv);
1715 fclose(stdout); 2143 fclose(stdout);
1716#ifdef __BOUNDS_CHECKING_ON 2144#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()"); 2145 cleanup();
2146 warn("The calls to add/delete heap should be off:\n"
2147 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
2148 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1718#endif 2149#endif
1719 return EXIT_SUCCESS; 2150 return ret;
1720} 2151}
2152
2153/* Match filename against entries in matchlist, return TRUE
2154 * if the file is listed */
2155static int file_matches_list(const char *filename, char **matchlist)
2156{
2157 char **file;
2158 char *match;
2159 char buf[__PAX_UTILS_PATH_MAX];
2160
2161 if (matchlist == NULL)
2162 return 0;
2163
2164 for (file = matchlist; *file != NULL; file++) {
2165 if (search_path) {
2166 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2167 match = buf;
2168 } else {
2169 match = *file;
2170 }
2171 if (fnmatch(match, filename, 0) == 0)
2172 return 1;
2173 }
2174 return 0;
2175}

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

  ViewVC Help
Powered by ViewVC 1.1.20