/[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.94 Revision 1.146
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2006 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.94 2005/12/10 04:10:26 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.146 2006/05/14 21:04:25 vapier Exp $
5 * 5 *
6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10#include <stdio.h>
11#include <stdlib.h>
12#include <sys/types.h>
13#include <libgen.h>
14#include <limits.h>
15#include <string.h>
16#include <errno.h>
17#include <unistd.h>
18#include <sys/stat.h>
19#include <dirent.h>
20#include <getopt.h>
21#include <assert.h>
22#include "paxinc.h" 10#include "paxinc.h"
11#if defined(__GLIBC__) || defined(__UCLIBC__)
12 #include <glob.h>
13#endif
14#if defined(__FreeBSD__) || defined(__DragonFly__)
15 #include <elf-hints.h>
16#endif
23 17
24static const char *rcsid = "$Id: scanelf.c,v 1.94 2005/12/10 04:10:26 vapier Exp $"; 18static const char *rcsid = "$Id: scanelf.c,v 1.146 2006/05/14 21:04:25 vapier Exp $";
25#define argv0 "scanelf" 19#define argv0 "scanelf"
26 20
27#define IS_MODIFIER(c) (c == '%' || c == '#') 21#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
28 22
23#define do_state(option, flag) \
24 if (islower(option)) { \
25 flags &= ~PF_##flag; \
26 flags |= PF_NO##flag; \
27 } else { \
28 flags &= ~PF_NO##flag; \
29 flags |= PF_##flag; \
30 }
29 31
30 32
31/* prototypes */ 33/* prototypes */
34static int file_matches_list(const char *filename, char **matchlist);
35static int scanelf_elfobj(elfobj *elf);
36static int scanelf_elf(const char *filename, int fd, size_t len);
37static int scanelf_archive(const char *filename, int fd, size_t len);
32static void scanelf_file(const char *filename); 38static void scanelf_file(const char *filename);
33static void scanelf_dir(const char *path); 39static void scanelf_dir(const char *path);
34static void scanelf_ldpath(); 40static void scanelf_ldpath(void);
35static void scanelf_envpath(); 41static void scanelf_envpath(void);
36static void usage(int status); 42static void usage(int status);
43static char **get_split_env(const char *envvar);
44static void parseenv(void);
37static void parseargs(int argc, char *argv[]); 45static void parseargs(int argc, char *argv[]);
38static char *xstrdup(const char *s); 46static char *xstrdup(const char *s);
39static void *xmalloc(size_t size); 47static void *xmalloc(size_t size);
48static void *xrealloc(void *ptr, size_t size);
40static void xstrcat(char **dst, const char *src, size_t *curr_len); 49static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
50#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
41static inline void xchrcat(char **dst, const char append, size_t *curr_len); 51static inline void xchrcat(char **dst, const char append, size_t *curr_len);
42 52
43/* variables to control behavior */ 53/* variables to control behavior */
54static char match_etypes[126] = "";
44static char *ldpaths[256]; 55static char *ldpaths[256];
45static char scan_ldpath = 0; 56static char scan_ldpath = 0;
46static char scan_envpath = 0; 57static char scan_envpath = 0;
47static char scan_symlink = 1; 58static char scan_symlink = 1;
59static char scan_archives = 0;
48static char dir_recurse = 0; 60static char dir_recurse = 0;
49static char dir_crossmount = 1; 61static char dir_crossmount = 1;
50static char show_pax = 0; 62static char show_pax = 0;
51static char show_phdr = 0; 63static char show_phdr = 0;
52static char show_textrel = 0; 64static char show_textrel = 0;
58static char show_textrels = 0; 70static char show_textrels = 0;
59static char show_banner = 1; 71static char show_banner = 1;
60static char be_quiet = 0; 72static char be_quiet = 0;
61static char be_verbose = 0; 73static char be_verbose = 0;
62static char be_wewy_wewy_quiet = 0; 74static char be_wewy_wewy_quiet = 0;
75static char be_semi_verbose = 0;
63static char *find_sym = NULL, *versioned_symname = NULL; 76static char *find_sym = NULL, *versioned_symname = NULL;
64static char *find_lib = NULL; 77static char *find_lib = NULL;
78static char *find_section = NULL;
65static char *out_format = NULL; 79static char *out_format = NULL;
66static char *search_path = NULL; 80static char *search_path = NULL;
81static char fix_elf = 0;
67static char gmatch = 0; 82static char gmatch = 0;
83static char use_ldcache = 0;
68 84
85static char **qa_textrels = NULL;
86static char **qa_execstack = NULL;
87static char **qa_wx_load = NULL;
88
89int match_bits = 0;
90caddr_t ldcache = 0;
91size_t ldcache_size = 0;
92unsigned long setpax = 0UL;
93
94/* utility funcs */
95static char *xstrdup(const char *s)
96{
97 char *ret = strdup(s);
98 if (!ret) err("Could not strdup(): %s", strerror(errno));
99 return ret;
100}
101static void *xmalloc(size_t size)
102{
103 void *ret = malloc(size);
104 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
105 return ret;
106}
107static void *xrealloc(void *ptr, size_t size)
108{
109 void *ret = realloc(ptr, size);
110 if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
111 return ret;
112}
113static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
114{
115 size_t new_len;
116
117 new_len = strlen(*dst) + strlen(src);
118 if (*curr_len <= new_len) {
119 *curr_len = new_len + (*curr_len / 2);
120 *dst = realloc(*dst, *curr_len);
121 if (!*dst)
122 err("could not realloc() %li bytes", (unsigned long)*curr_len);
123 }
124
125 if (n)
126 strncat(*dst, src, n);
127 else
128 strcat(*dst, src);
129}
130static inline void xchrcat(char **dst, const char append, size_t *curr_len)
131{
132 static char my_app[2];
133 my_app[0] = append;
134 my_app[1] = '\0';
135 xstrcat(dst, my_app, curr_len);
136}
137
138/* Match filename against entries in matchlist, return TRUE
139 * if the file is listed */
140static int file_matches_list(const char *filename, char **matchlist) {
141 char **file;
142 char *match;
143 char buf[__PAX_UTILS_PATH_MAX];
144
145 if (matchlist == NULL)
146 return 0;
147
148 for (file = matchlist; *file != NULL; file++) {
149 if (search_path) {
150 snprintf(buf,__PAX_UTILS_PATH_MAX, "%s%s", search_path, *file);
151 match=buf;
152 } else {
153 match=*file;
154 }
155 if (fnmatch(match, filename, 0) == 0)
156 return 1; /* TRUE */
157 }
158 return 0; /* FALSE */
159}
69 160
70/* sub-funcs for scanelf_file() */ 161/* sub-funcs for scanelf_file() */
71static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 162static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
72{ 163{
73 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 164 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
92 } \ 183 } \
93 } 184 }
94 GET_SYMTABS(32) 185 GET_SYMTABS(32)
95 GET_SYMTABS(64) 186 GET_SYMTABS(64)
96} 187}
188
97static char *scanelf_file_pax(elfobj *elf, char *found_pax) 189static char *scanelf_file_pax(elfobj *elf, char *found_pax)
98{ 190{
99 static char ret[7]; 191 static char ret[7];
100 unsigned long i, shown; 192 unsigned long i, shown;
101 193
110 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 202 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
111 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 203 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
112 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 204 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
113 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 205 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
114 continue; \ 206 continue; \
115 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 207 if (fix_elf && setpax) { \
208 /* set the paxctl flags */ \
209 ESET(phdr[i].p_flags, setpax); \
210 } \
211 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
116 continue; \ 212 continue; \
117 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 213 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
118 *found_pax = 1; \ 214 *found_pax = 1; \
119 ++shown; \ 215 ++shown; \
120 break; \ 216 break; \
121 } \ 217 } \
122 } 218 }
123 SHOW_PAX(32) 219 SHOW_PAX(32)
124 SHOW_PAX(64) 220 SHOW_PAX(64)
221 }
222
223
224 if (fix_elf && setpax) {
225 /* set the chpax settings */
226 if (elf->elf_class == ELFCLASS32) {
227 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
228 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
229 } else {
230 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
231 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
232 }
125 } 233 }
126 234
127 /* fall back to EI_PAX if no PT_PAX was found */ 235 /* fall back to EI_PAX if no PT_PAX was found */
128 if (!*ret) { 236 if (!*ret) {
129 static char *paxflags; 237 static char *paxflags;
143 251
144static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 252static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
145{ 253{
146 static char ret[12]; 254 static char ret[12];
147 char *found; 255 char *found;
148 unsigned long i, shown;
149 unsigned char multi_stack, multi_relro, multi_load; 256 unsigned long i, shown, multi_stack, multi_relro, multi_load;
257 int max_pt_load;
150 258
151 if (!show_phdr) return NULL; 259 if (!show_phdr) return NULL;
152 260
153 memcpy(ret, "--- --- ---\0", 12); 261 memcpy(ret, "--- --- ---\0", 12);
154 262
155 shown = 0; 263 shown = 0;
156 multi_stack = multi_relro = multi_load = 0; 264 multi_stack = multi_relro = multi_load = 0;
265 max_pt_load = elf_max_pt_load(elf);
157 266
267#define NOTE_GNU_STACK ".note.GNU-stack"
158#define SHOW_PHDR(B) \ 268#define SHOW_PHDR(B) \
159 if (elf->elf_class == ELFCLASS ## B) { \ 269 if (elf->elf_class == ELFCLASS ## B) { \
160 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 270 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
161 Elf ## B ## _Off offset; \ 271 Elf ## B ## _Off offset; \
162 uint32_t flags, check_flags; \ 272 uint32_t flags, check_flags; \
163 if (elf->phdr != NULL) { \ 273 if (elf->phdr != NULL) { \
164 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 274 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
165 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 275 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
166 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 276 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
167 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 277 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
278 if (!file_matches_list(elf->filename, qa_execstack)) {\
168 found = found_phdr; \ 279 found = found_phdr; \
169 offset = 0; \ 280 offset = 0; \
170 check_flags = PF_X; \ 281 check_flags = PF_X; \
282 } else continue; \
171 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 283 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
172 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 284 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
173 found = found_relro; \ 285 found = found_relro; \
174 offset = 4; \ 286 offset = 4; \
175 check_flags = PF_X; \ 287 check_flags = PF_X; \
176 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 288 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
289 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
177 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 290 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
291 if (!file_matches_list(elf->filename, qa_wx_load)) {\
178 found = found_load; \ 292 found = found_load; \
179 offset = 8; \ 293 offset = 8; \
180 check_flags = PF_W|PF_X; \ 294 check_flags = PF_W|PF_X; \
295 } else continue; \
181 } else \ 296 } else \
182 continue; \ 297 continue; \
183 flags = EGET(phdr[i].p_flags); \ 298 flags = EGET(phdr[i].p_flags); \
184 if (be_quiet && ((flags & check_flags) != check_flags)) \ 299 if (be_quiet && ((flags & check_flags) != check_flags)) \
185 continue; \ 300 continue; \
301 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
302 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
303 ret[3] = ret[7] = '!'; \
304 flags = EGET(phdr[i].p_flags); \
305 } \
186 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 306 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
187 *found = 1; \ 307 *found = 1; \
188 ++shown; \ 308 ++shown; \
189 } \ 309 } \
190 } else if (elf->shdr != NULL) { \ 310 } else if (elf->shdr != NULL) { \
191 /* no program headers which means this is prob an object file */ \ 311 /* no program headers which means this is prob an object file */ \
192 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 312 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
193 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 313 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
314 char *str; \
315 if ((void*)strtbl > (void*)elf->data_end) \
316 goto skip_this_shdr##B; \
194 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 317 check_flags = SHF_WRITE|SHF_EXECINSTR; \
195 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 318 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
196 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 319 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
197 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 320 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
198 if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \ 321 str = elf->data + offset; \
322 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
323 if (!strcmp(str, NOTE_GNU_STACK)) { \
199 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \ 324 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
200 flags = EGET(shdr[i].sh_flags); \ 325 flags = EGET(shdr[i].sh_flags); \
201 if (be_quiet && ((flags & check_flags) != check_flags)) \ 326 if (be_quiet && ((flags & check_flags) != check_flags)) \
202 continue; \ 327 continue; \
203 ++*found_phdr; \ 328 ++*found_phdr; \
207 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \ 332 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
208 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \ 333 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
209 break; \ 334 break; \
210 } \ 335 } \
211 } \ 336 } \
337 skip_this_shdr##B: \
212 if (!multi_stack) { \ 338 if (!multi_stack) { \
213 *found_phdr = 1; \ 339 *found_phdr = 1; \
214 shown = 1; \ 340 shown = 1; \
215 memcpy(ret, "!WX", 3); \ 341 memcpy(ret, "!WX", 3); \
216 } \ 342 } \
222 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 348 if (be_wewy_wewy_quiet || (be_quiet && !shown))
223 return NULL; 349 return NULL;
224 else 350 else
225 return ret; 351 return ret;
226} 352}
353
227static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 354static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
228{ 355{
229 static const char *ret = "TEXTREL"; 356 static const char *ret = "TEXTREL";
230 unsigned long i; 357 unsigned long i;
231 358
232 if (!show_textrel && !show_textrels) return NULL; 359 if (!show_textrel && !show_textrels) return NULL;
360
361 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
233 362
234 if (elf->phdr) { 363 if (elf->phdr) {
235#define SHOW_TEXTREL(B) \ 364#define SHOW_TEXTREL(B) \
236 if (elf->elf_class == ELFCLASS ## B) { \ 365 if (elf->elf_class == ELFCLASS ## B) { \
237 Elf ## B ## _Dyn *dyn; \ 366 Elf ## B ## _Dyn *dyn; \
320 if (be_verbose <= 2) continue; \ 449 if (be_verbose <= 2) continue; \
321 } else \ 450 } else \
322 *found_textrels = 1; \ 451 *found_textrels = 1; \
323 /* locate this relocation symbol name */ \ 452 /* locate this relocation symbol name */ \
324 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 453 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
454 if ((void*)sym > (void*)elf->data_end) { \
455 warn("%s: corrupt ELF symbol", elf->filename); \
456 continue; \
457 } \
325 sym_max = ELF ## B ## _R_SYM(r_info); \ 458 sym_max = ELF ## B ## _R_SYM(r_info); \
326 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 459 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
327 sym += sym_max; \ 460 sym += sym_max; \
328 else \ 461 else \
329 sym = NULL; \ 462 sym = NULL; \
361 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename); 494 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
362 495
363 return NULL; 496 return NULL;
364} 497}
365 498
366static void rpath_security_checks(elfobj *, char *); 499static void rpath_security_checks(elfobj *, char *, const char *);
367static void rpath_security_checks(elfobj *elf, char *item) { 500static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
501{
368 struct stat st; 502 struct stat st;
369 switch (*item) { 503 switch (*item) {
370 case '/': break; 504 case '/': break;
371 case '.': 505 case '.':
372 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename); 506 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
373 break; 507 break;
508 case ':':
374 case '\0': 509 case '\0':
375 warnf("Security problem NULL RPATH in %s", elf->filename); 510 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
376 break; 511 break;
377 case '$': 512 case '$':
378 if (fstat(elf->fd, &st) != -1) 513 if (fstat(elf->fd, &st) != -1)
379 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 514 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
380 warnf("Security problem with RPATH='%s' in %s with mode set of %o", 515 warnf("Security problem with %s='%s' in %s with mode set of %o",
381 item, elf->filename, st.st_mode & 07777); 516 dt_type, item, elf->filename, st.st_mode & 07777);
382 break; 517 break;
383 default: 518 default:
384 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename); 519 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
385 break; 520 break;
386 } 521 }
387} 522}
388static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 523static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
389{ 524{
425 /* Verify the memory is somewhat sane */ \ 560 /* Verify the memory is somewhat sane */ \
426 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 561 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
427 if (offset < (Elf ## B ## _Off)elf->len) { \ 562 if (offset < (Elf ## B ## _Off)elf->len) { \
428 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 563 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
429 *r = (char*)(elf->data + offset); \ 564 *r = (char*)(elf->data + offset); \
565 /* cache the length in case we need to nuke this section later on */ \
566 if (fix_elf) \
567 offset = strlen(*r); \
430 /* If quiet, don't output paths in ld.so.conf */ \ 568 /* If quiet, don't output paths in ld.so.conf */ \
431 if (be_quiet) { \ 569 if (be_quiet) { \
432 size_t len; \ 570 size_t len; \
433 char *start, *end; \ 571 char *start, *end; \
434 /* note that we only 'chop' off leading known paths. */ \ 572 /* note that we only 'chop' off leading known paths. */ \
435 /* since *r is read-only memory, we can only move the ptr forward. */ \ 573 /* since *r is read-only memory, we can only move the ptr forward. */ \
436 start = *r; \ 574 start = *r; \
437 /* scan each path in : delimited list */ \ 575 /* scan each path in : delimited list */ \
438 while (start) { \ 576 while (start) { \
439 rpath_security_checks(elf, start); \ 577 rpath_security_checks(elf, start, get_elfdtype(word)); \
440 end = strchr(start, ':'); \ 578 end = strchr(start, ':'); \
441 len = (end ? abs(end - start) : strlen(start)); \ 579 len = (end ? abs(end - start) : strlen(start)); \
580 if (use_ldcache) \
442 for (s = 0; ldpaths[s]; ++s) { \ 581 for (s = 0; ldpaths[s]; ++s) \
443 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 582 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
444 *r = (end ? end + 1 : NULL); \ 583 *r = end; \
584 /* corner case ... if RPATH reads "/usr/lib:", we want \
585 * to show ':' rather than '' */ \
586 if (end && end[1] != '\0') \
587 (*r)++; \
445 break; \ 588 break; \
446 } \ 589 } \
447 } \
448 if (!*r || !ldpaths[s] || !end) \ 590 if (!*r || !end) \
449 start = NULL; \ 591 break; \
450 else \ 592 else \
451 start = start + len + 1; \ 593 start = start + len + 1; \
452 } \ 594 } \
453 } \ 595 } \
596 if (*r) { \
597 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
598 /* just nuke it */ \
599 nuke_it##B: \
600 memset(*r, 0x00, offset); \
601 *r = NULL; \
602 ESET(dyn->d_tag, DT_DEBUG); \
603 ESET(dyn->d_un.d_ptr, 0); \
604 } else if (fix_elf) { \
605 /* try to clean "bad" paths */ \
606 size_t len, tmpdir_len; \
607 char *start, *end; \
608 const char *tmpdir; \
609 start = *r; \
610 tmpdir = (getenv("TMPDIR") ? : "."); \
611 tmpdir_len = strlen(tmpdir); \
612 while (1) { \
613 end = strchr(start, ':'); \
614 if (start == end) { \
615 eat_this_path##B: \
616 len = strlen(end); \
617 memmove(start, end+1, len); \
618 start[len-1] = '\0'; \
619 end = start - 1; \
620 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
621 if (!end) { \
622 if (start == *r) \
623 goto nuke_it##B; \
624 *--start = '\0'; \
625 } else \
626 goto eat_this_path##B; \
627 } \
628 if (!end) \
629 break; \
630 start = end + 1; \
631 } \
632 if (**r == '\0') \
633 goto nuke_it##B; \
634 } \
635 if (*r) \
454 if (*r) *found_rpath = 1; \ 636 *found_rpath = 1; \
637 } \
455 } \ 638 } \
456 ++dyn; \ 639 ++dyn; \
457 } \ 640 } \
458 } } 641 } }
459 SHOW_RPATH(32) 642 SHOW_RPATH(32)
476 } else if (rpath || runpath) 659 } else if (rpath || runpath)
477 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 660 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
478 else if (!be_quiet) 661 else if (!be_quiet)
479 xstrcat(ret, " - ", ret_len); 662 xstrcat(ret, " - ", ret_len);
480} 663}
664
665#define LDSO_CACHE_MAGIC "ld.so-"
666#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
667#define LDSO_CACHE_VER "1.7.0"
668#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
669#define FLAG_ANY -1
670#define FLAG_TYPE_MASK 0x00ff
671#define FLAG_LIBC4 0x0000
672#define FLAG_ELF 0x0001
673#define FLAG_ELF_LIBC5 0x0002
674#define FLAG_ELF_LIBC6 0x0003
675#define FLAG_REQUIRED_MASK 0xff00
676#define FLAG_SPARC_LIB64 0x0100
677#define FLAG_IA64_LIB64 0x0200
678#define FLAG_X8664_LIB64 0x0300
679#define FLAG_S390_LIB64 0x0400
680#define FLAG_POWERPC_LIB64 0x0500
681#define FLAG_MIPS64_LIBN32 0x0600
682#define FLAG_MIPS64_LIBN64 0x0700
683
684static char *lookup_cache_lib(elfobj *, char *);
685#if defined(__GLIBC__) || defined(__UCLIBC__)
686static char *lookup_cache_lib(elfobj *elf, char *fname)
687{
688 int fd = 0;
689 char *strs;
690 static char buf[__PAX_UTILS_PATH_MAX] = "";
691 const char *cachefile = "/etc/ld.so.cache";
692 struct stat st;
693
694 typedef struct {
695 char magic[LDSO_CACHE_MAGIC_LEN];
696 char version[LDSO_CACHE_VER_LEN];
697 int nlibs;
698 } header_t;
699 header_t *header;
700
701 typedef struct {
702 int flags;
703 int sooffset;
704 int liboffset;
705 } libentry_t;
706 libentry_t *libent;
707
708 if (fname == NULL)
709 return NULL;
710
711 if (ldcache == 0) {
712 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
713 return NULL;
714
715 /* cache these values so we only map/unmap the cache file once */
716 ldcache_size = st.st_size;
717 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
718
719 close(fd);
720
721 if (ldcache == (caddr_t)-1) {
722 ldcache = 0;
723 return NULL;
724 }
725
726 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
727 return NULL;
728 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
729 return NULL;
730 }
731
732 header = (header_t *) ldcache;
733 libent = (libentry_t *) (ldcache + sizeof(header_t));
734 strs = (char *) &libent[header->nlibs];
735
736 for (fd = 0; fd < header->nlibs; fd++) {
737 /* this should be more fine grained, but for now we assume that
738 * diff arches will not be cached together. and we ignore the
739 * the different multilib mips cases. */
740 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
741 continue;
742 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
743 continue;
744
745 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
746 continue;
747 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
748 }
749 return buf;
750}
751#else
752#warning Cache support not implemented for your current target.
753static char *lookup_cache_lib(elfobj *elf, char *fname)
754{
755 return NULL;
756}
757#endif
758
481static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 759static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
482{ 760{
483 unsigned long i; 761 unsigned long i;
484 char *needed; 762 char *needed;
485 void *strtbl_void; 763 void *strtbl_void;
764 char *p;
486 765
487 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 766 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
488 767
489 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 768 strtbl_void = elf_findsecbyname(elf, ".dynstr");
490 769
510 } \ 789 } \
511 needed = (char*)(elf->data + offset); \ 790 needed = (char*)(elf->data + offset); \
512 if (op == 0) { \ 791 if (op == 0) { \
513 if (!be_wewy_wewy_quiet) { \ 792 if (!be_wewy_wewy_quiet) { \
514 if (*found_needed) xchrcat(ret, ',', ret_len); \ 793 if (*found_needed) xchrcat(ret, ',', ret_len); \
794 if (use_ldcache) \
795 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
796 needed = p; \
515 xstrcat(ret, needed, ret_len); \ 797 xstrcat(ret, needed, ret_len); \
516 } \ 798 } \
517 *found_needed = 1; \ 799 *found_needed = 1; \
518 } else { \ 800 } else { \
519 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 801 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
555} 837}
556static char *scanelf_file_bind(elfobj *elf, char *found_bind) 838static char *scanelf_file_bind(elfobj *elf, char *found_bind)
557{ 839{
558 unsigned long i; 840 unsigned long i;
559 struct stat s; 841 struct stat s;
842 char dynamic = 0;
560 843
561 if (!show_bind) return NULL; 844 if (!show_bind) return NULL;
562 if (!elf->phdr) return NULL; 845 if (!elf->phdr) return NULL;
563 846
564#define SHOW_BIND(B) \ 847#define SHOW_BIND(B) \
567 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 850 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
568 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 851 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
569 Elf ## B ## _Off offset; \ 852 Elf ## B ## _Off offset; \
570 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 853 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
571 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 854 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
855 dynamic = 1; \
572 offset = EGET(phdr[i].p_offset); \ 856 offset = EGET(phdr[i].p_offset); \
573 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 857 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
574 dyn = DYN ## B (elf->data + offset); \ 858 dyn = DYN ## B (elf->data + offset); \
575 while (EGET(dyn->d_tag) != DT_NULL) { \ 859 while (EGET(dyn->d_tag) != DT_NULL) { \
576 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 860 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
591 875
592 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 876 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
593 return NULL; 877 return NULL;
594 } else { 878 } else {
595 *found_bind = 1; 879 *found_bind = 1;
596 return (char *) "LAZY"; 880 return (char *) (dynamic ? "LAZY" : "STATIC");
597 } 881 }
598} 882}
599static char *scanelf_file_soname(elfobj *elf, char *found_soname) 883static char *scanelf_file_soname(elfobj *elf, char *found_soname)
600{ 884{
601 unsigned long i; 885 unsigned long i;
643 return NULL; 927 return NULL;
644} 928}
645static char *scanelf_file_sym(elfobj *elf, char *found_sym) 929static char *scanelf_file_sym(elfobj *elf, char *found_sym)
646{ 930{
647 unsigned long i; 931 unsigned long i;
932 char *ret;
648 void *symtab_void, *strtab_void; 933 void *symtab_void, *strtab_void;
649 934
650 if (!find_sym) return NULL; 935 if (!find_sym) return NULL;
936 ret = find_sym;
651 937
652 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 938 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
653 939
654 if (symtab_void && strtab_void) { 940 if (symtab_void && strtab_void) {
655#define FIND_SYM(B) \ 941#define FIND_SYM(B) \
656 if (elf->elf_class == ELFCLASS ## B) { \ 942 if (elf->elf_class == ELFCLASS ## B) { \
657 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 943 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
658 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 944 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
659 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 945 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
660 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 946 unsigned long cnt = EGET(symtab->sh_entsize); \
661 char *symname; \ 947 char *symname; \
948 if (cnt) \
949 cnt = EGET(symtab->sh_size) / cnt; \
662 for (i = 0; i < cnt; ++i) { \ 950 for (i = 0; i < cnt; ++i) { \
663 if (sym->st_name) { \ 951 if (sym->st_name) { \
952 /* make sure the symbol name is in acceptable memory range */ \
664 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 953 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
954 if ((void*)symname > (void*)elf->data_end) { \
955 warnf("%s: corrupt ELF symbols", elf->filename); \
956 ++sym; \
957 continue; \
958 } \
959 /* debug display ... show all symbols and some extra info */ \
665 if (*find_sym == '*') { \ 960 if (*ret == '*') { \
666 printf("%s(%s) %5lX %15s %s\n", \ 961 printf("%s(%s) %5lX %15s %s\n", \
667 ((*found_sym == 0) ? "\n\t" : "\t"), \ 962 ((*found_sym == 0) ? "\n\t" : "\t"), \
668 elf->base_filename, \ 963 elf->base_filename, \
669 (unsigned long)sym->st_size, \ 964 (unsigned long)sym->st_size, \
670 (char *)get_elfstttype(sym->st_info), \ 965 get_elfstttype(sym->st_info), \
671 symname); \ 966 symname); \
672 *found_sym = 1; \ 967 *found_sym = 1; \
673 } else if ((strcmp(find_sym, symname) == 0) || \ 968 } else { \
674 (strcmp(symname, versioned_symname) == 0)) \ 969 /* allow the user to specify a comma delimited list of symbols to search for */ \
970 char *this_sym, *next_sym; \
971 this_sym = ret; \
972 do { \
973 next_sym = strchr(this_sym, ','); \
974 if (next_sym == NULL) \
975 next_sym = this_sym + strlen(this_sym); \
976 /* do we want a defined symbol ? */ \
977 if (*this_sym == '+') { \
978 if (sym->st_shndx == SHN_UNDEF) \
979 goto skip_this_sym##B; \
980 ++this_sym; \
981 /* do we want an undefined symbol ? */ \
982 } else if (*this_sym == '-') { \
983 if (sym->st_shndx != SHN_UNDEF) \
984 goto skip_this_sym##B; \
985 ++this_sym; \
986 } \
987 /* ok, lets compare the name now */ \
988 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
989 (strncmp(symname, versioned_symname, strlen(versioned_symname)) == 0)) { \
990 if (be_semi_verbose) { \
991 char buf[126]; \
992 snprintf(buf, sizeof(buf), "%lX %s %s", \
993 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
994 ret = buf; \
995 } else \
996 ret = this_sym; \
675 (*found_sym)++; \ 997 (*found_sym)++; \
998 goto break_out; \
999 } \
1000 skip_this_sym##B: this_sym = next_sym + 1; \
1001 } while (*next_sym != '\0'); \
1002 } \
676 } \ 1003 } \
677 ++sym; \ 1004 ++sym; \
678 } } 1005 } }
679 FIND_SYM(32) 1006 FIND_SYM(32)
680 FIND_SYM(64) 1007 FIND_SYM(64)
681 } 1008 }
682 1009
1010break_out:
683 if (be_wewy_wewy_quiet) return NULL; 1011 if (be_wewy_wewy_quiet) return NULL;
684 1012
685 if (*find_sym != '*' && *found_sym) 1013 if (*find_sym != '*' && *found_sym)
686 return find_sym; 1014 return ret;
687 if (be_quiet) 1015 if (be_quiet)
688 return NULL; 1016 return NULL;
689 else 1017 else
690 return (char *)" - "; 1018 return (char *)" - ";
691} 1019}
1020
1021
1022static char *scanelf_file_sections(elfobj *elf, char *found_section)
1023{
1024 if (!find_section)
1025 return NULL;
1026
1027#define FIND_SECTION(B) \
1028 if (elf->elf_class == ELFCLASS ## B) { \
1029 int invert; \
1030 Elf ## B ## _Shdr *section; \
1031 invert = (*find_section == '!' ? 1 : 0); \
1032 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1033 if ((section == NULL && invert) || (section != NULL && !invert)) \
1034 *found_section = 1; \
1035 }
1036 FIND_SECTION(32)
1037 FIND_SECTION(64)
1038
1039 if (be_wewy_wewy_quiet)
1040 return NULL;
1041
1042 if (*found_section)
1043 return find_section;
1044
1045 if (be_quiet)
1046 return NULL;
1047 else
1048 return (char *)" - ";
1049}
1050
692/* scan an elf file and show all the fun stuff */ 1051/* scan an elf file and show all the fun stuff */
693#define prints(str) write(fileno(stdout), str, strlen(str)) 1052#define prints(str) write(fileno(stdout), str, strlen(str))
694static void scanelf_file(const char *filename) 1053static int scanelf_elfobj(elfobj *elf)
695{ 1054{
696 unsigned long i; 1055 unsigned long i;
697 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1056 char found_pax, found_phdr, found_relro, found_load, found_textrel,
698 found_rpath, found_needed, found_interp, found_bind, found_soname, 1057 found_rpath, found_needed, found_interp, found_bind, found_soname,
699 found_sym, found_lib, found_file, found_textrels; 1058 found_sym, found_lib, found_file, found_textrels, found_section;
700 elfobj *elf;
701 struct stat st;
702 static char *out_buffer = NULL; 1059 static char *out_buffer = NULL;
703 static size_t out_len; 1060 static size_t out_len;
704 1061
705 /* make sure 'filename' exists */
706 if (lstat(filename, &st) == -1) {
707 if (be_verbose > 2) printf("%s: does not exist\n", filename);
708 return;
709 }
710 /* always handle regular files and handle symlinked files if no -y */
711 if (S_ISLNK(st.st_mode)) {
712 if (!scan_symlink) return;
713 stat(filename, &st);
714 }
715 if (!S_ISREG(st.st_mode)) {
716 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
717 return;
718 }
719
720 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1062 found_pax = found_phdr = found_relro = found_load = found_textrel = \
721 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1063 found_rpath = found_needed = found_interp = found_bind = found_soname = \
722 found_sym = found_lib = found_file = found_textrels = 0; 1064 found_sym = found_lib = found_file = found_textrels = found_section = 0;
723 1065
724 /* verify this is real ELF */
725 if ((elf = readelf(filename)) == NULL) {
726 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
727 return;
728 }
729
730 if (be_verbose > 1) 1066 if (be_verbose > 2)
731 printf("%s: scanning file {%s,%s}\n", filename, 1067 printf("%s: scanning file {%s,%s}\n", elf->filename,
732 get_elfeitype(EI_CLASS, elf->elf_class), 1068 get_elfeitype(EI_CLASS, elf->elf_class),
733 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1069 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
734 else if (be_verbose) 1070 else if (be_verbose > 1)
735 printf("%s: scanning file\n", filename); 1071 printf("%s: scanning file\n", elf->filename);
736 1072
737 /* init output buffer */ 1073 /* init output buffer */
738 if (!out_buffer) { 1074 if (!out_buffer) {
739 out_len = sizeof(char) * 80; 1075 out_len = sizeof(char) * 80;
740 out_buffer = (char*)xmalloc(out_len); 1076 out_buffer = (char*)xmalloc(out_len);
745 if (!be_quiet && show_banner) { 1081 if (!be_quiet && show_banner) {
746 for (i = 0; out_format[i]; ++i) { 1082 for (i = 0; out_format[i]; ++i) {
747 if (!IS_MODIFIER(out_format[i])) continue; 1083 if (!IS_MODIFIER(out_format[i])) continue;
748 1084
749 switch (out_format[++i]) { 1085 switch (out_format[++i]) {
1086 case '+': break;
750 case '%': break; 1087 case '%': break;
751 case '#': break; 1088 case '#': break;
752 case 'F': 1089 case 'F':
753 case 'p': 1090 case 'p':
754 case 'f': prints("FILE "); found_file = 1; break; 1091 case 'f': prints("FILE "); found_file = 1; break;
762 case 'b': prints("BIND "); break; 1099 case 'b': prints("BIND "); break;
763 case 'S': prints("SONAME "); break; 1100 case 'S': prints("SONAME "); break;
764 case 's': prints("SYM "); break; 1101 case 's': prints("SYM "); break;
765 case 'N': prints("LIB "); break; 1102 case 'N': prints("LIB "); break;
766 case 'T': prints("TEXTRELS "); break; 1103 case 'T': prints("TEXTRELS "); break;
1104 case 'k': prints("SECTION "); break;
767 default: warnf("'%c' has no title ?", out_format[i]); 1105 default: warnf("'%c' has no title ?", out_format[i]);
768 } 1106 }
769 } 1107 }
770 if (!found_file) prints("FILE "); 1108 if (!found_file) prints("FILE ");
771 prints("\n"); 1109 prints("\n");
776 /* dump all the good stuff */ 1114 /* dump all the good stuff */
777 for (i = 0; out_format[i]; ++i) { 1115 for (i = 0; out_format[i]; ++i) {
778 const char *out; 1116 const char *out;
779 const char *tmp; 1117 const char *tmp;
780 1118
781 /* make sure we trim leading spaces in quiet mode */
782 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
783 *out_buffer = '\0';
784
785 if (!IS_MODIFIER(out_format[i])) { 1119 if (!IS_MODIFIER(out_format[i])) {
786 xchrcat(&out_buffer, out_format[i], &out_len); 1120 xchrcat(&out_buffer, out_format[i], &out_len);
787 continue; 1121 continue;
788 } 1122 }
789 1123
790 out = NULL; 1124 out = NULL;
791 be_wewy_wewy_quiet = (out_format[i] == '#'); 1125 be_wewy_wewy_quiet = (out_format[i] == '#');
1126 be_semi_verbose = (out_format[i] == '+');
792 switch (out_format[++i]) { 1127 switch (out_format[++i]) {
1128 case '+':
793 case '%': 1129 case '%':
794 case '#': 1130 case '#':
795 xchrcat(&out_buffer, out_format[i], &out_len); break; 1131 xchrcat(&out_buffer, out_format[i], &out_len); break;
796 case 'F': 1132 case 'F':
797 found_file = 1; 1133 found_file = 1;
798 if (be_wewy_wewy_quiet) break; 1134 if (be_wewy_wewy_quiet) break;
799 xstrcat(&out_buffer, filename, &out_len); 1135 xstrcat(&out_buffer, elf->filename, &out_len);
800 break; 1136 break;
801 case 'p': 1137 case 'p':
802 found_file = 1; 1138 found_file = 1;
803 if (be_wewy_wewy_quiet) break; 1139 if (be_wewy_wewy_quiet) break;
804 tmp = filename; 1140 tmp = elf->filename;
805 if (search_path) { 1141 if (search_path) {
806 ssize_t len_search = strlen(search_path); 1142 ssize_t len_search = strlen(search_path);
807 ssize_t len_file = strlen(filename); 1143 ssize_t len_file = strlen(elf->filename);
808 if (!strncmp(filename, search_path, len_search) && \ 1144 if (!strncmp(elf->filename, search_path, len_search) && \
809 len_file > len_search) 1145 len_file > len_search)
810 tmp += len_search; 1146 tmp += len_search;
811 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1147 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
812 } 1148 }
813 xstrcat(&out_buffer, tmp, &out_len); 1149 xstrcat(&out_buffer, tmp, &out_len);
814 break; 1150 break;
815 case 'f': 1151 case 'f':
816 found_file = 1; 1152 found_file = 1;
817 if (be_wewy_wewy_quiet) break; 1153 if (be_wewy_wewy_quiet) break;
818 tmp = strrchr(filename, '/'); 1154 tmp = strrchr(elf->filename, '/');
819 tmp = (tmp == NULL ? filename : tmp+1); 1155 tmp = (tmp == NULL ? elf->filename : tmp+1);
820 xstrcat(&out_buffer, tmp, &out_len); 1156 xstrcat(&out_buffer, tmp, &out_len);
821 break; 1157 break;
822 case 'o': out = get_elfetype(elf); break; 1158 case 'o': out = get_elfetype(elf); break;
823 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1159 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
824 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1160 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
829 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1165 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
830 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1166 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
831 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1167 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
832 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1168 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
833 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1169 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1170 case 'k': out = scanelf_file_sections(elf, &found_section); break;
834 default: warnf("'%c' has no scan code?", out_format[i]); 1171 default: warnf("'%c' has no scan code?", out_format[i]);
835 } 1172 }
1173 if (out) {
1174 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1175 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1176 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1177 else
836 if (out) xstrcat(&out_buffer, out, &out_len); 1178 xstrcat(&out_buffer, out, &out_len);
1179 }
837 } 1180 }
838 1181
839#define FOUND_SOMETHING() \ 1182#define FOUND_SOMETHING() \
840 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1183 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
841 found_rpath || found_needed || found_interp || found_bind || \ 1184 found_rpath || found_needed || found_interp || found_bind || \
842 found_soname || found_sym || found_lib || found_textrels) 1185 found_soname || found_sym || found_lib || found_textrels || found_section )
843 1186
844 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1187 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
845 xchrcat(&out_buffer, ' ', &out_len); 1188 xchrcat(&out_buffer, ' ', &out_len);
846 xstrcat(&out_buffer, filename, &out_len); 1189 xstrcat(&out_buffer, elf->filename, &out_len);
847 } 1190 }
848 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1191 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
849 puts(out_buffer); 1192 puts(out_buffer);
850 fflush(stdout); 1193 fflush(stdout);
851 } 1194 }
852 1195
1196 return 0;
1197}
1198
1199/* scan a single elf */
1200static int scanelf_elf(const char *filename, int fd, size_t len)
1201{
1202 int ret = 1;
1203 elfobj *elf;
1204
1205 /* verify this is real ELF */
1206 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1207 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1208 return ret;
1209 }
1210 switch (match_bits) {
1211 case 32:
1212 if (elf->elf_class != ELFCLASS32)
1213 goto label_done;
1214 break;
1215 case 64:
1216 if (elf->elf_class != ELFCLASS64)
1217 goto label_done;
1218 break;
1219 default: break;
1220 }
1221 if (strlen(match_etypes)) {
1222 char sbuf[126];
1223 strncpy(sbuf, match_etypes, sizeof(sbuf));
1224 if (strchr(match_etypes, ',') != NULL) {
1225 char *p;
1226 while((p = strrchr(sbuf, ',')) != NULL) {
1227 *p = 0;
1228 if (etype_lookup(p+1) == get_etype(elf))
1229 goto label_ret;
1230 }
1231 }
1232 if (etype_lookup(sbuf) != get_etype(elf))
1233 goto label_done;
1234 }
1235
1236label_ret:
1237 ret = scanelf_elfobj(elf);
1238
1239label_done:
853 unreadelf(elf); 1240 unreadelf(elf);
1241 return ret;
1242}
1243
1244/* scan an archive of elfs */
1245static int scanelf_archive(const char *filename, int fd, size_t len)
1246{
1247 archive_handle *ar;
1248 archive_member *m;
1249 char *ar_buffer;
1250 elfobj *elf;
1251
1252 ar = ar_open_fd(filename, fd);
1253 if (ar == NULL)
1254 return 1;
1255
1256 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1257 while ((m=ar_next(ar)) != NULL) {
1258 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1259 if (elf) {
1260 scanelf_elfobj(elf);
1261 unreadelf(elf);
1262 }
1263 }
1264 munmap(ar_buffer, len);
1265
1266 return 0;
1267}
1268/* scan a file which may be an elf or an archive or some other magical beast */
1269static void scanelf_file(const char *filename)
1270{
1271 struct stat st;
1272 int fd;
1273
1274 /* make sure 'filename' exists */
1275 if (lstat(filename, &st) == -1) {
1276 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1277 return;
1278 }
1279
1280 /* always handle regular files and handle symlinked files if no -y */
1281 if (S_ISLNK(st.st_mode)) {
1282 if (!scan_symlink) return;
1283 stat(filename, &st);
1284 }
1285 if (!S_ISREG(st.st_mode)) {
1286 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1287 return;
1288 }
1289
1290 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1291 return;
1292
1293 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1294 /* if it isn't an ELF, maybe it's an .a archive */
1295 scanelf_archive(filename, fd, st.st_size);
1296
1297 close(fd);
854} 1298}
855 1299
856/* scan a directory for ET_EXEC files and print when we find one */ 1300/* scan a directory for ET_EXEC files and print when we find one */
857static void scanelf_dir(const char *path) 1301static void scanelf_dir(const char *path)
858{ 1302{
859 register DIR *dir; 1303 register DIR *dir;
860 register struct dirent *dentry; 1304 register struct dirent *dentry;
861 struct stat st_top, st; 1305 struct stat st_top, st;
862 char buf[_POSIX_PATH_MAX]; 1306 char buf[__PAX_UTILS_PATH_MAX];
863 size_t pathlen = 0, len = 0; 1307 size_t pathlen = 0, len = 0;
864 1308
865 /* make sure path exists */ 1309 /* make sure path exists */
866 if (lstat(path, &st_top) == -1) { 1310 if (lstat(path, &st_top) == -1) {
867 if (be_verbose > 2) printf("%s: does not exist\n", path); 1311 if (be_verbose > 2) printf("%s: does not exist\n", path);
877 /* now scan the dir looking for fun stuff */ 1321 /* now scan the dir looking for fun stuff */
878 if ((dir = opendir(path)) == NULL) { 1322 if ((dir = opendir(path)) == NULL) {
879 warnf("could not opendir %s: %s", path, strerror(errno)); 1323 warnf("could not opendir %s: %s", path, strerror(errno));
880 return; 1324 return;
881 } 1325 }
882 if (be_verbose) printf("%s: scanning dir\n", path); 1326 if (be_verbose > 1) printf("%s: scanning dir\n", path);
883 1327
884 pathlen = strlen(path); 1328 pathlen = strlen(path);
885 while ((dentry = readdir(dir))) { 1329 while ((dentry = readdir(dir))) {
886 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1330 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
887 continue; 1331 continue;
889 if (len >= sizeof(buf)) { 1333 if (len >= sizeof(buf)) {
890 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1334 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
891 (unsigned long)len, (unsigned long)sizeof(buf)); 1335 (unsigned long)len, (unsigned long)sizeof(buf));
892 continue; 1336 continue;
893 } 1337 }
894 sprintf(buf, "%s/%s", path, dentry->d_name); 1338 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
895 if (lstat(buf, &st) != -1) { 1339 if (lstat(buf, &st) != -1) {
896 if (S_ISREG(st.st_mode)) 1340 if (S_ISREG(st.st_mode))
897 scanelf_file(buf); 1341 scanelf_file(buf);
898 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1342 else if (dir_recurse && S_ISDIR(st.st_mode)) {
899 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1343 if (dir_crossmount || (st_top.st_dev == st.st_dev))
902 } 1346 }
903 } 1347 }
904 closedir(dir); 1348 closedir(dir);
905} 1349}
906 1350
907static int scanelf_from_file(char *filename) 1351static int scanelf_from_file(const char *filename)
908{ 1352{
909 FILE *fp = NULL; 1353 FILE *fp = NULL;
910 char *p; 1354 char *p;
911 char path[_POSIX_PATH_MAX]; 1355 char path[__PAX_UTILS_PATH_MAX];
912 1356
913 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1357 if (strcmp(filename, "-") == 0)
914 fp = stdin; 1358 fp = stdin;
915 else if ((fp = fopen(filename, "r")) == NULL) 1359 else if ((fp = fopen(filename, "r")) == NULL)
916 return 1; 1360 return 1;
917 1361
918 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1362 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
919 if ((p = strchr(path, '\n')) != NULL) 1363 if ((p = strchr(path, '\n')) != NULL)
920 *p = 0; 1364 *p = 0;
921 search_path = path; 1365 search_path = path;
922 scanelf_dir(path); 1366 scanelf_dir(path);
923 } 1367 }
924 if (fp != stdin) 1368 if (fp != stdin)
925 fclose(fp); 1369 fclose(fp);
926 return 0; 1370 return 0;
927} 1371}
928 1372
929static void load_ld_so_conf() 1373#if defined(__GLIBC__) || defined(__UCLIBC__)
1374static int load_ld_so_conf(int i, const char *fname)
930{ 1375{
931 FILE *fp = NULL; 1376 FILE *fp = NULL;
932 char *p; 1377 char *p;
933 char path[_POSIX_PATH_MAX]; 1378 char path[__PAX_UTILS_PATH_MAX];
934 int i = 0;
935 1379
936 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1380 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
937 return; 1381 return i;
938 1382
1383 if ((fp = fopen(fname, "r")) == NULL)
1384 return i;
1385
939 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1386 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
940 if (*path != '/')
941 continue;
942
943 if ((p = strrchr(path, '\r')) != NULL) 1387 if ((p = strrchr(path, '\r')) != NULL)
944 *p = 0; 1388 *p = 0;
945 if ((p = strchr(path, '\n')) != NULL) 1389 if ((p = strchr(path, '\n')) != NULL)
946 *p = 0; 1390 *p = 0;
1391 // recursive includes of the same file will make this segfault.
1392 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1393 glob64_t gl;
1394 size_t x;
1395 char gpath[__PAX_UTILS_PATH_MAX];
1396
1397 memset(gpath, 0, sizeof(gpath));
1398
1399 if (path[8] != '/')
1400 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1401 else
1402 strncpy(gpath, &path[8], sizeof(gpath));
1403
1404 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1405 for (x = 0; x < gl.gl_pathc; ++x) {
1406 /* try to avoid direct loops */
1407 if (strcmp(gl.gl_pathv[x], fname) == 0)
1408 continue;
1409 i = load_ld_so_conf(i, gl.gl_pathv[x]);
1410 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) {
1411 globfree64(&gl);
1412 return i;
1413 }
1414 }
1415 globfree64 (&gl);
1416 continue;
1417 } else
1418 abort();
1419 }
1420 if (*path != '/')
1421 continue;
947 1422
948 ldpaths[i++] = xstrdup(path); 1423 ldpaths[i++] = xstrdup(path);
949 1424
950 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1425 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
951 break; 1426 break;
952 } 1427 }
953 ldpaths[i] = NULL; 1428 ldpaths[i] = NULL;
954 1429
955 fclose(fp); 1430 fclose(fp);
1431 return i;
956} 1432}
1433#endif
1434
1435#if defined(__FreeBSD__) || (__DragonFly__)
1436static int load_ld_so_hints(int i, const char *fname)
1437{
1438 FILE *fp = NULL;
1439 char *b = NULL, *p;
1440 struct elfhints_hdr hdr;
1441
1442 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1443 return i;
1444
1445 if ((fp = fopen(fname, "r")) == NULL)
1446 return i;
1447
1448 if ( fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1449 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1450 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1
1451 ) {
1452 fclose(fp);
1453 return i;
1454 }
1455
1456 b = (char*)malloc(hdr.dirlistlen+1);
1457 if ( fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1 ) {
1458 fclose(fp);
1459 free(b);
1460 return i;
1461 }
1462
1463 while ( (p = strsep(&b, ":")) ) {
1464 if ( *p == '\0' ) continue;
1465 ldpaths[i++] = xstrdup(p);
1466
1467 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1468 break;
1469 }
1470 ldpaths[i] = NULL;
1471
1472 free(b);
1473 fclose(fp);
1474 return i;
1475}
1476#endif
957 1477
958/* scan /etc/ld.so.conf for paths */ 1478/* scan /etc/ld.so.conf for paths */
959static void scanelf_ldpath() 1479static void scanelf_ldpath()
960{ 1480{
961 char scan_l, scan_ul, scan_ull; 1481 char scan_l, scan_ul, scan_ull;
995 } 1515 }
996 1516
997 free(path); 1517 free(path);
998} 1518}
999 1519
1000
1001
1002/* usage / invocation handling functions */ 1520/* usage / invocation handling functions */
1003#define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV" 1521#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1004#define a_argument required_argument 1522#define a_argument required_argument
1005static struct option const long_opts[] = { 1523static struct option const long_opts[] = {
1006 {"path", no_argument, NULL, 'p'}, 1524 {"path", no_argument, NULL, 'p'},
1007 {"ldpath", no_argument, NULL, 'l'}, 1525 {"ldpath", no_argument, NULL, 'l'},
1008 {"recursive", no_argument, NULL, 'R'}, 1526 {"recursive", no_argument, NULL, 'R'},
1009 {"mount", no_argument, NULL, 'm'}, 1527 {"mount", no_argument, NULL, 'm'},
1010 {"symlink", no_argument, NULL, 'y'}, 1528 {"symlink", no_argument, NULL, 'y'},
1529 {"archives", no_argument, NULL, 'A'},
1530 {"ldcache", no_argument, NULL, 'L'},
1531 {"fix", no_argument, NULL, 'X'},
1532 {"setpax", a_argument, NULL, 'z'},
1011 {"pax", no_argument, NULL, 'x'}, 1533 {"pax", no_argument, NULL, 'x'},
1012 {"header", no_argument, NULL, 'e'}, 1534 {"header", no_argument, NULL, 'e'},
1013 {"textrel", no_argument, NULL, 't'}, 1535 {"textrel", no_argument, NULL, 't'},
1014 {"rpath", no_argument, NULL, 'r'}, 1536 {"rpath", no_argument, NULL, 'r'},
1015 {"needed", no_argument, NULL, 'n'}, 1537 {"needed", no_argument, NULL, 'n'},
1016 {"interp", no_argument, NULL, 'i'}, 1538 {"interp", no_argument, NULL, 'i'},
1017 {"bind", no_argument, NULL, 'b'}, 1539 {"bind", no_argument, NULL, 'b'},
1018 {"soname", no_argument, NULL, 'S'}, 1540 {"soname", no_argument, NULL, 'S'},
1019 {"symbol", a_argument, NULL, 's'}, 1541 {"symbol", a_argument, NULL, 's'},
1542 {"section", a_argument, NULL, 'k'},
1020 {"lib", a_argument, NULL, 'N'}, 1543 {"lib", a_argument, NULL, 'N'},
1021 {"gmatch", no_argument, NULL, 'g'}, 1544 {"gmatch", no_argument, NULL, 'g'},
1022 {"textrels", no_argument, NULL, 'T'}, 1545 {"textrels", no_argument, NULL, 'T'},
1546 {"etype", a_argument, NULL, 'E'},
1547 {"bits", a_argument, NULL, 'M'},
1023 {"all", no_argument, NULL, 'a'}, 1548 {"all", no_argument, NULL, 'a'},
1024 {"quiet", no_argument, NULL, 'q'}, 1549 {"quiet", no_argument, NULL, 'q'},
1025 {"verbose", no_argument, NULL, 'v'}, 1550 {"verbose", no_argument, NULL, 'v'},
1026 {"format", a_argument, NULL, 'F'}, 1551 {"format", a_argument, NULL, 'F'},
1027 {"from", a_argument, NULL, 'f'}, 1552 {"from", a_argument, NULL, 'f'},
1035static const char *opts_help[] = { 1560static const char *opts_help[] = {
1036 "Scan all directories in PATH environment", 1561 "Scan all directories in PATH environment",
1037 "Scan all directories in /etc/ld.so.conf", 1562 "Scan all directories in /etc/ld.so.conf",
1038 "Scan directories recursively", 1563 "Scan directories recursively",
1039 "Don't recursively cross mount points", 1564 "Don't recursively cross mount points",
1040 "Don't scan symlinks\n", 1565 "Don't scan symlinks",
1566 "Scan archives (.a files)",
1567 "Utilize ld.so.cache information (use with -r/-n)",
1568 "Try and 'fix' bad things (use with -r/-e)",
1569 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1041 "Print PaX markings", 1570 "Print PaX markings",
1042 "Print GNU_STACK/PT_LOAD markings", 1571 "Print GNU_STACK/PT_LOAD markings",
1043 "Print TEXTREL information", 1572 "Print TEXTREL information",
1044 "Print RPATH information", 1573 "Print RPATH information",
1045 "Print NEEDED information", 1574 "Print NEEDED information",
1046 "Print INTERP information", 1575 "Print INTERP information",
1047 "Print BIND information", 1576 "Print BIND information",
1048 "Print SONAME information", 1577 "Print SONAME information",
1049 "Find a specified symbol", 1578 "Find a specified symbol",
1579 "Find a specified section",
1050 "Find a specified library", 1580 "Find a specified library",
1051 "Use strncmp to match libraries. (use with -N)", 1581 "Use strncmp to match libraries. (use with -N)",
1052 "Locate cause of TEXTREL", 1582 "Locate cause of TEXTREL",
1583 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1584 "Print only ELF files matching numeric bits",
1053 "Print all scanned info (-x -e -t -r -b)\n", 1585 "Print all scanned info (-x -e -t -r -b)\n",
1054 "Only output 'bad' things", 1586 "Only output 'bad' things",
1055 "Be verbose (can be specified more than once)", 1587 "Be verbose (can be specified more than once)",
1056 "Use specified format for output", 1588 "Use specified format for output",
1057 "Read input stream from a filename", 1589 "Read input stream from a filename",
1065/* display usage and exit */ 1597/* display usage and exit */
1066static void usage(int status) 1598static void usage(int status)
1067{ 1599{
1068 unsigned long i; 1600 unsigned long i;
1069 printf("* Scan ELF binaries for stuff\n\n" 1601 printf("* Scan ELF binaries for stuff\n\n"
1070 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1602 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1071 printf("Options: -[%s]\n", PARSE_FLAGS); 1603 printf("Options: -[%s]\n", PARSE_FLAGS);
1072 for (i = 0; long_opts[i].name; ++i) 1604 for (i = 0; long_opts[i].name; ++i)
1073 if (long_opts[i].has_arg == no_argument) 1605 if (long_opts[i].has_arg == no_argument)
1074 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1606 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1075 long_opts[i].name, opts_help[i]); 1607 long_opts[i].name, opts_help[i]);
1076 else 1608 else
1077 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1609 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1078 long_opts[i].name, opts_help[i]); 1610 long_opts[i].name, opts_help[i]);
1079 1611
1080 if (status != EXIT_SUCCESS) 1612 if (status != EXIT_SUCCESS)
1081 exit(status); 1613 exit(status);
1082 1614
1083 puts("\nThe format modifiers for the -F option are:"); 1615 puts("\nThe format modifiers for the -F option are:");
1084 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1616 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1085 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1617 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1086 puts(" i INTERP \tb BIND \ts symbol"); 1618 puts(" i INTERP \tb BIND \ts symbol");
1087 puts(" N library \to Type \tT TEXTRELs"); 1619 puts(" N library \to Type \tT TEXTRELs");
1088 puts(" S SONAME"); 1620 puts(" S SONAME \tk section");
1089 puts(" p filename (with search path removed)"); 1621 puts(" p filename (with search path removed)");
1090 puts(" f filename (short name/basename)"); 1622 puts(" f filename (short name/basename)");
1091 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1623 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1092 1624
1625 puts("\nELF Etypes:");
1626 print_etypes(stdout);
1627
1093 exit(status); 1628 exit(status);
1094} 1629}
1095 1630
1096/* parse command line arguments and preform needed actions */ 1631/* parse command line arguments and preform needed actions */
1097static void parseargs(int argc, char *argv[]) 1632static void parseargs(int argc, char *argv[])
1098{ 1633{
1099 int i; 1634 int i;
1100 char *from_file = NULL; 1635 const char *from_file = NULL;
1101 1636
1102 opterr = 0; 1637 opterr = 0;
1103 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1638 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1104 switch (i) { 1639 switch (i) {
1105 1640
1109 VERSION, __FILE__, __DATE__, rcsid, argv0); 1644 VERSION, __FILE__, __DATE__, rcsid, argv0);
1110 exit(EXIT_SUCCESS); 1645 exit(EXIT_SUCCESS);
1111 break; 1646 break;
1112 case 'h': usage(EXIT_SUCCESS); break; 1647 case 'h': usage(EXIT_SUCCESS); break;
1113 case 'f': 1648 case 'f':
1114 if (from_file) err("Don't specify -f twice"); 1649 if (from_file) warn("You prob don't want to specify -f twice");
1115 from_file = xstrdup(optarg); 1650 from_file = optarg;
1651 break;
1652 case 'E':
1653 strncpy(match_etypes, optarg, sizeof(match_etypes));
1654 break;
1655 case 'M':
1656 match_bits = atoi(optarg);
1116 break; 1657 break;
1117 case 'o': { 1658 case 'o': {
1118 FILE *fp = NULL;
1119 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1659 if (freopen(optarg, "w", stdout) == NULL)
1120 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1660 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1121 SET_STDOUT(fp);
1122 break; 1661 break;
1123 } 1662 }
1124 1663 case 'k':
1664 if (find_section) warn("You prob don't want to specify -k twice");
1665 find_section = optarg;
1666 break;
1125 case 's': { 1667 case 's': {
1126 if (find_sym) warn("You prob don't want to specify -s twice"); 1668 if (find_sym) warn("You prob don't want to specify -s twice");
1127 find_sym = optarg; 1669 find_sym = optarg;
1128 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1670 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1129 sprintf(versioned_symname, "%s@", find_sym); 1671 sprintf(versioned_symname, "%s@", find_sym);
1138 case 'F': { 1680 case 'F': {
1139 if (out_format) warn("You prob don't want to specify -F twice"); 1681 if (out_format) warn("You prob don't want to specify -F twice");
1140 out_format = optarg; 1682 out_format = optarg;
1141 break; 1683 break;
1142 } 1684 }
1685 case 'z': {
1686 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1687 size_t x;
1143 1688
1689 for (x = 0 ; x < strlen(optarg); x++) {
1690 switch(optarg[x]) {
1691 case 'p':
1692 case 'P':
1693 do_state(optarg[x], PAGEEXEC);
1694 break;
1695 case 's':
1696 case 'S':
1697 do_state(optarg[x], SEGMEXEC);
1698 break;
1699 case 'm':
1700 case 'M':
1701 do_state(optarg[x], MPROTECT);
1702 break;
1703 case 'e':
1704 case 'E':
1705 do_state(optarg[x], EMUTRAMP);
1706 break;
1707 case 'r':
1708 case 'R':
1709 do_state(optarg[x], RANDMMAP);
1710 break;
1711 case 'x':
1712 case 'X':
1713 do_state(optarg[x], RANDEXEC);
1714 break;
1715 default:
1716 break;
1717 }
1718 }
1719 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1720 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1721 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1722 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1723 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1724 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1725 setpax = flags;
1726 break;
1727 }
1144 case 'g': gmatch = 1; 1728 case 'g': gmatch = 1; break;
1729 case 'L': use_ldcache = 1; break;
1145 case 'y': scan_symlink = 0; break; 1730 case 'y': scan_symlink = 0; break;
1731 case 'A': scan_archives = 1; break;
1146 case 'B': show_banner = 0; break; 1732 case 'B': show_banner = 0; break;
1147 case 'l': scan_ldpath = 1; break; 1733 case 'l': scan_ldpath = 1; break;
1148 case 'p': scan_envpath = 1; break; 1734 case 'p': scan_envpath = 1; break;
1149 case 'R': dir_recurse = 1; break; 1735 case 'R': dir_recurse = 1; break;
1150 case 'm': dir_crossmount = 0; break; 1736 case 'm': dir_crossmount = 0; break;
1737 case 'X': ++fix_elf; break;
1151 case 'x': show_pax = 1; break; 1738 case 'x': show_pax = 1; break;
1152 case 'e': show_phdr = 1; break; 1739 case 'e': show_phdr = 1; break;
1153 case 't': show_textrel = 1; break; 1740 case 't': show_textrel = 1; break;
1154 case 'r': show_rpath = 1; break; 1741 case 'r': show_rpath = 1; break;
1155 case 'n': show_needed = 1; break; 1742 case 'n': show_needed = 1; break;
1160 case 'q': be_quiet = 1; break; 1747 case 'q': be_quiet = 1; break;
1161 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1748 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1162 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1749 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1163 1750
1164 case ':': 1751 case ':':
1165 err("Option missing parameter\n"); 1752 err("Option '%c' is missing parameter", optopt);
1166 case '?': 1753 case '?':
1167 err("Unknown option\n"); 1754 err("Unknown option '%c' or argument missing", optopt);
1168 default: 1755 default:
1169 err("Unhandled option '%c'", i); 1756 err("Unhandled option '%c'; please report this", i);
1170 } 1757 }
1171 } 1758 }
1172 1759
1173 /* let the format option override all other options */ 1760 /* let the format option override all other options */
1174 if (out_format) { 1761 if (out_format) {
1177 show_textrels = 0; 1764 show_textrels = 0;
1178 for (i = 0; out_format[i]; ++i) { 1765 for (i = 0; out_format[i]; ++i) {
1179 if (!IS_MODIFIER(out_format[i])) continue; 1766 if (!IS_MODIFIER(out_format[i])) continue;
1180 1767
1181 switch (out_format[++i]) { 1768 switch (out_format[++i]) {
1769 case '+': break;
1182 case '%': break; 1770 case '%': break;
1183 case '#': break; 1771 case '#': break;
1184 case 'F': break; 1772 case 'F': break;
1185 case 'p': break; 1773 case 'p': break;
1186 case 'f': break; 1774 case 'f': break;
1775 case 'k': break;
1187 case 's': break; 1776 case 's': break;
1188 case 'N': break; 1777 case 'N': break;
1189 case 'o': break; 1778 case 'o': break;
1190 case 'x': show_pax = 1; break; 1779 case 'x': show_pax = 1; break;
1191 case 'e': show_phdr = 1; break; 1780 case 'e': show_phdr = 1; break;
1215 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1804 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1216 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1805 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1217 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1806 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1218 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1807 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1219 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1808 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1809 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1220 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1810 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1221 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1811 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1222 } 1812 }
1223 if (be_verbose > 2) printf("Format: %s\n", out_format); 1813 if (be_verbose > 2) printf("Format: %s\n", out_format);
1224 1814
1225 /* now lets actually do the scanning */ 1815 /* now lets actually do the scanning */
1226 if (scan_ldpath || (show_rpath && be_quiet)) 1816 if (scan_ldpath || use_ldcache)
1227 load_ld_so_conf(); 1817#if defined(__GLIBC__) || defined(__UCLIBC__)
1818 load_ld_so_conf(0, "/etc/ld.so.conf");
1819#elif defined(__FreeBSD__) || defined(__DragonFly__)
1820 load_ld_so_hints(0, _PATH_ELF_HINTS);
1821#endif
1228 if (scan_ldpath) scanelf_ldpath(); 1822 if (scan_ldpath) scanelf_ldpath();
1229 if (scan_envpath) scanelf_envpath(); 1823 if (scan_envpath) scanelf_envpath();
1824 if (!from_file && optind == argc && ttyname(0) == NULL)
1825 from_file = "-";
1230 if (from_file) { 1826 if (from_file) {
1231 scanelf_from_file(from_file); 1827 scanelf_from_file(from_file);
1232 free(from_file);
1233 from_file = *argv; 1828 from_file = *argv;
1234 } 1829 }
1235 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1830 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1236 err("Nothing to scan !?"); 1831 err("Nothing to scan !?");
1237 while (optind < argc) { 1832 while (optind < argc) {
1241 1836
1242 /* clean up */ 1837 /* clean up */
1243 if (versioned_symname) free(versioned_symname); 1838 if (versioned_symname) free(versioned_symname);
1244 for (i = 0; ldpaths[i]; ++i) 1839 for (i = 0; ldpaths[i]; ++i)
1245 free(ldpaths[i]); 1840 free(ldpaths[i]);
1246}
1247 1841
1248 1842 if (ldcache != 0)
1249 1843 munmap(ldcache, ldcache_size);
1250/* utility funcs */
1251static char *xstrdup(const char *s)
1252{
1253 char *ret = strdup(s);
1254 if (!ret) err("Could not strdup(): %s", strerror(errno));
1255 return ret;
1256} 1844}
1257 1845
1258static void *xmalloc(size_t size) 1846static char **get_split_env(const char *envvar) {
1259{ 1847 char **envvals = NULL;
1260 void *ret = malloc(size); 1848 char *saveptr = NULL;
1261 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1849 char *env;
1262 return ret; 1850 char *s;
1263} 1851 int nentry;
1264 1852
1265static void xstrcat(char **dst, const char *src, size_t *curr_len) 1853 if ((env = getenv(envvar)) == NULL)
1266{ 1854 return NULL;
1267 size_t new_len;
1268 1855
1269 new_len = strlen(*dst) + strlen(src); 1856 env = xstrdup(env);
1270 if (*curr_len <= new_len) { 1857 if (env == NULL)
1271 *curr_len = new_len + (*curr_len / 2); 1858 return NULL;
1272 *dst = realloc(*dst, *curr_len);
1273 if (!*dst)
1274 err("could not realloc %li bytes", (unsigned long)*curr_len);
1275 }
1276 1859
1277 strcat(*dst, src); 1860 nentry = 0;
1278} 1861 for (s = strtok_r(env, " \t\n", &saveptr); s != NULL; s = strtok_r(NULL, " \t\n", &saveptr)) {
1862 if ((envvals = xrealloc(envvals, sizeof(char *)*(nentry+1))) == NULL)
1863 return NULL;
1864 envvals[nentry++] = s;
1865 }
1866 envvals[nentry] = NULL;
1279 1867
1280static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1868 return envvals;
1281{ 1869}
1282 static char my_app[2]; 1870
1283 my_app[0] = append; 1871static void parseenv() {
1284 my_app[1] = '\0'; 1872 qa_textrels=get_split_env("QA_TEXTRELS");
1285 xstrcat(dst, my_app, curr_len); 1873 qa_execstack=get_split_env("QA_EXECSTACK");
1874 qa_wx_load=get_split_env("QA_WX_LOAD");
1286} 1875}
1287 1876
1288 1877
1289 1878
1290int main(int argc, char *argv[]) 1879int main(int argc, char *argv[])
1291{ 1880{
1292 if (argc < 2) 1881 if (argc < 2)
1293 usage(EXIT_FAILURE); 1882 usage(EXIT_FAILURE);
1883 parseenv();
1294 parseargs(argc, argv); 1884 parseargs(argc, argv);
1295 fclose(stdout); 1885 fclose(stdout);
1296#ifdef __BOUNDS_CHECKING_ON 1886#ifdef __BOUNDS_CHECKING_ON
1297 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 1887 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1298#endif 1888#endif

Legend:
Removed from v.1.94  
changed lines
  Added in v.1.146

  ViewVC Help
Powered by ViewVC 1.1.20