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

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

  ViewVC Help
Powered by ViewVC 1.1.20