/[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.89 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.89 2005/10/13 01:53:55 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#define __USE_GNU
16#include <string.h>
17#include <errno.h>
18#include <unistd.h>
19#include <sys/stat.h>
20#include <dirent.h>
21#include <getopt.h>
22#include <assert.h>
23#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
24 17
25static const char *rcsid = "$Id: scanelf.c,v 1.89 2005/10/13 01:53:55 vapier Exp $"; 18static const char *rcsid = "$Id: scanelf.c,v 1.146 2006/05/14 21:04:25 vapier Exp $";
26#define argv0 "scanelf" 19#define argv0 "scanelf"
27 20
28#define IS_MODIFIER(c) (c == '%' || c == '#') 21#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
29 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 }
30 31
31 32
32/* 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);
33static void scanelf_file(const char *filename); 38static void scanelf_file(const char *filename);
34static void scanelf_dir(const char *path); 39static void scanelf_dir(const char *path);
35static void scanelf_ldpath(); 40static void scanelf_ldpath(void);
36static void scanelf_envpath(); 41static void scanelf_envpath(void);
37static void usage(int status); 42static void usage(int status);
43static char **get_split_env(const char *envvar);
44static void parseenv(void);
38static void parseargs(int argc, char *argv[]); 45static void parseargs(int argc, char *argv[]);
39static char *xstrdup(const char *s); 46static char *xstrdup(const char *s);
40static void *xmalloc(size_t size); 47static void *xmalloc(size_t size);
48static void *xrealloc(void *ptr, size_t size);
41static 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)
42static 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);
43 52
44/* variables to control behavior */ 53/* variables to control behavior */
54static char match_etypes[126] = "";
45static char *ldpaths[256]; 55static char *ldpaths[256];
46static char scan_ldpath = 0; 56static char scan_ldpath = 0;
47static char scan_envpath = 0; 57static char scan_envpath = 0;
48static char scan_symlink = 1; 58static char scan_symlink = 1;
59static char scan_archives = 0;
49static char dir_recurse = 0; 60static char dir_recurse = 0;
50static char dir_crossmount = 1; 61static char dir_crossmount = 1;
51static char show_pax = 0; 62static char show_pax = 0;
52static char show_phdr = 0; 63static char show_phdr = 0;
53static char show_textrel = 0; 64static char show_textrel = 0;
59static char show_textrels = 0; 70static char show_textrels = 0;
60static char show_banner = 1; 71static char show_banner = 1;
61static char be_quiet = 0; 72static char be_quiet = 0;
62static char be_verbose = 0; 73static char be_verbose = 0;
63static char be_wewy_wewy_quiet = 0; 74static char be_wewy_wewy_quiet = 0;
75static char be_semi_verbose = 0;
64static char *find_sym = NULL, *versioned_symname = NULL; 76static char *find_sym = NULL, *versioned_symname = NULL;
65static char *find_lib = NULL; 77static char *find_lib = NULL;
78static char *find_section = NULL;
66static char *out_format = NULL; 79static char *out_format = NULL;
67static char *search_path = NULL; 80static char *search_path = NULL;
81static char fix_elf = 0;
68static char gmatch = 0; 82static char gmatch = 0;
83static char use_ldcache = 0;
69 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}
70 160
71/* sub-funcs for scanelf_file() */ 161/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 162static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{ 163{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 164 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
93 } \ 183 } \
94 } 184 }
95 GET_SYMTABS(32) 185 GET_SYMTABS(32)
96 GET_SYMTABS(64) 186 GET_SYMTABS(64)
97} 187}
188
98static char *scanelf_file_pax(elfobj *elf, char *found_pax) 189static char *scanelf_file_pax(elfobj *elf, char *found_pax)
99{ 190{
100 static char *paxflags;
101 static char ret[7]; 191 static char ret[7];
102 unsigned long i, shown; 192 unsigned long i, shown;
103 193
104 if (!show_pax) return NULL; 194 if (!show_pax) return NULL;
105 195
112 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 202 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
113 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 203 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
114 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 204 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
115 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 205 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
116 continue; \ 206 continue; \
117 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))) \
118 continue; \ 212 continue; \
119 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); \
120 *found_pax = 1; \ 214 *found_pax = 1; \
121 ++shown; \ 215 ++shown; \
122 break; \ 216 break; \
124 } 218 }
125 SHOW_PAX(32) 219 SHOW_PAX(32)
126 SHOW_PAX(64) 220 SHOW_PAX(64)
127 } 221 }
128 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 }
233 }
234
129 /* fall back to EI_PAX if no PT_PAX was found */ 235 /* fall back to EI_PAX if no PT_PAX was found */
130 if (!*ret) { 236 if (!*ret) {
237 static char *paxflags;
131 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 238 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
132 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 239 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
133 *found_pax = 1; 240 *found_pax = 1;
134 return paxflags; 241 return (be_wewy_wewy_quiet ? NULL : paxflags);
135 } 242 }
136 strncpy(ret, paxflags, sizeof(ret)); 243 strncpy(ret, paxflags, sizeof(ret));
137 } 244 }
138 245
139 if (be_quiet && !shown) 246 if (be_wewy_wewy_quiet || (be_quiet && !shown))
140 return NULL; 247 return NULL;
248 else
141 return ret; 249 return ret;
142
143} 250}
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, off, shown, check_flags;
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
158 if (elf->phdr) { 267#define NOTE_GNU_STACK ".note.GNU-stack"
159#define SHOW_PHDR(B) \ 268#define SHOW_PHDR(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \ 269 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 270 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
271 Elf ## B ## _Off offset; \
272 uint32_t flags, check_flags; \
273 if (elf->phdr != NULL) { \
162 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 274 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
163 uint32_t flags; \
164 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 275 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
165 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 276 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
166 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)) {\
167 found = found_phdr; \ 279 found = found_phdr; \
168 off = 0; \ 280 offset = 0; \
169 check_flags = PF_X; \ 281 check_flags = PF_X; \
282 } else continue; \
170 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 283 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
171 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); \
172 found = found_relro; \ 285 found = found_relro; \
173 off = 4; \ 286 offset = 4; \
174 check_flags = PF_X; \ 287 check_flags = PF_X; \
175 } 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) \
176 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)) {\
177 found = found_load; \ 292 found = found_load; \
178 off = 8; \ 293 offset = 8; \
179 check_flags = PF_W|PF_X; \ 294 check_flags = PF_W|PF_X; \
295 } else continue; \
180 } else \ 296 } else \
181 continue; \ 297 continue; \
182 flags = EGET(phdr[i].p_flags); \ 298 flags = EGET(phdr[i].p_flags); \
183 if (be_quiet && ((flags & check_flags) != check_flags)) \ 299 if (be_quiet && ((flags & check_flags) != check_flags)) \
184 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 } \
185 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \ 306 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
186 *found = 1; \ 307 *found = 1; \
187 ++shown; \ 308 ++shown; \
309 } \
310 } else if (elf->shdr != NULL) { \
311 /* no program headers which means this is prob an object file */ \
312 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
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; \
317 check_flags = SHF_WRITE|SHF_EXECINSTR; \
318 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
319 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
320 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
321 str = elf->data + offset; \
322 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
323 if (!strcmp(str, NOTE_GNU_STACK)) { \
324 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
325 flags = EGET(shdr[i].sh_flags); \
326 if (be_quiet && ((flags & check_flags) != check_flags)) \
327 continue; \
328 ++*found_phdr; \
329 shown = 1; \
330 if (flags & SHF_WRITE) ret[0] = 'W'; \
331 if (flags & SHF_ALLOC) ret[1] = 'A'; \
332 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
333 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
334 break; \
335 } \
336 } \
337 skip_this_shdr##B: \
338 if (!multi_stack) { \
339 *found_phdr = 1; \
340 shown = 1; \
341 memcpy(ret, "!WX", 3); \
342 } \
188 } \ 343 } \
189 } 344 }
190 SHOW_PHDR(32) 345 SHOW_PHDR(32)
191 SHOW_PHDR(64) 346 SHOW_PHDR(64)
192 }
193 347
194 if (be_quiet && !shown) 348 if (be_wewy_wewy_quiet || (be_quiet && !shown))
195 return NULL; 349 return NULL;
196 else 350 else
197 return ret; 351 return ret;
198} 352}
353
199static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 354static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
200{ 355{
201 static char ret[] = "TEXTREL"; 356 static const char *ret = "TEXTREL";
202 unsigned long i; 357 unsigned long i;
203 358
204 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;
205 362
206 if (elf->phdr) { 363 if (elf->phdr) {
207#define SHOW_TEXTREL(B) \ 364#define SHOW_TEXTREL(B) \
208 if (elf->elf_class == ELFCLASS ## B) { \ 365 if (elf->elf_class == ELFCLASS ## B) { \
209 Elf ## B ## _Dyn *dyn; \ 366 Elf ## B ## _Dyn *dyn; \
229 } 386 }
230 387
231 if (be_quiet || be_wewy_wewy_quiet) 388 if (be_quiet || be_wewy_wewy_quiet)
232 return NULL; 389 return NULL;
233 else 390 else
234 return (char *)" - "; 391 return " - ";
235} 392}
236static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 393static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
237{ 394{
238 unsigned long s, r, rmax; 395 unsigned long s, r, rmax;
239 void *symtab_void, *strtab_void, *text_void; 396 void *symtab_void, *strtab_void, *text_void;
292 if (be_verbose <= 2) continue; \ 449 if (be_verbose <= 2) continue; \
293 } else \ 450 } else \
294 *found_textrels = 1; \ 451 *found_textrels = 1; \
295 /* locate this relocation symbol name */ \ 452 /* locate this relocation symbol name */ \
296 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 } \
297 sym_max = ELF ## B ## _R_SYM(r_info); \ 458 sym_max = ELF ## B ## _R_SYM(r_info); \
298 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 459 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
299 sym += sym_max; \ 460 sym += sym_max; \
300 else \ 461 else \
301 sym = NULL; \ 462 sym = NULL; \
333 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);
334 495
335 return NULL; 496 return NULL;
336} 497}
337 498
338static void rpath_security_checks(elfobj *, char *); 499static void rpath_security_checks(elfobj *, char *, const char *);
339static void rpath_security_checks(elfobj *elf, char *item) { 500static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
501{
340 struct stat st; 502 struct stat st;
341 switch (*item) { 503 switch (*item) {
342 case '/': break; 504 case '/': break;
343 case '.': 505 case '.':
344 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);
345 break; 507 break;
508 case ':':
346 case '\0': 509 case '\0':
347 warnf("Security problem NULL RPATH in %s", elf->filename); 510 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
348 break; 511 break;
349 case '$': 512 case '$':
350 if (fstat(elf->fd, &st) != -1) 513 if (fstat(elf->fd, &st) != -1)
351 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 514 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
352 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",
353 item, elf->filename, st.st_mode & 07777); 516 dt_type, item, elf->filename, st.st_mode & 07777);
354 break; 517 break;
355 default: 518 default:
356 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);
357 break; 520 break;
358 } 521 }
359} 522}
360static 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)
361{ 524{
397 /* Verify the memory is somewhat sane */ \ 560 /* Verify the memory is somewhat sane */ \
398 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 561 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
399 if (offset < (Elf ## B ## _Off)elf->len) { \ 562 if (offset < (Elf ## B ## _Off)elf->len) { \
400 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 563 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
401 *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); \
402 /* If quiet, don't output paths in ld.so.conf */ \ 568 /* If quiet, don't output paths in ld.so.conf */ \
403 if (be_quiet) { \ 569 if (be_quiet) { \
404 size_t len; \ 570 size_t len; \
405 char *start, *end; \ 571 char *start, *end; \
406 /* note that we only 'chop' off leading known paths. */ \ 572 /* note that we only 'chop' off leading known paths. */ \
407 /* 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. */ \
408 start = *r; \ 574 start = *r; \
409 /* scan each path in : delimited list */ \ 575 /* scan each path in : delimited list */ \
410 while (start) { \ 576 while (start) { \
411 rpath_security_checks(elf, start); \ 577 rpath_security_checks(elf, start, get_elfdtype(word)); \
412 end = strchr(start, ':'); \ 578 end = strchr(start, ':'); \
413 len = (end ? abs(end - start) : strlen(start)); \ 579 len = (end ? abs(end - start) : strlen(start)); \
580 if (use_ldcache) \
414 for (s = 0; ldpaths[s]; ++s) { \ 581 for (s = 0; ldpaths[s]; ++s) \
415 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 582 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
416 *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)++; \
417 break; \ 588 break; \
418 } \ 589 } \
419 } \
420 if (!*r || !ldpaths[s] || !end) \ 590 if (!*r || !end) \
421 start = NULL; \ 591 break; \
422 else \ 592 else \
423 start = start + len + 1; \ 593 start = start + len + 1; \
424 } \ 594 } \
425 } \ 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) \
426 if (*r) *found_rpath = 1; \ 636 *found_rpath = 1; \
637 } \
427 } \ 638 } \
428 ++dyn; \ 639 ++dyn; \
429 } \ 640 } \
430 } } 641 } }
431 SHOW_RPATH(32) 642 SHOW_RPATH(32)
448 } else if (rpath || runpath) 659 } else if (rpath || runpath)
449 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 660 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
450 else if (!be_quiet) 661 else if (!be_quiet)
451 xstrcat(ret, " - ", ret_len); 662 xstrcat(ret, " - ", ret_len);
452} 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
453static 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)
454{ 760{
455 unsigned long i; 761 unsigned long i;
456 char *needed; 762 char *needed;
457 void *strtbl_void; 763 void *strtbl_void;
764 char *p;
458 765
459 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 766 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
460 767
461 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 768 strtbl_void = elf_findsecbyname(elf, ".dynstr");
462 769
482 } \ 789 } \
483 needed = (char*)(elf->data + offset); \ 790 needed = (char*)(elf->data + offset); \
484 if (op == 0) { \ 791 if (op == 0) { \
485 if (!be_wewy_wewy_quiet) { \ 792 if (!be_wewy_wewy_quiet) { \
486 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; \
487 xstrcat(ret, needed, ret_len); \ 797 xstrcat(ret, needed, ret_len); \
488 } \ 798 } \
489 *found_needed = 1; \ 799 *found_needed = 1; \
490 } else { \ 800 } else { \
491 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 801 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
527} 837}
528static char *scanelf_file_bind(elfobj *elf, char *found_bind) 838static char *scanelf_file_bind(elfobj *elf, char *found_bind)
529{ 839{
530 unsigned long i; 840 unsigned long i;
531 struct stat s; 841 struct stat s;
842 char dynamic = 0;
532 843
533 if (!show_bind) return NULL; 844 if (!show_bind) return NULL;
534 if (!elf->phdr) return NULL; 845 if (!elf->phdr) return NULL;
535 846
536#define SHOW_BIND(B) \ 847#define SHOW_BIND(B) \
539 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 850 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
540 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 851 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
541 Elf ## B ## _Off offset; \ 852 Elf ## B ## _Off offset; \
542 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 853 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
543 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 854 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
855 dynamic = 1; \
544 offset = EGET(phdr[i].p_offset); \ 856 offset = EGET(phdr[i].p_offset); \
545 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 857 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
546 dyn = DYN ## B (elf->data + offset); \ 858 dyn = DYN ## B (elf->data + offset); \
547 while (EGET(dyn->d_tag) != DT_NULL) { \ 859 while (EGET(dyn->d_tag) != DT_NULL) { \
548 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 860 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
563 875
564 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)) {
565 return NULL; 877 return NULL;
566 } else { 878 } else {
567 *found_bind = 1; 879 *found_bind = 1;
568 return (char *) "LAZY"; 880 return (char *) (dynamic ? "LAZY" : "STATIC");
569 } 881 }
570} 882}
571static char *scanelf_file_soname(elfobj *elf, char *found_soname) 883static char *scanelf_file_soname(elfobj *elf, char *found_soname)
572{ 884{
573 unsigned long i; 885 unsigned long i;
615 return NULL; 927 return NULL;
616} 928}
617static char *scanelf_file_sym(elfobj *elf, char *found_sym) 929static char *scanelf_file_sym(elfobj *elf, char *found_sym)
618{ 930{
619 unsigned long i; 931 unsigned long i;
932 char *ret;
620 void *symtab_void, *strtab_void; 933 void *symtab_void, *strtab_void;
621 934
622 if (!find_sym) return NULL; 935 if (!find_sym) return NULL;
936 ret = find_sym;
623 937
624 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 938 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
625 939
626 if (symtab_void && strtab_void) { 940 if (symtab_void && strtab_void) {
627#define FIND_SYM(B) \ 941#define FIND_SYM(B) \
628 if (elf->elf_class == ELFCLASS ## B) { \ 942 if (elf->elf_class == ELFCLASS ## B) { \
629 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 943 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
630 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 944 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
631 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)); \
632 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 946 unsigned long cnt = EGET(symtab->sh_entsize); \
633 char *symname; \ 947 char *symname; \
948 if (cnt) \
949 cnt = EGET(symtab->sh_size) / cnt; \
634 for (i = 0; i < cnt; ++i) { \ 950 for (i = 0; i < cnt; ++i) { \
635 if (sym->st_name) { \ 951 if (sym->st_name) { \
952 /* make sure the symbol name is in acceptable memory range */ \
636 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 */ \
637 if (*find_sym == '*') { \ 960 if (*ret == '*') { \
638 printf("%s(%s) %5lX %15s %s\n", \ 961 printf("%s(%s) %5lX %15s %s\n", \
639 ((*found_sym == 0) ? "\n\t" : "\t"), \ 962 ((*found_sym == 0) ? "\n\t" : "\t"), \
640 elf->base_filename, \ 963 elf->base_filename, \
641 (long)sym->st_size, \ 964 (unsigned long)sym->st_size, \
642 (char *)get_elfstttype(sym->st_info), \ 965 get_elfstttype(sym->st_info), \
643 symname); \ 966 symname); \
644 *found_sym = 1; \ 967 *found_sym = 1; \
645 } else if ((strcmp(find_sym, symname) == 0) || \ 968 } else { \
646 (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; \
647 (*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 } \
648 } \ 1003 } \
649 ++sym; \ 1004 ++sym; \
650 } } 1005 } }
651 FIND_SYM(32) 1006 FIND_SYM(32)
652 FIND_SYM(64) 1007 FIND_SYM(64)
653 } 1008 }
654 1009
1010break_out:
655 if (be_wewy_wewy_quiet) return NULL; 1011 if (be_wewy_wewy_quiet) return NULL;
656 1012
657 if (*find_sym != '*' && *found_sym) 1013 if (*find_sym != '*' && *found_sym)
658 return find_sym; 1014 return ret;
659 if (be_quiet) 1015 if (be_quiet)
660 return NULL; 1016 return NULL;
661 else 1017 else
662 return (char *)" - "; 1018 return (char *)" - ";
663} 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
664/* scan an elf file and show all the fun stuff */ 1051/* scan an elf file and show all the fun stuff */
665#define prints(str) write(fileno(stdout), str, strlen(str)) 1052#define prints(str) write(fileno(stdout), str, strlen(str))
666static void scanelf_file(const char *filename) 1053static int scanelf_elfobj(elfobj *elf)
667{ 1054{
668 unsigned long i; 1055 unsigned long i;
669 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1056 char found_pax, found_phdr, found_relro, found_load, found_textrel,
670 found_rpath, found_needed, found_interp, found_bind, found_soname, 1057 found_rpath, found_needed, found_interp, found_bind, found_soname,
671 found_sym, found_lib, found_file, found_textrels; 1058 found_sym, found_lib, found_file, found_textrels, found_section;
672 elfobj *elf;
673 struct stat st;
674 static char *out_buffer = NULL; 1059 static char *out_buffer = NULL;
675 static size_t out_len; 1060 static size_t out_len;
676 1061
677 /* make sure 'filename' exists */
678 if (lstat(filename, &st) == -1) {
679 if (be_verbose > 2) printf("%s: does not exist\n", filename);
680 return;
681 }
682 /* always handle regular files and handle symlinked files if no -y */
683 if (S_ISLNK(st.st_mode)) {
684 if (!scan_symlink) return;
685 stat(filename, &st);
686 }
687 if (!S_ISREG(st.st_mode)) {
688 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
689 return;
690 }
691
692 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1062 found_pax = found_phdr = found_relro = found_load = found_textrel = \
693 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1063 found_rpath = found_needed = found_interp = found_bind = found_soname = \
694 found_sym = found_lib = found_file = found_textrels = 0; 1064 found_sym = found_lib = found_file = found_textrels = found_section = 0;
695 1065
696 /* verify this is real ELF */
697 if ((elf = readelf(filename)) == NULL) {
698 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
699 return;
700 }
701
702 if (be_verbose > 1) 1066 if (be_verbose > 2)
703 printf("%s: scanning file {%s,%s}\n", filename, 1067 printf("%s: scanning file {%s,%s}\n", elf->filename,
704 get_elfeitype(EI_CLASS, elf->elf_class), 1068 get_elfeitype(EI_CLASS, elf->elf_class),
705 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1069 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
706 else if (be_verbose) 1070 else if (be_verbose > 1)
707 printf("%s: scanning file\n", filename); 1071 printf("%s: scanning file\n", elf->filename);
708 1072
709 /* init output buffer */ 1073 /* init output buffer */
710 if (!out_buffer) { 1074 if (!out_buffer) {
711 out_len = sizeof(char) * 80; 1075 out_len = sizeof(char) * 80;
712 out_buffer = (char*)xmalloc(out_len); 1076 out_buffer = (char*)xmalloc(out_len);
717 if (!be_quiet && show_banner) { 1081 if (!be_quiet && show_banner) {
718 for (i = 0; out_format[i]; ++i) { 1082 for (i = 0; out_format[i]; ++i) {
719 if (!IS_MODIFIER(out_format[i])) continue; 1083 if (!IS_MODIFIER(out_format[i])) continue;
720 1084
721 switch (out_format[++i]) { 1085 switch (out_format[++i]) {
1086 case '+': break;
722 case '%': break; 1087 case '%': break;
723 case '#': break; 1088 case '#': break;
724 case 'F': 1089 case 'F':
725 case 'p': 1090 case 'p':
726 case 'f': prints("FILE "); found_file = 1; break; 1091 case 'f': prints("FILE "); found_file = 1; break;
734 case 'b': prints("BIND "); break; 1099 case 'b': prints("BIND "); break;
735 case 'S': prints("SONAME "); break; 1100 case 'S': prints("SONAME "); break;
736 case 's': prints("SYM "); break; 1101 case 's': prints("SYM "); break;
737 case 'N': prints("LIB "); break; 1102 case 'N': prints("LIB "); break;
738 case 'T': prints("TEXTRELS "); break; 1103 case 'T': prints("TEXTRELS "); break;
1104 case 'k': prints("SECTION "); break;
739 default: warnf("'%c' has no title ?", out_format[i]); 1105 default: warnf("'%c' has no title ?", out_format[i]);
740 } 1106 }
741 } 1107 }
742 if (!found_file) prints("FILE "); 1108 if (!found_file) prints("FILE ");
743 prints("\n"); 1109 prints("\n");
748 /* dump all the good stuff */ 1114 /* dump all the good stuff */
749 for (i = 0; out_format[i]; ++i) { 1115 for (i = 0; out_format[i]; ++i) {
750 const char *out; 1116 const char *out;
751 const char *tmp; 1117 const char *tmp;
752 1118
753 /* make sure we trim leading spaces in quiet mode */
754 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
755 *out_buffer = '\0';
756
757 if (!IS_MODIFIER(out_format[i])) { 1119 if (!IS_MODIFIER(out_format[i])) {
758 xchrcat(&out_buffer, out_format[i], &out_len); 1120 xchrcat(&out_buffer, out_format[i], &out_len);
759 continue; 1121 continue;
760 } 1122 }
761 1123
762 out = NULL; 1124 out = NULL;
763 be_wewy_wewy_quiet = (out_format[i] == '#'); 1125 be_wewy_wewy_quiet = (out_format[i] == '#');
1126 be_semi_verbose = (out_format[i] == '+');
764 switch (out_format[++i]) { 1127 switch (out_format[++i]) {
1128 case '+':
765 case '%': 1129 case '%':
766 case '#': 1130 case '#':
767 xchrcat(&out_buffer, out_format[i], &out_len); break; 1131 xchrcat(&out_buffer, out_format[i], &out_len); break;
768 case 'F': 1132 case 'F':
769 found_file = 1; 1133 found_file = 1;
770 if (be_wewy_wewy_quiet) break; 1134 if (be_wewy_wewy_quiet) break;
771 xstrcat(&out_buffer, filename, &out_len); 1135 xstrcat(&out_buffer, elf->filename, &out_len);
772 break; 1136 break;
773 case 'p': 1137 case 'p':
774 found_file = 1; 1138 found_file = 1;
775 if (be_wewy_wewy_quiet) break; 1139 if (be_wewy_wewy_quiet) break;
776 tmp = filename; 1140 tmp = elf->filename;
777 if (search_path) { 1141 if (search_path) {
778 ssize_t len_search = strlen(search_path); 1142 ssize_t len_search = strlen(search_path);
779 ssize_t len_file = strlen(filename); 1143 ssize_t len_file = strlen(elf->filename);
780 if (!strncmp(filename, search_path, len_search) && \ 1144 if (!strncmp(elf->filename, search_path, len_search) && \
781 len_file > len_search) 1145 len_file > len_search)
782 tmp += len_search; 1146 tmp += len_search;
783 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1147 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
784 } 1148 }
785 xstrcat(&out_buffer, tmp, &out_len); 1149 xstrcat(&out_buffer, tmp, &out_len);
786 break; 1150 break;
787 case 'f': 1151 case 'f':
788 found_file = 1; 1152 found_file = 1;
789 if (be_wewy_wewy_quiet) break; 1153 if (be_wewy_wewy_quiet) break;
790 tmp = strrchr(filename, '/'); 1154 tmp = strrchr(elf->filename, '/');
791 tmp = (tmp == NULL ? filename : tmp+1); 1155 tmp = (tmp == NULL ? elf->filename : tmp+1);
792 xstrcat(&out_buffer, tmp, &out_len); 1156 xstrcat(&out_buffer, tmp, &out_len);
793 break; 1157 break;
794 case 'o': out = get_elfetype(elf); break; 1158 case 'o': out = get_elfetype(elf); break;
795 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1159 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
796 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;
801 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;
802 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1166 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
803 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1167 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
804 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1168 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
805 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;
806 default: warnf("'%c' has no scan code?", out_format[i]); 1171 default: warnf("'%c' has no scan code?", out_format[i]);
807 } 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
808 if (out) xstrcat(&out_buffer, out, &out_len); 1178 xstrcat(&out_buffer, out, &out_len);
1179 }
809 } 1180 }
810 1181
811#define FOUND_SOMETHING() \ 1182#define FOUND_SOMETHING() \
812 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1183 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
813 found_rpath || found_needed || found_interp || found_bind || \ 1184 found_rpath || found_needed || found_interp || found_bind || \
814 found_soname || found_sym || found_lib || found_textrels) 1185 found_soname || found_sym || found_lib || found_textrels || found_section )
815 1186
816 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1187 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
817 xchrcat(&out_buffer, ' ', &out_len); 1188 xchrcat(&out_buffer, ' ', &out_len);
818 xstrcat(&out_buffer, filename, &out_len); 1189 xstrcat(&out_buffer, elf->filename, &out_len);
819 } 1190 }
820 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1191 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
821 puts(out_buffer); 1192 puts(out_buffer);
822 fflush(stdout); 1193 fflush(stdout);
823 } 1194 }
824 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:
825 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);
826} 1298}
827 1299
828/* 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 */
829static void scanelf_dir(const char *path) 1301static void scanelf_dir(const char *path)
830{ 1302{
831 register DIR *dir; 1303 register DIR *dir;
832 register struct dirent *dentry; 1304 register struct dirent *dentry;
833 struct stat st_top, st; 1305 struct stat st_top, st;
834 char buf[_POSIX_PATH_MAX]; 1306 char buf[__PAX_UTILS_PATH_MAX];
835 size_t pathlen = 0, len = 0; 1307 size_t pathlen = 0, len = 0;
836 1308
837 /* make sure path exists */ 1309 /* make sure path exists */
838 if (lstat(path, &st_top) == -1) { 1310 if (lstat(path, &st_top) == -1) {
839 if (be_verbose > 2) printf("%s: does not exist\n", path); 1311 if (be_verbose > 2) printf("%s: does not exist\n", path);
849 /* now scan the dir looking for fun stuff */ 1321 /* now scan the dir looking for fun stuff */
850 if ((dir = opendir(path)) == NULL) { 1322 if ((dir = opendir(path)) == NULL) {
851 warnf("could not opendir %s: %s", path, strerror(errno)); 1323 warnf("could not opendir %s: %s", path, strerror(errno));
852 return; 1324 return;
853 } 1325 }
854 if (be_verbose) printf("%s: scanning dir\n", path); 1326 if (be_verbose > 1) printf("%s: scanning dir\n", path);
855 1327
856 pathlen = strlen(path); 1328 pathlen = strlen(path);
857 while ((dentry = readdir(dir))) { 1329 while ((dentry = readdir(dir))) {
858 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1330 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
859 continue; 1331 continue;
861 if (len >= sizeof(buf)) { 1333 if (len >= sizeof(buf)) {
862 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1334 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
863 (unsigned long)len, (unsigned long)sizeof(buf)); 1335 (unsigned long)len, (unsigned long)sizeof(buf));
864 continue; 1336 continue;
865 } 1337 }
866 sprintf(buf, "%s/%s", path, dentry->d_name); 1338 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
867 if (lstat(buf, &st) != -1) { 1339 if (lstat(buf, &st) != -1) {
868 if (S_ISREG(st.st_mode)) 1340 if (S_ISREG(st.st_mode))
869 scanelf_file(buf); 1341 scanelf_file(buf);
870 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1342 else if (dir_recurse && S_ISDIR(st.st_mode)) {
871 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1343 if (dir_crossmount || (st_top.st_dev == st.st_dev))
874 } 1346 }
875 } 1347 }
876 closedir(dir); 1348 closedir(dir);
877} 1349}
878 1350
879static int scanelf_from_file(char *filename) 1351static int scanelf_from_file(const char *filename)
880{ 1352{
881 FILE *fp = NULL; 1353 FILE *fp = NULL;
882 char *p; 1354 char *p;
883 char path[_POSIX_PATH_MAX]; 1355 char path[__PAX_UTILS_PATH_MAX];
884 1356
885 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1357 if (strcmp(filename, "-") == 0)
886 fp = stdin; 1358 fp = stdin;
887 else if ((fp = fopen(filename, "r")) == NULL) 1359 else if ((fp = fopen(filename, "r")) == NULL)
888 return 1; 1360 return 1;
889 1361
890 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1362 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
891 if ((p = strchr(path, '\n')) != NULL) 1363 if ((p = strchr(path, '\n')) != NULL)
892 *p = 0; 1364 *p = 0;
893 search_path = path; 1365 search_path = path;
894 scanelf_dir(path); 1366 scanelf_dir(path);
895 } 1367 }
896 if (fp != stdin) 1368 if (fp != stdin)
897 fclose(fp); 1369 fclose(fp);
898 return 0; 1370 return 0;
899} 1371}
900 1372
901static void load_ld_so_conf() 1373#if defined(__GLIBC__) || defined(__UCLIBC__)
1374static int load_ld_so_conf(int i, const char *fname)
902{ 1375{
903 FILE *fp = NULL; 1376 FILE *fp = NULL;
904 char *p; 1377 char *p;
905 char path[_POSIX_PATH_MAX]; 1378 char path[__PAX_UTILS_PATH_MAX];
906 int i = 0;
907 1379
908 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1380 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
909 return; 1381 return i;
910 1382
1383 if ((fp = fopen(fname, "r")) == NULL)
1384 return i;
1385
911 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1386 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
912 if (*path != '/')
913 continue;
914
915 if ((p = strrchr(path, '\r')) != NULL) 1387 if ((p = strrchr(path, '\r')) != NULL)
916 *p = 0; 1388 *p = 0;
917 if ((p = strchr(path, '\n')) != NULL) 1389 if ((p = strchr(path, '\n')) != NULL)
918 *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;
919 1422
920 ldpaths[i++] = xstrdup(path); 1423 ldpaths[i++] = xstrdup(path);
921 1424
922 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1425 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
923 break; 1426 break;
924 } 1427 }
925 ldpaths[i] = NULL; 1428 ldpaths[i] = NULL;
926 1429
927 fclose(fp); 1430 fclose(fp);
1431 return i;
928} 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
929 1477
930/* scan /etc/ld.so.conf for paths */ 1478/* scan /etc/ld.so.conf for paths */
931static void scanelf_ldpath() 1479static void scanelf_ldpath()
932{ 1480{
933 char scan_l, scan_ul, scan_ull; 1481 char scan_l, scan_ul, scan_ull;
967 } 1515 }
968 1516
969 free(path); 1517 free(path);
970} 1518}
971 1519
972
973
974/* usage / invocation handling functions */ 1520/* usage / invocation handling functions */
975#define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV" 1521#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
976#define a_argument required_argument 1522#define a_argument required_argument
977static struct option const long_opts[] = { 1523static struct option const long_opts[] = {
978 {"path", no_argument, NULL, 'p'}, 1524 {"path", no_argument, NULL, 'p'},
979 {"ldpath", no_argument, NULL, 'l'}, 1525 {"ldpath", no_argument, NULL, 'l'},
980 {"recursive", no_argument, NULL, 'R'}, 1526 {"recursive", no_argument, NULL, 'R'},
981 {"mount", no_argument, NULL, 'm'}, 1527 {"mount", no_argument, NULL, 'm'},
982 {"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'},
983 {"pax", no_argument, NULL, 'x'}, 1533 {"pax", no_argument, NULL, 'x'},
984 {"header", no_argument, NULL, 'e'}, 1534 {"header", no_argument, NULL, 'e'},
985 {"textrel", no_argument, NULL, 't'}, 1535 {"textrel", no_argument, NULL, 't'},
986 {"rpath", no_argument, NULL, 'r'}, 1536 {"rpath", no_argument, NULL, 'r'},
987 {"needed", no_argument, NULL, 'n'}, 1537 {"needed", no_argument, NULL, 'n'},
988 {"interp", no_argument, NULL, 'i'}, 1538 {"interp", no_argument, NULL, 'i'},
989 {"bind", no_argument, NULL, 'b'}, 1539 {"bind", no_argument, NULL, 'b'},
990 {"soname", no_argument, NULL, 'S'}, 1540 {"soname", no_argument, NULL, 'S'},
991 {"symbol", a_argument, NULL, 's'}, 1541 {"symbol", a_argument, NULL, 's'},
1542 {"section", a_argument, NULL, 'k'},
992 {"lib", a_argument, NULL, 'N'}, 1543 {"lib", a_argument, NULL, 'N'},
993 {"gmatch", no_argument, NULL, 'g'}, 1544 {"gmatch", no_argument, NULL, 'g'},
994 {"textrels", no_argument, NULL, 'T'}, 1545 {"textrels", no_argument, NULL, 'T'},
1546 {"etype", a_argument, NULL, 'E'},
1547 {"bits", a_argument, NULL, 'M'},
995 {"all", no_argument, NULL, 'a'}, 1548 {"all", no_argument, NULL, 'a'},
996 {"quiet", no_argument, NULL, 'q'}, 1549 {"quiet", no_argument, NULL, 'q'},
997 {"verbose", no_argument, NULL, 'v'}, 1550 {"verbose", no_argument, NULL, 'v'},
998 {"format", a_argument, NULL, 'F'}, 1551 {"format", a_argument, NULL, 'F'},
999 {"from", a_argument, NULL, 'f'}, 1552 {"from", a_argument, NULL, 'f'},
1007static const char *opts_help[] = { 1560static const char *opts_help[] = {
1008 "Scan all directories in PATH environment", 1561 "Scan all directories in PATH environment",
1009 "Scan all directories in /etc/ld.so.conf", 1562 "Scan all directories in /etc/ld.so.conf",
1010 "Scan directories recursively", 1563 "Scan directories recursively",
1011 "Don't recursively cross mount points", 1564 "Don't recursively cross mount points",
1012 "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",
1013 "Print PaX markings", 1570 "Print PaX markings",
1014 "Print GNU_STACK/PT_LOAD markings", 1571 "Print GNU_STACK/PT_LOAD markings",
1015 "Print TEXTREL information", 1572 "Print TEXTREL information",
1016 "Print RPATH information", 1573 "Print RPATH information",
1017 "Print NEEDED information", 1574 "Print NEEDED information",
1018 "Print INTERP information", 1575 "Print INTERP information",
1019 "Print BIND information", 1576 "Print BIND information",
1020 "Print SONAME information", 1577 "Print SONAME information",
1021 "Find a specified symbol", 1578 "Find a specified symbol",
1579 "Find a specified section",
1022 "Find a specified library", 1580 "Find a specified library",
1023 "Use strncmp to match libraries. (use with -N)", 1581 "Use strncmp to match libraries. (use with -N)",
1024 "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",
1025 "Print all scanned info (-x -e -t -r -b)\n", 1585 "Print all scanned info (-x -e -t -r -b)\n",
1026 "Only output 'bad' things", 1586 "Only output 'bad' things",
1027 "Be verbose (can be specified more than once)", 1587 "Be verbose (can be specified more than once)",
1028 "Use specified format for output", 1588 "Use specified format for output",
1029 "Read input stream from a filename", 1589 "Read input stream from a filename",
1037/* display usage and exit */ 1597/* display usage and exit */
1038static void usage(int status) 1598static void usage(int status)
1039{ 1599{
1040 unsigned long i; 1600 unsigned long i;
1041 printf("* Scan ELF binaries for stuff\n\n" 1601 printf("* Scan ELF binaries for stuff\n\n"
1042 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1602 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1043 printf("Options: -[%s]\n", PARSE_FLAGS); 1603 printf("Options: -[%s]\n", PARSE_FLAGS);
1044 for (i = 0; long_opts[i].name; ++i) 1604 for (i = 0; long_opts[i].name; ++i)
1045 if (long_opts[i].has_arg == no_argument) 1605 if (long_opts[i].has_arg == no_argument)
1046 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1606 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1047 long_opts[i].name, opts_help[i]); 1607 long_opts[i].name, opts_help[i]);
1048 else 1608 else
1049 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1609 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1050 long_opts[i].name, opts_help[i]); 1610 long_opts[i].name, opts_help[i]);
1051 1611
1052 if (status != EXIT_SUCCESS) 1612 if (status != EXIT_SUCCESS)
1053 exit(status); 1613 exit(status);
1054 1614
1055 puts("\nThe format modifiers for the -F option are:"); 1615 puts("\nThe format modifiers for the -F option are:");
1056 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1616 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1057 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1617 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1058 puts(" i INTERP \tb BIND \ts symbol"); 1618 puts(" i INTERP \tb BIND \ts symbol");
1059 puts(" N library \to Type \tT TEXTRELs"); 1619 puts(" N library \to Type \tT TEXTRELs");
1060 puts(" S SONAME"); 1620 puts(" S SONAME \tk section");
1061 puts(" p filename (with search path removed)"); 1621 puts(" p filename (with search path removed)");
1062 puts(" f filename (short name/basename)"); 1622 puts(" f filename (short name/basename)");
1063 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1623 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1064 1624
1625 puts("\nELF Etypes:");
1626 print_etypes(stdout);
1627
1065 exit(status); 1628 exit(status);
1066} 1629}
1067 1630
1068/* parse command line arguments and preform needed actions */ 1631/* parse command line arguments and preform needed actions */
1069static void parseargs(int argc, char *argv[]) 1632static void parseargs(int argc, char *argv[])
1070{ 1633{
1071 int i; 1634 int i;
1072 char *from_file = NULL; 1635 const char *from_file = NULL;
1073 1636
1074 opterr = 0; 1637 opterr = 0;
1075 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) {
1076 switch (i) { 1639 switch (i) {
1077 1640
1081 VERSION, __FILE__, __DATE__, rcsid, argv0); 1644 VERSION, __FILE__, __DATE__, rcsid, argv0);
1082 exit(EXIT_SUCCESS); 1645 exit(EXIT_SUCCESS);
1083 break; 1646 break;
1084 case 'h': usage(EXIT_SUCCESS); break; 1647 case 'h': usage(EXIT_SUCCESS); break;
1085 case 'f': 1648 case 'f':
1086 if (from_file) err("Don't specify -f twice"); 1649 if (from_file) warn("You prob don't want to specify -f twice");
1087 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);
1088 break; 1657 break;
1089 case 'o': { 1658 case 'o': {
1090 FILE *fp = NULL;
1091 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1659 if (freopen(optarg, "w", stdout) == NULL)
1092 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1660 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1093 SET_STDOUT(fp);
1094 break; 1661 break;
1095 } 1662 }
1096 1663 case 'k':
1664 if (find_section) warn("You prob don't want to specify -k twice");
1665 find_section = optarg;
1666 break;
1097 case 's': { 1667 case 's': {
1098 size_t len;
1099 if (find_sym) err("Don't specify -s twice"); 1668 if (find_sym) warn("You prob don't want to specify -s twice");
1100 find_sym = xstrdup(optarg); 1669 find_sym = optarg;
1101 len = strlen(find_sym) + 1;
1102 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1670 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1103 sprintf(versioned_symname, "%s@", find_sym); 1671 sprintf(versioned_symname, "%s@", find_sym);
1104 break; 1672 break;
1105 } 1673 }
1106 case 'N': { 1674 case 'N': {
1107 if (find_lib) err("Don't specify -N twice"); 1675 if (find_lib) warn("You prob don't want to specify -N twice");
1108 find_lib = xstrdup(optarg); 1676 find_lib = optarg;
1109 break; 1677 break;
1110 } 1678 }
1111 1679
1112 case 'F': { 1680 case 'F': {
1113 if (out_format) err("Don't specify -F twice"); 1681 if (out_format) warn("You prob don't want to specify -F twice");
1114 out_format = xstrdup(optarg); 1682 out_format = optarg;
1683 break;
1684 }
1685 case 'z': {
1686 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1687 size_t x;
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);
1115 break; 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 }
1116 } 1718 }
1117 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 }
1118 case 'g': gmatch = 1; 1728 case 'g': gmatch = 1; break;
1729 case 'L': use_ldcache = 1; break;
1119 case 'y': scan_symlink = 0; break; 1730 case 'y': scan_symlink = 0; break;
1731 case 'A': scan_archives = 1; break;
1120 case 'B': show_banner = 0; break; 1732 case 'B': show_banner = 0; break;
1121 case 'l': scan_ldpath = 1; break; 1733 case 'l': scan_ldpath = 1; break;
1122 case 'p': scan_envpath = 1; break; 1734 case 'p': scan_envpath = 1; break;
1123 case 'R': dir_recurse = 1; break; 1735 case 'R': dir_recurse = 1; break;
1124 case 'm': dir_crossmount = 0; break; 1736 case 'm': dir_crossmount = 0; break;
1737 case 'X': ++fix_elf; break;
1125 case 'x': show_pax = 1; break; 1738 case 'x': show_pax = 1; break;
1126 case 'e': show_phdr = 1; break; 1739 case 'e': show_phdr = 1; break;
1127 case 't': show_textrel = 1; break; 1740 case 't': show_textrel = 1; break;
1128 case 'r': show_rpath = 1; break; 1741 case 'r': show_rpath = 1; break;
1129 case 'n': show_needed = 1; break; 1742 case 'n': show_needed = 1; break;
1134 case 'q': be_quiet = 1; break; 1747 case 'q': be_quiet = 1; break;
1135 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1748 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1136 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;
1137 1750
1138 case ':': 1751 case ':':
1139 err("Option missing parameter\n"); 1752 err("Option '%c' is missing parameter", optopt);
1140 case '?': 1753 case '?':
1141 err("Unknown option\n"); 1754 err("Unknown option '%c' or argument missing", optopt);
1142 default: 1755 default:
1143 err("Unhandled option '%c'", i); 1756 err("Unhandled option '%c'; please report this", i);
1144 } 1757 }
1145 } 1758 }
1146 1759
1147 /* let the format option override all other options */ 1760 /* let the format option override all other options */
1148 if (out_format) { 1761 if (out_format) {
1151 show_textrels = 0; 1764 show_textrels = 0;
1152 for (i = 0; out_format[i]; ++i) { 1765 for (i = 0; out_format[i]; ++i) {
1153 if (!IS_MODIFIER(out_format[i])) continue; 1766 if (!IS_MODIFIER(out_format[i])) continue;
1154 1767
1155 switch (out_format[++i]) { 1768 switch (out_format[++i]) {
1769 case '+': break;
1156 case '%': break; 1770 case '%': break;
1157 case '#': break; 1771 case '#': break;
1158 case 'F': break; 1772 case 'F': break;
1159 case 'p': break; 1773 case 'p': break;
1160 case 'f': break; 1774 case 'f': break;
1775 case 'k': break;
1161 case 's': break; 1776 case 's': break;
1162 case 'N': break; 1777 case 'N': break;
1163 case 'o': break; 1778 case 'o': break;
1164 case 'x': show_pax = 1; break; 1779 case 'x': show_pax = 1; break;
1165 case 'e': show_phdr = 1; break; 1780 case 'e': show_phdr = 1; break;
1189 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1804 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1190 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1805 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1191 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1806 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1192 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1807 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1193 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);
1194 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1810 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1195 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1811 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1196 } 1812 }
1197 if (be_verbose > 2) printf("Format: %s\n", out_format); 1813 if (be_verbose > 2) printf("Format: %s\n", out_format);
1198 1814
1199 /* now lets actually do the scanning */ 1815 /* now lets actually do the scanning */
1200 if (scan_ldpath || (show_rpath && be_quiet)) 1816 if (scan_ldpath || use_ldcache)
1201 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
1202 if (scan_ldpath) scanelf_ldpath(); 1822 if (scan_ldpath) scanelf_ldpath();
1203 if (scan_envpath) scanelf_envpath(); 1823 if (scan_envpath) scanelf_envpath();
1824 if (!from_file && optind == argc && ttyname(0) == NULL)
1825 from_file = "-";
1204 if (from_file) { 1826 if (from_file) {
1205 scanelf_from_file(from_file); 1827 scanelf_from_file(from_file);
1206 free(from_file);
1207 from_file = *argv; 1828 from_file = *argv;
1208 } 1829 }
1209 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1830 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1210 err("Nothing to scan !?"); 1831 err("Nothing to scan !?");
1211 while (optind < argc) { 1832 while (optind < argc) {
1212 search_path = argv[optind++]; 1833 search_path = argv[optind++];
1213 scanelf_dir(search_path); 1834 scanelf_dir(search_path);
1214 } 1835 }
1215 1836
1216 /* clean up */ 1837 /* clean up */
1217 if (find_sym) { 1838 if (versioned_symname) free(versioned_symname);
1218 free(find_sym);
1219 free(versioned_symname);
1220 }
1221 if (find_lib) free(find_lib);
1222 if (out_format) free(out_format);
1223 for (i = 0; ldpaths[i]; ++i) 1839 for (i = 0; ldpaths[i]; ++i)
1224 free(ldpaths[i]); 1840 free(ldpaths[i]);
1225}
1226 1841
1227 1842 if (ldcache != 0)
1228 1843 munmap(ldcache, ldcache_size);
1229/* utility funcs */
1230static char *xstrdup(const char *s)
1231{
1232 char *ret = strdup(s);
1233 if (!ret) err("Could not strdup(): %s", strerror(errno));
1234 return ret;
1235} 1844}
1236 1845
1237static void *xmalloc(size_t size) 1846static char **get_split_env(const char *envvar) {
1238{ 1847 char **envvals = NULL;
1239 void *ret = malloc(size); 1848 char *saveptr = NULL;
1240 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1849 char *env;
1241 return ret; 1850 char *s;
1242} 1851 int nentry;
1243 1852
1244static void xstrcat(char **dst, const char *src, size_t *curr_len) 1853 if ((env = getenv(envvar)) == NULL)
1245{ 1854 return NULL;
1246 size_t new_len;
1247 1855
1248 new_len = strlen(*dst) + strlen(src); 1856 env = xstrdup(env);
1249 if (*curr_len <= new_len) { 1857 if (env == NULL)
1250 *curr_len = new_len + (*curr_len / 2); 1858 return NULL;
1251 *dst = realloc(*dst, *curr_len);
1252 if (!*dst)
1253 err("could not realloc %li bytes", (unsigned long)*curr_len);
1254 }
1255 1859
1256 strcat(*dst, src); 1860 nentry = 0;
1257} 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;
1258 1867
1259static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1868 return envvals;
1260{ 1869}
1261 static char my_app[2]; 1870
1262 my_app[0] = append; 1871static void parseenv() {
1263 my_app[1] = '\0'; 1872 qa_textrels=get_split_env("QA_TEXTRELS");
1264 xstrcat(dst, my_app, curr_len); 1873 qa_execstack=get_split_env("QA_EXECSTACK");
1874 qa_wx_load=get_split_env("QA_WX_LOAD");
1265} 1875}
1266 1876
1267 1877
1268 1878
1269int main(int argc, char *argv[]) 1879int main(int argc, char *argv[])
1270{ 1880{
1271 if (argc < 2) 1881 if (argc < 2)
1272 usage(EXIT_FAILURE); 1882 usage(EXIT_FAILURE);
1883 parseenv();
1273 parseargs(argc, argv); 1884 parseargs(argc, argv);
1274 fclose(stdout); 1885 fclose(stdout);
1275#ifdef __BOUNDS_CHECKING_ON 1886#ifdef __BOUNDS_CHECKING_ON
1276 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()");
1277#endif 1888#endif

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

  ViewVC Help
Powered by ViewVC 1.1.20