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

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

  ViewVC Help
Powered by ViewVC 1.1.20