/[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.80 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.80 2005/06/13 03:09:51 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 ******************************************************************** 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
21 */ 8 */
22 9
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <libgen.h>
27#include <limits.h>
28#define __USE_GNU
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/stat.h>
33#include <dirent.h>
34#include <getopt.h>
35#include <assert.h>
36#include "paxelf.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
37 17
38static const char *rcsid = "$Id: scanelf.c,v 1.80 2005/06/13 03:09:51 vapier Exp $"; 18static const char *rcsid = "$Id: scanelf.c,v 1.146 2006/05/14 21:04:25 vapier Exp $";
39#define argv0 "scanelf" 19#define argv0 "scanelf"
40 20
41#define IS_MODIFIER(c) (c == '%' || c == '#') 21#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
42 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 }
43 31
44 32
45/* 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);
46static void scanelf_file(const char *filename); 38static void scanelf_file(const char *filename);
47static void scanelf_dir(const char *path); 39static void scanelf_dir(const char *path);
48static void scanelf_ldpath(); 40static void scanelf_ldpath(void);
49static void scanelf_envpath(); 41static void scanelf_envpath(void);
50static void usage(int status); 42static void usage(int status);
43static char **get_split_env(const char *envvar);
44static void parseenv(void);
51static void parseargs(int argc, char *argv[]); 45static void parseargs(int argc, char *argv[]);
52static char *xstrdup(const char *s); 46static char *xstrdup(const char *s);
53static void *xmalloc(size_t size); 47static void *xmalloc(size_t size);
48static void *xrealloc(void *ptr, size_t size);
54static 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)
55static 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);
56 52
57/* variables to control behavior */ 53/* variables to control behavior */
54static char match_etypes[126] = "";
58static char *ldpaths[256]; 55static char *ldpaths[256];
59static char scan_ldpath = 0; 56static char scan_ldpath = 0;
60static char scan_envpath = 0; 57static char scan_envpath = 0;
61static char scan_symlink = 1; 58static char scan_symlink = 1;
59static char scan_archives = 0;
62static char dir_recurse = 0; 60static char dir_recurse = 0;
63static char dir_crossmount = 1; 61static char dir_crossmount = 1;
64static char show_pax = 0; 62static char show_pax = 0;
65static char show_phdr = 0; 63static char show_phdr = 0;
66static char show_textrel = 0; 64static char show_textrel = 0;
67static char show_rpath = 0; 65static char show_rpath = 0;
68static char show_needed = 0; 66static char show_needed = 0;
69static char show_interp = 0; 67static char show_interp = 0;
70static char show_bind = 0; 68static char show_bind = 0;
69static char show_soname = 0;
71static char show_textrels = 0; 70static char show_textrels = 0;
72static char show_banner = 1; 71static char show_banner = 1;
73static char be_quiet = 0; 72static char be_quiet = 0;
74static char be_verbose = 0; 73static char be_verbose = 0;
75static char be_wewy_wewy_quiet = 0; 74static char be_wewy_wewy_quiet = 0;
75static char be_semi_verbose = 0;
76static char *find_sym = NULL, *versioned_symname = NULL; 76static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL; 77static char *find_lib = NULL;
78static char *find_section = NULL;
78static char *out_format = NULL; 79static char *out_format = NULL;
79static char *search_path = NULL; 80static char *search_path = NULL;
81static char fix_elf = 0;
82static char gmatch = 0;
83static char use_ldcache = 0;
80 84
85static char **qa_textrels = NULL;
86static char **qa_execstack = NULL;
87static char **qa_wx_load = NULL;
81 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}
82 160
83/* sub-funcs for scanelf_file() */ 161/* sub-funcs for scanelf_file() */
84static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 162static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
85{ 163{
86 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 164 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
105 } \ 183 } \
106 } 184 }
107 GET_SYMTABS(32) 185 GET_SYMTABS(32)
108 GET_SYMTABS(64) 186 GET_SYMTABS(64)
109} 187}
188
110static char *scanelf_file_pax(elfobj *elf, char *found_pax) 189static char *scanelf_file_pax(elfobj *elf, char *found_pax)
111{ 190{
112 static char *paxflags;
113 static char ret[7]; 191 static char ret[7];
114 unsigned long i, shown; 192 unsigned long i, shown;
115
116 193
117 if (!show_pax) return NULL; 194 if (!show_pax) return NULL;
118 195
119 shown = 0; 196 shown = 0;
120 memset(&ret, 0, sizeof(ret)); 197 memset(&ret, 0, sizeof(ret));
125 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 202 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
126 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 203 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
127 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 204 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
128 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 205 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
129 continue; \ 206 continue; \
130 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))) \
131 continue; \ 212 continue; \
132 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); \
133 *found_pax = 1; \ 214 *found_pax = 1; \
134 ++shown; \ 215 ++shown; \
135 break; \ 216 break; \
137 } 218 }
138 SHOW_PAX(32) 219 SHOW_PAX(32)
139 SHOW_PAX(64) 220 SHOW_PAX(64)
140 } 221 }
141 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
142 /* fall back to EI_PAX if no PT_PAX was found */ 235 /* fall back to EI_PAX if no PT_PAX was found */
143 if (!*ret) { 236 if (!*ret) {
237 static char *paxflags;
144 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 238 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
145 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 239 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
146 *found_pax = 1; 240 *found_pax = 1;
147 return paxflags; 241 return (be_wewy_wewy_quiet ? NULL : paxflags);
148 } 242 }
149 strncpy(ret, paxflags, sizeof(ret)); 243 strncpy(ret, paxflags, sizeof(ret));
150 // ++shown;
151 } 244 }
152 245
153 if (be_quiet && !shown) 246 if (be_wewy_wewy_quiet || (be_quiet && !shown))
154 return NULL; 247 return NULL;
248 else
155 return ret; 249 return ret;
156
157} 250}
251
158static 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)
159{ 253{
160 static char ret[12]; 254 static char ret[12];
161 char *found; 255 char *found;
162 unsigned long i, off, shown, check_flags;
163 unsigned char multi_stack, multi_relro, multi_load; 256 unsigned long i, shown, multi_stack, multi_relro, multi_load;
257 int max_pt_load;
164 258
165 if (!show_phdr) return NULL; 259 if (!show_phdr) return NULL;
166 260
167 memcpy(ret, "--- --- ---\0", 12); 261 memcpy(ret, "--- --- ---\0", 12);
168 262
169 shown = 0; 263 shown = 0;
170 multi_stack = multi_relro = multi_load = 0; 264 multi_stack = multi_relro = multi_load = 0;
265 max_pt_load = elf_max_pt_load(elf);
171 266
172 if (elf->phdr) { 267#define NOTE_GNU_STACK ".note.GNU-stack"
173#define SHOW_PHDR(B) \ 268#define SHOW_PHDR(B) \
174 if (elf->elf_class == ELFCLASS ## B) { \ 269 if (elf->elf_class == ELFCLASS ## B) { \
175 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) { \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 274 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 uint32_t flags; \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 275 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
179 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 276 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
180 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)) {\
181 found = found_phdr; \ 279 found = found_phdr; \
182 off = 0; \ 280 offset = 0; \
183 check_flags = PF_X; \ 281 check_flags = PF_X; \
282 } else continue; \
184 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 283 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
185 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); \
186 found = found_relro; \ 285 found = found_relro; \
187 off = 4; \ 286 offset = 4; \
188 check_flags = PF_X; \ 287 check_flags = PF_X; \
189 } 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) \
190 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)) {\
191 found = found_load; \ 292 found = found_load; \
192 off = 8; \ 293 offset = 8; \
193 check_flags = PF_W|PF_X; \ 294 check_flags = PF_W|PF_X; \
295 } else continue; \
194 } else \ 296 } else \
195 continue; \ 297 continue; \
196 flags = EGET(phdr[i].p_flags); \ 298 flags = EGET(phdr[i].p_flags); \
197 if (be_quiet && ((flags & check_flags) != check_flags)) \ 299 if (be_quiet && ((flags & check_flags) != check_flags)) \
198 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 } \
199 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \ 306 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
200 *found = 1; \ 307 *found = 1; \
201 ++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 } \
202 } \ 343 } \
203 } 344 }
204 SHOW_PHDR(32) 345 SHOW_PHDR(32)
205 SHOW_PHDR(64) 346 SHOW_PHDR(64)
206 }
207 347
208 if (be_quiet && !shown) 348 if (be_wewy_wewy_quiet || (be_quiet && !shown))
209 return NULL; 349 return NULL;
210 else 350 else
211 return ret; 351 return ret;
212} 352}
353
213static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 354static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
214{ 355{
215 static char ret[] = "TEXTREL"; 356 static const char *ret = "TEXTREL";
216 unsigned long i; 357 unsigned long i;
217 358
218 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;
219 362
220 if (elf->phdr) { 363 if (elf->phdr) {
221#define SHOW_TEXTREL(B) \ 364#define SHOW_TEXTREL(B) \
222 if (elf->elf_class == ELFCLASS ## B) { \ 365 if (elf->elf_class == ELFCLASS ## B) { \
223 Elf ## B ## _Dyn *dyn; \ 366 Elf ## B ## _Dyn *dyn; \
243 } 386 }
244 387
245 if (be_quiet || be_wewy_wewy_quiet) 388 if (be_quiet || be_wewy_wewy_quiet)
246 return NULL; 389 return NULL;
247 else 390 else
248 return (char *)" - "; 391 return " - ";
249} 392}
250static 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)
251{ 394{
252 unsigned long p, s, r, rmax; 395 unsigned long s, r, rmax;
253 void *symtab_void, *strtab_void; 396 void *symtab_void, *strtab_void, *text_void;
254 397
255 if (!show_textrels) return NULL; 398 if (!show_textrels) return NULL;
256 399
257 /* don't search for TEXTREL's if the ELF doesn't have any */ 400 /* don't search for TEXTREL's if the ELF doesn't have any */
258 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel); 401 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
259 if (!*found_textrel) return NULL; 402 if (!*found_textrel) return NULL;
260 403
261 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 404 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
405 text_void = elf_findsecbyname(elf, ".text");
262 406
263 if (symtab_void && strtab_void && elf->phdr && elf->shdr) { 407 if (symtab_void && strtab_void && text_void && elf->shdr) {
264#define SHOW_TEXTRELS(B) \ 408#define SHOW_TEXTRELS(B) \
265 if (elf->elf_class == ELFCLASS ## B) { \ 409 if (elf->elf_class == ELFCLASS ## B) { \
266 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 410 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
267 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
268 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 411 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
269 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 412 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
270 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 413 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
414 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
415 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
416 uint ## B ## _t memsz = EGET(text->sh_size); \
271 Elf ## B ## _Rel *rel; \ 417 Elf ## B ## _Rel *rel; \
272 Elf ## B ## _Rela *rela; \ 418 Elf ## B ## _Rela *rela; \
273 /* search the section headers for relocations */ \ 419 /* search the section headers for relocations */ \
274 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ 420 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
275 uint32_t sh_type = EGET(shdr[s].sh_type); \ 421 uint32_t sh_type = EGET(shdr[s].sh_type); \
281 rel = NULL; \ 427 rel = NULL; \
282 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ 428 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
283 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ 429 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
284 } else \ 430 } else \
285 continue; \ 431 continue; \
286 /* search the program headers for PT_LOAD headers */ \
287 for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
288 Elf ## B ## _Addr vaddr; \
289 uint ## B ## _t memsz; \
290 if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
291 if (EGET(phdr[p].p_flags) & PF_W) continue; \
292 vaddr = EGET(phdr[p].p_vaddr); \
293 memsz = EGET(phdr[p].p_memsz); \
294 /* now see if any of the relocs are in the PT_LOAD */ \ 432 /* now see if any of the relocs are in the .text */ \
295 for (r = 0; r < rmax; ++r) { \ 433 for (r = 0; r < rmax; ++r) { \
296 unsigned long sym_max; \ 434 unsigned long sym_max; \
297 Elf ## B ## _Addr offset_tmp; \ 435 Elf ## B ## _Addr offset_tmp; \
298 Elf ## B ## _Sym *func; \ 436 Elf ## B ## _Sym *func; \
299 Elf ## B ## _Sym *sym; \ 437 Elf ## B ## _Sym *sym; \
300 Elf ## B ## _Addr r_offset; \ 438 Elf ## B ## _Addr r_offset; \
301 uint ## B ## _t r_info; \ 439 uint ## B ## _t r_info; \
302 if (sh_type == SHT_REL) { \ 440 if (sh_type == SHT_REL) { \
303 r_offset = EGET(rel[r].r_offset); \ 441 r_offset = EGET(rel[r].r_offset); \
304 r_info = EGET(rel[r].r_info); \ 442 r_info = EGET(rel[r].r_info); \
305 } else { \ 443 } else { \
306 r_offset = EGET(rela[r].r_offset); \ 444 r_offset = EGET(rela[r].r_offset); \
307 r_info = EGET(rela[r].r_info); \ 445 r_info = EGET(rela[r].r_info); \
446 } \
447 /* make sure this relocation is inside of the .text */ \
448 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
449 if (be_verbose <= 2) continue; \
450 } else \
451 *found_textrels = 1; \
452 /* locate this relocation symbol name */ \
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 } \
458 sym_max = ELF ## B ## _R_SYM(r_info); \
459 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
460 sym += sym_max; \
461 else \
462 sym = NULL; \
463 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
464 /* show the raw details about this reloc */ \
465 printf(" %s: ", elf->base_filename); \
466 if (sym && sym->st_name) \
467 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
468 else \
469 printf("(memory/fake?)"); \
470 printf(" [0x%lX]", (unsigned long)r_offset); \
471 /* now try to find the closest symbol that this rel is probably in */ \
472 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
473 func = NULL; \
474 offset_tmp = 0; \
475 while (sym_max--) { \
476 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
477 func = sym; \
478 offset_tmp = EGET(sym->st_value); \
308 } \ 479 } \
309 /* make sure this relocation is inside of the .text */ \
310 if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \
311 *found_textrels = 1; \
312 /* locate this relocation symbol name */ \
313 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
314 sym_max = ELF ## B ## _R_SYM(r_info); \
315 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
316 sym += sym_max; \
317 else \
318 sym = NULL; \
319 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
320 /* show the raw details about this reloc */ \
321 printf("\tTEXTREL %s: ", elf->base_filename); \
322 if (sym && sym->st_name) \
323 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
324 else \
325 printf("(NULL: fake?)"); \
326 printf(" [0x%lX]", (unsigned long)r_offset); \
327 /* now try to find the closest symbol that this rel is probably in */ \
328 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
329 func = NULL; \
330 offset_tmp = 0; \
331 while (sym_max--) { \
332 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
333 func = sym; \
334 offset_tmp = EGET(sym->st_value); \
335 } \
336 ++sym; \ 480 ++sym; \
337 } \
338 printf(" in "); \
339 if (func && func->st_name) \
340 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
341 else \
342 printf("(NULL: fake?)"); \
343 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
344 } \ 481 } \
482 printf(" in "); \
483 if (func && func->st_name) \
484 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
485 else \
486 printf("(NULL: fake?)"); \
487 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
345 } \ 488 } \
346 } } 489 } }
347 SHOW_TEXTRELS(32) 490 SHOW_TEXTRELS(32)
348 SHOW_TEXTRELS(64) 491 SHOW_TEXTRELS(64)
349 } 492 }
493 if (!*found_textrels)
494 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
350 495
351 return NULL; 496 return NULL;
497}
498
499static void rpath_security_checks(elfobj *, char *, const char *);
500static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
501{
502 struct stat st;
503 switch (*item) {
504 case '/': break;
505 case '.':
506 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
507 break;
508 case ':':
509 case '\0':
510 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
511 break;
512 case '$':
513 if (fstat(elf->fd, &st) != -1)
514 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
515 warnf("Security problem with %s='%s' in %s with mode set of %o",
516 dt_type, item, elf->filename, st.st_mode & 07777);
517 break;
518 default:
519 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
520 break;
521 }
352} 522}
353static 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)
354{ 524{
355 unsigned long i, s; 525 unsigned long i, s;
356 char *rpath, *runpath, **r; 526 char *rpath, *runpath, **r;
390 /* Verify the memory is somewhat sane */ \ 560 /* Verify the memory is somewhat sane */ \
391 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 561 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
392 if (offset < (Elf ## B ## _Off)elf->len) { \ 562 if (offset < (Elf ## B ## _Off)elf->len) { \
393 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 563 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
394 *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); \
395 /* If quiet, don't output paths in ld.so.conf */ \ 568 /* If quiet, don't output paths in ld.so.conf */ \
396 if (be_quiet) { \ 569 if (be_quiet) { \
397 size_t len; \ 570 size_t len; \
398 char *start, *end; \ 571 char *start, *end; \
399 /* note that we only 'chop' off leading known paths. */ \ 572 /* note that we only 'chop' off leading known paths. */ \
400 /* 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. */ \
401 start = *r; \ 574 start = *r; \
402 /* scan each path in : delimited list */ \ 575 /* scan each path in : delimited list */ \
403 while (start) { \ 576 while (start) { \
577 rpath_security_checks(elf, start, get_elfdtype(word)); \
404 end = strchr(start, ':'); \ 578 end = strchr(start, ':'); \
405 len = (end ? abs(end - start) : strlen(start)); \ 579 len = (end ? abs(end - start) : strlen(start)); \
580 if (use_ldcache) \
406 for (s = 0; ldpaths[s]; ++s) { \ 581 for (s = 0; ldpaths[s]; ++s) \
407 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 582 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
408 *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)++; \
409 break; \ 588 break; \
410 } \ 589 } \
411 } \
412 if (!*r || !ldpaths[s] || !end) \ 590 if (!*r || !end) \
413 start = NULL; \ 591 break; \
414 else \ 592 else \
415 start = start + len + 1; \ 593 start = start + len + 1; \
416 } \ 594 } \
417 } \ 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) \
418 if (*r) *found_rpath = 1; \ 636 *found_rpath = 1; \
637 } \
419 } \ 638 } \
420 ++dyn; \ 639 ++dyn; \
421 } \ 640 } \
422 } } 641 } }
423 SHOW_RPATH(32) 642 SHOW_RPATH(32)
440 } else if (rpath || runpath) 659 } else if (rpath || runpath)
441 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 660 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
442 else if (!be_quiet) 661 else if (!be_quiet)
443 xstrcat(ret, " - ", ret_len); 662 xstrcat(ret, " - ", ret_len);
444} 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
445static 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)
446{ 760{
447 unsigned long i; 761 unsigned long i;
448 char *needed; 762 char *needed;
449 void *strtbl_void; 763 void *strtbl_void;
764 char *p;
450 765
451 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 766 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
452 767
453 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 768 strtbl_void = elf_findsecbyname(elf, ".dynstr");
454 769
474 } \ 789 } \
475 needed = (char*)(elf->data + offset); \ 790 needed = (char*)(elf->data + offset); \
476 if (op == 0) { \ 791 if (op == 0) { \
477 if (!be_wewy_wewy_quiet) { \ 792 if (!be_wewy_wewy_quiet) { \
478 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; \
479 xstrcat(ret, needed, ret_len); \ 797 xstrcat(ret, needed, ret_len); \
480 } \ 798 } \
481 *found_needed = 1; \ 799 *found_needed = 1; \
482 } else { \ 800 } else { \
483 if (strcmp(find_lib, needed)) return NULL; \ 801 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
484 *found_lib = 1; \ 802 *found_lib = 1; \
485 return (be_wewy_wewy_quiet ? NULL : find_lib); \ 803 return (be_wewy_wewy_quiet ? NULL : needed); \
804 } \
486 } \ 805 } \
487 } \ 806 } \
488 ++dyn; \ 807 ++dyn; \
489 } \ 808 } \
490 } } 809 } }
491 SHOW_NEEDED(32) 810 SHOW_NEEDED(32)
492 SHOW_NEEDED(64) 811 SHOW_NEEDED(64)
812 if (op == 0 && !*found_needed && be_verbose)
813 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
493 } 814 }
494 815
495 return NULL; 816 return NULL;
496} 817}
497static char *scanelf_file_interp(elfobj *elf, char *found_interp) 818static char *scanelf_file_interp(elfobj *elf, char *found_interp)
516} 837}
517static char *scanelf_file_bind(elfobj *elf, char *found_bind) 838static char *scanelf_file_bind(elfobj *elf, char *found_bind)
518{ 839{
519 unsigned long i; 840 unsigned long i;
520 struct stat s; 841 struct stat s;
842 char dynamic = 0;
521 843
522 if (!show_bind) return NULL; 844 if (!show_bind) return NULL;
523 if (!elf->phdr) return NULL; 845 if (!elf->phdr) return NULL;
524 846
525#define SHOW_BIND(B) \ 847#define SHOW_BIND(B) \
528 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 850 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
529 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 851 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
530 Elf ## B ## _Off offset; \ 852 Elf ## B ## _Off offset; \
531 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 853 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
532 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 854 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
855 dynamic = 1; \
533 offset = EGET(phdr[i].p_offset); \ 856 offset = EGET(phdr[i].p_offset); \
534 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 857 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
535 dyn = DYN ## B (elf->data + offset); \ 858 dyn = DYN ## B (elf->data + offset); \
536 while (EGET(dyn->d_tag) != DT_NULL) { \ 859 while (EGET(dyn->d_tag) != DT_NULL) { \
537 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 860 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
552 875
553 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)) {
554 return NULL; 877 return NULL;
555 } else { 878 } else {
556 *found_bind = 1; 879 *found_bind = 1;
557 return (char *) "LAZY"; 880 return (char *) (dynamic ? "LAZY" : "STATIC");
558 } 881 }
882}
883static char *scanelf_file_soname(elfobj *elf, char *found_soname)
884{
885 unsigned long i;
886 char *soname;
887 void *strtbl_void;
888
889 if (!show_soname) return NULL;
890
891 strtbl_void = elf_findsecbyname(elf, ".dynstr");
892
893 if (elf->phdr && strtbl_void) {
894#define SHOW_SONAME(B) \
895 if (elf->elf_class == ELFCLASS ## B) { \
896 Elf ## B ## _Dyn *dyn; \
897 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
898 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
899 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
900 Elf ## B ## _Off offset; \
901 /* only look for soname in shared objects */ \
902 if (ehdr->e_type != ET_DYN) \
903 return NULL; \
904 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
905 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
906 offset = EGET(phdr[i].p_offset); \
907 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
908 dyn = DYN ## B (elf->data + offset); \
909 while (EGET(dyn->d_tag) != DT_NULL) { \
910 if (EGET(dyn->d_tag) == DT_SONAME) { \
911 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
912 if (offset >= (Elf ## B ## _Off)elf->len) { \
913 ++dyn; \
914 continue; \
915 } \
916 soname = (char*)(elf->data + offset); \
917 *found_soname = 1; \
918 return (be_wewy_wewy_quiet ? NULL : soname); \
919 } \
920 ++dyn; \
921 } \
922 } }
923 SHOW_SONAME(32)
924 SHOW_SONAME(64)
925 }
926
927 return NULL;
559} 928}
560static char *scanelf_file_sym(elfobj *elf, char *found_sym) 929static char *scanelf_file_sym(elfobj *elf, char *found_sym)
561{ 930{
562 unsigned long i; 931 unsigned long i;
932 char *ret;
563 void *symtab_void, *strtab_void; 933 void *symtab_void, *strtab_void;
564 934
565 if (!find_sym) return NULL; 935 if (!find_sym) return NULL;
936 ret = find_sym;
566 937
567 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 938 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
568 939
569 if (symtab_void && strtab_void) { 940 if (symtab_void && strtab_void) {
570#define FIND_SYM(B) \ 941#define FIND_SYM(B) \
571 if (elf->elf_class == ELFCLASS ## B) { \ 942 if (elf->elf_class == ELFCLASS ## B) { \
572 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 943 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
573 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 944 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
574 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)); \
575 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 946 unsigned long cnt = EGET(symtab->sh_entsize); \
576 char *symname; \ 947 char *symname; \
948 if (cnt) \
949 cnt = EGET(symtab->sh_size) / cnt; \
577 for (i = 0; i < cnt; ++i) { \ 950 for (i = 0; i < cnt; ++i) { \
578 if (sym->st_name) { \ 951 if (sym->st_name) { \
952 /* make sure the symbol name is in acceptable memory range */ \
579 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 */ \
580 if (*find_sym == '*') { \ 960 if (*ret == '*') { \
581 printf("%s(%s) %5lX %15s %s\n", \ 961 printf("%s(%s) %5lX %15s %s\n", \
582 ((*found_sym == 0) ? "\n\t" : "\t"), \ 962 ((*found_sym == 0) ? "\n\t" : "\t"), \
583 elf->base_filename, \ 963 elf->base_filename, \
584 (long)sym->st_size, \ 964 (unsigned long)sym->st_size, \
585 (char *)get_elfstttype(sym->st_info), \ 965 get_elfstttype(sym->st_info), \
586 symname); \ 966 symname); \
587 *found_sym = 1; \ 967 *found_sym = 1; \
588 } else if ((strcmp(find_sym, symname) == 0) || \ 968 } else { \
589 (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; \
590 (*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 } \
591 } \ 1003 } \
592 ++sym; \ 1004 ++sym; \
593 } } 1005 } }
594 FIND_SYM(32) 1006 FIND_SYM(32)
595 FIND_SYM(64) 1007 FIND_SYM(64)
596 } 1008 }
597 1009
1010break_out:
598 if (be_wewy_wewy_quiet) return NULL; 1011 if (be_wewy_wewy_quiet) return NULL;
599 1012
600 if (*find_sym != '*' && *found_sym) 1013 if (*find_sym != '*' && *found_sym)
601 return find_sym; 1014 return ret;
602 if (be_quiet) 1015 if (be_quiet)
603 return NULL; 1016 return NULL;
604 else 1017 else
605 return (char *)" - "; 1018 return (char *)" - ";
606} 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
607/* scan an elf file and show all the fun stuff */ 1051/* scan an elf file and show all the fun stuff */
608#define prints(str) write(fileno(stdout), str, strlen(str)) 1052#define prints(str) write(fileno(stdout), str, strlen(str))
609static void scanelf_file(const char *filename) 1053static int scanelf_elfobj(elfobj *elf)
610{ 1054{
611 unsigned long i; 1055 unsigned long i;
612 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1056 char found_pax, found_phdr, found_relro, found_load, found_textrel,
613 found_rpath, found_needed, found_interp, found_bind, 1057 found_rpath, found_needed, found_interp, found_bind, found_soname,
614 found_sym, found_lib, found_file, found_textrels; 1058 found_sym, found_lib, found_file, found_textrels, found_section;
615 elfobj *elf;
616 struct stat st;
617 static char *out_buffer = NULL; 1059 static char *out_buffer = NULL;
618 static size_t out_len; 1060 static size_t out_len;
619 1061
620 /* make sure 'filename' exists */
621 if (lstat(filename, &st) == -1) {
622 if (be_verbose > 2) printf("%s: does not exist\n", filename);
623 return;
624 }
625 /* always handle regular files and handle symlinked files if no -y */
626 if (S_ISLNK(st.st_mode)) {
627 if (!scan_symlink) return;
628 stat(filename, &st);
629 }
630 if (!S_ISREG(st.st_mode)) {
631 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
632 return;
633 }
634
635 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1062 found_pax = found_phdr = found_relro = found_load = found_textrel = \
636 found_rpath = found_needed = found_interp = found_bind = \ 1063 found_rpath = found_needed = found_interp = found_bind = found_soname = \
637 found_sym = found_lib = found_file = found_textrels = 0; 1064 found_sym = found_lib = found_file = found_textrels = found_section = 0;
638 1065
639 /* verify this is real ELF */
640 if ((elf = readelf(filename)) == NULL) {
641 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
642 return;
643 }
644
645 if (be_verbose > 1) 1066 if (be_verbose > 2)
646 printf("%s: scanning file {%s,%s}\n", filename, 1067 printf("%s: scanning file {%s,%s}\n", elf->filename,
647 get_elfeitype(EI_CLASS, elf->elf_class), 1068 get_elfeitype(EI_CLASS, elf->elf_class),
648 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1069 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
649 else if (be_verbose) 1070 else if (be_verbose > 1)
650 printf("%s: scanning file\n", filename); 1071 printf("%s: scanning file\n", elf->filename);
651 1072
652 /* init output buffer */ 1073 /* init output buffer */
653 if (!out_buffer) { 1074 if (!out_buffer) {
654 out_len = sizeof(char) * 80; 1075 out_len = sizeof(char) * 80;
655 out_buffer = (char*)xmalloc(out_len); 1076 out_buffer = (char*)xmalloc(out_len);
660 if (!be_quiet && show_banner) { 1081 if (!be_quiet && show_banner) {
661 for (i = 0; out_format[i]; ++i) { 1082 for (i = 0; out_format[i]; ++i) {
662 if (!IS_MODIFIER(out_format[i])) continue; 1083 if (!IS_MODIFIER(out_format[i])) continue;
663 1084
664 switch (out_format[++i]) { 1085 switch (out_format[++i]) {
1086 case '+': break;
665 case '%': break; 1087 case '%': break;
666 case '#': break; 1088 case '#': break;
667 case 'F': 1089 case 'F':
668 case 'p': 1090 case 'p':
669 case 'f': prints("FILE "); found_file = 1; break; 1091 case 'f': prints("FILE "); found_file = 1; break;
673 case 't': prints("TEXTREL "); break; 1095 case 't': prints("TEXTREL "); break;
674 case 'r': prints("RPATH "); break; 1096 case 'r': prints("RPATH "); break;
675 case 'n': prints("NEEDED "); break; 1097 case 'n': prints("NEEDED "); break;
676 case 'i': prints("INTERP "); break; 1098 case 'i': prints("INTERP "); break;
677 case 'b': prints("BIND "); break; 1099 case 'b': prints("BIND "); break;
1100 case 'S': prints("SONAME "); break;
678 case 's': prints("SYM "); break; 1101 case 's': prints("SYM "); break;
679 case 'N': prints("LIB "); break; 1102 case 'N': prints("LIB "); break;
680 case 'T': prints("TEXTRELS "); break; 1103 case 'T': prints("TEXTRELS "); break;
1104 case 'k': prints("SECTION "); break;
681 default: warnf("'%c' has no title ?", out_format[i]); 1105 default: warnf("'%c' has no title ?", out_format[i]);
682 } 1106 }
683 } 1107 }
684 if (!found_file) prints("FILE "); 1108 if (!found_file) prints("FILE ");
685 prints("\n"); 1109 prints("\n");
690 /* dump all the good stuff */ 1114 /* dump all the good stuff */
691 for (i = 0; out_format[i]; ++i) { 1115 for (i = 0; out_format[i]; ++i) {
692 const char *out; 1116 const char *out;
693 const char *tmp; 1117 const char *tmp;
694 1118
695 /* make sure we trim leading spaces in quiet mode */
696 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
697 *out_buffer = '\0';
698
699 if (!IS_MODIFIER(out_format[i])) { 1119 if (!IS_MODIFIER(out_format[i])) {
700 xchrcat(&out_buffer, out_format[i], &out_len); 1120 xchrcat(&out_buffer, out_format[i], &out_len);
701 continue; 1121 continue;
702 } 1122 }
703 1123
704 out = NULL; 1124 out = NULL;
705 be_wewy_wewy_quiet = (out_format[i] == '#'); 1125 be_wewy_wewy_quiet = (out_format[i] == '#');
1126 be_semi_verbose = (out_format[i] == '+');
706 switch (out_format[++i]) { 1127 switch (out_format[++i]) {
1128 case '+':
707 case '%': 1129 case '%':
708 case '#': 1130 case '#':
709 xchrcat(&out_buffer, out_format[i], &out_len); break; 1131 xchrcat(&out_buffer, out_format[i], &out_len); break;
710 case 'F': 1132 case 'F':
711 found_file = 1; 1133 found_file = 1;
712 if (be_wewy_wewy_quiet) break; 1134 if (be_wewy_wewy_quiet) break;
713 xstrcat(&out_buffer, filename, &out_len); 1135 xstrcat(&out_buffer, elf->filename, &out_len);
714 break; 1136 break;
715 case 'p': 1137 case 'p':
716 found_file = 1; 1138 found_file = 1;
717 if (be_wewy_wewy_quiet) break; 1139 if (be_wewy_wewy_quiet) break;
718 tmp = filename; 1140 tmp = elf->filename;
719 if (search_path) { 1141 if (search_path) {
720 ssize_t len_search = strlen(search_path); 1142 ssize_t len_search = strlen(search_path);
721 ssize_t len_file = strlen(filename); 1143 ssize_t len_file = strlen(elf->filename);
722 if (!strncmp(filename, search_path, len_search) && \ 1144 if (!strncmp(elf->filename, search_path, len_search) && \
723 len_file > len_search) 1145 len_file > len_search)
724 tmp += len_search; 1146 tmp += len_search;
725 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1147 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
726 } 1148 }
727 xstrcat(&out_buffer, tmp, &out_len); 1149 xstrcat(&out_buffer, tmp, &out_len);
728 break; 1150 break;
729 case 'f': 1151 case 'f':
730 found_file = 1; 1152 found_file = 1;
731 if (be_wewy_wewy_quiet) break; 1153 if (be_wewy_wewy_quiet) break;
732 tmp = strrchr(filename, '/'); 1154 tmp = strrchr(elf->filename, '/');
733 tmp = (tmp == NULL ? filename : tmp+1); 1155 tmp = (tmp == NULL ? elf->filename : tmp+1);
734 xstrcat(&out_buffer, tmp, &out_len); 1156 xstrcat(&out_buffer, tmp, &out_len);
735 break; 1157 break;
736 case 'o': out = get_elfetype(elf); break; 1158 case 'o': out = get_elfetype(elf); break;
737 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1159 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
738 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;
741 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1163 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
742 case 'n': 1164 case 'n':
743 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;
744 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1166 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
745 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1167 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1168 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
746 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;
747 default: warnf("'%c' has no scan code?", out_format[i]); 1171 default: warnf("'%c' has no scan code?", out_format[i]);
748 } 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
749 if (out) xstrcat(&out_buffer, out, &out_len); 1178 xstrcat(&out_buffer, out, &out_len);
1179 }
750 } 1180 }
751 1181
752#define FOUND_SOMETHING() \ 1182#define FOUND_SOMETHING() \
753 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1183 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
754 found_rpath || found_needed || found_interp || found_bind || \ 1184 found_rpath || found_needed || found_interp || found_bind || \
755 found_sym || found_lib || found_textrels) 1185 found_soname || found_sym || found_lib || found_textrels || found_section )
756 1186
757 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1187 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
758 xchrcat(&out_buffer, ' ', &out_len); 1188 xchrcat(&out_buffer, ' ', &out_len);
759 xstrcat(&out_buffer, filename, &out_len); 1189 xstrcat(&out_buffer, elf->filename, &out_len);
760 } 1190 }
761 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1191 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
762 puts(out_buffer); 1192 puts(out_buffer);
763 fflush(stdout); 1193 fflush(stdout);
764 } 1194 }
765 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:
766 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);
767} 1298}
768 1299
769/* 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 */
770static void scanelf_dir(const char *path) 1301static void scanelf_dir(const char *path)
771{ 1302{
772 register DIR *dir; 1303 register DIR *dir;
773 register struct dirent *dentry; 1304 register struct dirent *dentry;
774 struct stat st_top, st; 1305 struct stat st_top, st;
775 char buf[_POSIX_PATH_MAX]; 1306 char buf[__PAX_UTILS_PATH_MAX];
776 size_t pathlen = 0, len = 0; 1307 size_t pathlen = 0, len = 0;
777 1308
778 /* make sure path exists */ 1309 /* make sure path exists */
779 if (lstat(path, &st_top) == -1) { 1310 if (lstat(path, &st_top) == -1) {
780 if (be_verbose > 2) printf("%s: does not exist\n", path); 1311 if (be_verbose > 2) printf("%s: does not exist\n", path);
790 /* now scan the dir looking for fun stuff */ 1321 /* now scan the dir looking for fun stuff */
791 if ((dir = opendir(path)) == NULL) { 1322 if ((dir = opendir(path)) == NULL) {
792 warnf("could not opendir %s: %s", path, strerror(errno)); 1323 warnf("could not opendir %s: %s", path, strerror(errno));
793 return; 1324 return;
794 } 1325 }
795 if (be_verbose) printf("%s: scanning dir\n", path); 1326 if (be_verbose > 1) printf("%s: scanning dir\n", path);
796 1327
797 pathlen = strlen(path); 1328 pathlen = strlen(path);
798 while ((dentry = readdir(dir))) { 1329 while ((dentry = readdir(dir))) {
799 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1330 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
800 continue; 1331 continue;
802 if (len >= sizeof(buf)) { 1333 if (len >= sizeof(buf)) {
803 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1334 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
804 (unsigned long)len, (unsigned long)sizeof(buf)); 1335 (unsigned long)len, (unsigned long)sizeof(buf));
805 continue; 1336 continue;
806 } 1337 }
807 sprintf(buf, "%s/%s", path, dentry->d_name); 1338 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
808 if (lstat(buf, &st) != -1) { 1339 if (lstat(buf, &st) != -1) {
809 if (S_ISREG(st.st_mode)) 1340 if (S_ISREG(st.st_mode))
810 scanelf_file(buf); 1341 scanelf_file(buf);
811 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1342 else if (dir_recurse && S_ISDIR(st.st_mode)) {
812 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1343 if (dir_crossmount || (st_top.st_dev == st.st_dev))
815 } 1346 }
816 } 1347 }
817 closedir(dir); 1348 closedir(dir);
818} 1349}
819 1350
820static int scanelf_from_file(char *filename) 1351static int scanelf_from_file(const char *filename)
821{ 1352{
822 FILE *fp = NULL; 1353 FILE *fp = NULL;
823 char *p; 1354 char *p;
824 char path[_POSIX_PATH_MAX]; 1355 char path[__PAX_UTILS_PATH_MAX];
825 1356
826 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1357 if (strcmp(filename, "-") == 0)
827 fp = stdin; 1358 fp = stdin;
828 else if ((fp = fopen(filename, "r")) == NULL) 1359 else if ((fp = fopen(filename, "r")) == NULL)
829 return 1; 1360 return 1;
830 1361
831 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1362 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
832 if ((p = strchr(path, '\n')) != NULL) 1363 if ((p = strchr(path, '\n')) != NULL)
833 *p = 0; 1364 *p = 0;
834 search_path = path; 1365 search_path = path;
835 scanelf_dir(path); 1366 scanelf_dir(path);
836 } 1367 }
837 if (fp != stdin) 1368 if (fp != stdin)
838 fclose(fp); 1369 fclose(fp);
839 return 0; 1370 return 0;
840} 1371}
841 1372
842static void load_ld_so_conf() 1373#if defined(__GLIBC__) || defined(__UCLIBC__)
1374static int load_ld_so_conf(int i, const char *fname)
843{ 1375{
844 FILE *fp = NULL; 1376 FILE *fp = NULL;
845 char *p; 1377 char *p;
846 char path[_POSIX_PATH_MAX]; 1378 char path[__PAX_UTILS_PATH_MAX];
847 int i = 0;
848 1379
849 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1380 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
850 return; 1381 return i;
851 1382
1383 if ((fp = fopen(fname, "r")) == NULL)
1384 return i;
1385
852 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1386 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
853 if (*path != '/')
854 continue;
855
856 if ((p = strrchr(path, '\r')) != NULL) 1387 if ((p = strrchr(path, '\r')) != NULL)
857 *p = 0; 1388 *p = 0;
858 if ((p = strchr(path, '\n')) != NULL) 1389 if ((p = strchr(path, '\n')) != NULL)
859 *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;
860 1422
861 ldpaths[i++] = xstrdup(path); 1423 ldpaths[i++] = xstrdup(path);
862 1424
863 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1425 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
864 break; 1426 break;
865 } 1427 }
866 ldpaths[i] = NULL; 1428 ldpaths[i] = NULL;
867 1429
868 fclose(fp); 1430 fclose(fp);
1431 return i;
869} 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
870 1477
871/* scan /etc/ld.so.conf for paths */ 1478/* scan /etc/ld.so.conf for paths */
872static void scanelf_ldpath() 1479static void scanelf_ldpath()
873{ 1480{
874 char scan_l, scan_ul, scan_ull; 1481 char scan_l, scan_ul, scan_ull;
908 } 1515 }
909 1516
910 free(path); 1517 free(path);
911} 1518}
912 1519
913
914
915/* usage / invocation handling functions */ 1520/* usage / invocation handling functions */
916#define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV" 1521#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
917#define a_argument required_argument 1522#define a_argument required_argument
918static struct option const long_opts[] = { 1523static struct option const long_opts[] = {
919 {"path", no_argument, NULL, 'p'}, 1524 {"path", no_argument, NULL, 'p'},
920 {"ldpath", no_argument, NULL, 'l'}, 1525 {"ldpath", no_argument, NULL, 'l'},
921 {"recursive", no_argument, NULL, 'R'}, 1526 {"recursive", no_argument, NULL, 'R'},
922 {"mount", no_argument, NULL, 'm'}, 1527 {"mount", no_argument, NULL, 'm'},
923 {"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'},
924 {"pax", no_argument, NULL, 'x'}, 1533 {"pax", no_argument, NULL, 'x'},
925 {"header", no_argument, NULL, 'e'}, 1534 {"header", no_argument, NULL, 'e'},
926 {"textrel", no_argument, NULL, 't'}, 1535 {"textrel", no_argument, NULL, 't'},
927 {"rpath", no_argument, NULL, 'r'}, 1536 {"rpath", no_argument, NULL, 'r'},
928 {"needed", no_argument, NULL, 'n'}, 1537 {"needed", no_argument, NULL, 'n'},
929 {"interp", no_argument, NULL, 'i'}, 1538 {"interp", no_argument, NULL, 'i'},
930 {"bind", no_argument, NULL, 'b'}, 1539 {"bind", no_argument, NULL, 'b'},
1540 {"soname", no_argument, NULL, 'S'},
931 {"symbol", a_argument, NULL, 's'}, 1541 {"symbol", a_argument, NULL, 's'},
1542 {"section", a_argument, NULL, 'k'},
932 {"lib", a_argument, NULL, 'N'}, 1543 {"lib", a_argument, NULL, 'N'},
1544 {"gmatch", no_argument, NULL, 'g'},
933 {"textrels", no_argument, NULL, 'T'}, 1545 {"textrels", no_argument, NULL, 'T'},
1546 {"etype", a_argument, NULL, 'E'},
1547 {"bits", a_argument, NULL, 'M'},
934 {"all", no_argument, NULL, 'a'}, 1548 {"all", no_argument, NULL, 'a'},
935 {"quiet", no_argument, NULL, 'q'}, 1549 {"quiet", no_argument, NULL, 'q'},
936 {"verbose", no_argument, NULL, 'v'}, 1550 {"verbose", no_argument, NULL, 'v'},
937 {"format", a_argument, NULL, 'F'}, 1551 {"format", a_argument, NULL, 'F'},
938 {"from", a_argument, NULL, 'f'}, 1552 {"from", a_argument, NULL, 'f'},
946static const char *opts_help[] = { 1560static const char *opts_help[] = {
947 "Scan all directories in PATH environment", 1561 "Scan all directories in PATH environment",
948 "Scan all directories in /etc/ld.so.conf", 1562 "Scan all directories in /etc/ld.so.conf",
949 "Scan directories recursively", 1563 "Scan directories recursively",
950 "Don't recursively cross mount points", 1564 "Don't recursively cross mount points",
951 "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",
952 "Print PaX markings", 1570 "Print PaX markings",
953 "Print GNU_STACK/PT_LOAD markings", 1571 "Print GNU_STACK/PT_LOAD markings",
954 "Print TEXTREL information", 1572 "Print TEXTREL information",
955 "Print RPATH information", 1573 "Print RPATH information",
956 "Print NEEDED information", 1574 "Print NEEDED information",
957 "Print INTERP information", 1575 "Print INTERP information",
958 "Print BIND information", 1576 "Print BIND information",
1577 "Print SONAME information",
959 "Find a specified symbol", 1578 "Find a specified symbol",
1579 "Find a specified section",
960 "Find a specified library", 1580 "Find a specified library",
1581 "Use strncmp to match libraries. (use with -N)",
961 "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",
962 "Print all scanned info (-x -e -t -r -n -i -b)\n", 1585 "Print all scanned info (-x -e -t -r -b)\n",
963 "Only output 'bad' things", 1586 "Only output 'bad' things",
964 "Be verbose (can be specified more than once)", 1587 "Be verbose (can be specified more than once)",
965 "Use specified format for output", 1588 "Use specified format for output",
966 "Read input stream from a filename", 1589 "Read input stream from a filename",
967 "Write output stream to a filename", 1590 "Write output stream to a filename",
974/* display usage and exit */ 1597/* display usage and exit */
975static void usage(int status) 1598static void usage(int status)
976{ 1599{
977 unsigned long i; 1600 unsigned long i;
978 printf("* Scan ELF binaries for stuff\n\n" 1601 printf("* Scan ELF binaries for stuff\n\n"
979 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1602 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
980 printf("Options: -[%s]\n", PARSE_FLAGS); 1603 printf("Options: -[%s]\n", PARSE_FLAGS);
981 for (i = 0; long_opts[i].name; ++i) 1604 for (i = 0; long_opts[i].name; ++i)
982 if (long_opts[i].has_arg == no_argument) 1605 if (long_opts[i].has_arg == no_argument)
983 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1606 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
984 long_opts[i].name, opts_help[i]); 1607 long_opts[i].name, opts_help[i]);
985 else 1608 else
986 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1609 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
987 long_opts[i].name, opts_help[i]); 1610 long_opts[i].name, opts_help[i]);
988 1611
989 if (status != EXIT_SUCCESS) 1612 if (status != EXIT_SUCCESS)
990 exit(status); 1613 exit(status);
991 1614
992 puts("\nThe format modifiers for the -F option are:"); 1615 puts("\nThe format modifiers for the -F option are:");
993 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1616 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
994 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1617 puts(" t TEXTREL \tr RPATH \tn NEEDED");
995 puts(" i INTERP \tb BIND \ts symbol"); 1618 puts(" i INTERP \tb BIND \ts symbol");
996 puts(" N library \to Type \tT TEXTRELs"); 1619 puts(" N library \to Type \tT TEXTRELs");
1620 puts(" S SONAME \tk section");
997 puts(" p filename (with search path removed)"); 1621 puts(" p filename (with search path removed)");
998 puts(" f base filename"); 1622 puts(" f filename (short name/basename)");
999 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1623 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1624
1625 puts("\nELF Etypes:");
1626 print_etypes(stdout);
1000 1627
1001 exit(status); 1628 exit(status);
1002} 1629}
1003 1630
1004/* parse command line arguments and preform needed actions */ 1631/* parse command line arguments and preform needed actions */
1005static void parseargs(int argc, char *argv[]) 1632static void parseargs(int argc, char *argv[])
1006{ 1633{
1007 int i; 1634 int i;
1008 char *from_file = NULL; 1635 const char *from_file = NULL;
1009 1636
1010 opterr = 0; 1637 opterr = 0;
1011 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) {
1012 switch (i) { 1639 switch (i) {
1013 1640
1017 VERSION, __FILE__, __DATE__, rcsid, argv0); 1644 VERSION, __FILE__, __DATE__, rcsid, argv0);
1018 exit(EXIT_SUCCESS); 1645 exit(EXIT_SUCCESS);
1019 break; 1646 break;
1020 case 'h': usage(EXIT_SUCCESS); break; 1647 case 'h': usage(EXIT_SUCCESS); break;
1021 case 'f': 1648 case 'f':
1022 if (from_file) err("Don't specify -f twice"); 1649 if (from_file) warn("You prob don't want to specify -f twice");
1023 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);
1024 break; 1657 break;
1025 case 'o': { 1658 case 'o': {
1026 FILE *fp = NULL;
1027 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1659 if (freopen(optarg, "w", stdout) == NULL)
1028 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1660 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1029 SET_STDOUT(fp);
1030 break; 1661 break;
1031 } 1662 }
1032 1663 case 'k':
1664 if (find_section) warn("You prob don't want to specify -k twice");
1665 find_section = optarg;
1666 break;
1033 case 's': { 1667 case 's': {
1034 size_t len;
1035 if (find_sym) err("Don't specify -s twice"); 1668 if (find_sym) warn("You prob don't want to specify -s twice");
1036 find_sym = xstrdup(optarg); 1669 find_sym = optarg;
1037 len = strlen(find_sym) + 1;
1038 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1670 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1039 sprintf(versioned_symname, "%s@", find_sym); 1671 sprintf(versioned_symname, "%s@", find_sym);
1040 break; 1672 break;
1041 } 1673 }
1042 case 'N': { 1674 case 'N': {
1043 if (find_lib) err("Don't specify -N twice"); 1675 if (find_lib) warn("You prob don't want to specify -N twice");
1044 find_lib = xstrdup(optarg); 1676 find_lib = optarg;
1045 break; 1677 break;
1046 } 1678 }
1047 1679
1048 case 'F': { 1680 case 'F': {
1049 if (out_format) err("Don't specify -F twice"); 1681 if (out_format) warn("You prob don't want to specify -F twice");
1050 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);
1051 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 }
1052 } 1718 }
1053 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 }
1728 case 'g': gmatch = 1; break;
1729 case 'L': use_ldcache = 1; break;
1054 case 'y': scan_symlink = 0; break; 1730 case 'y': scan_symlink = 0; break;
1731 case 'A': scan_archives = 1; break;
1055 case 'B': show_banner = 0; break; 1732 case 'B': show_banner = 0; break;
1056 case 'l': scan_ldpath = 1; break; 1733 case 'l': scan_ldpath = 1; break;
1057 case 'p': scan_envpath = 1; break; 1734 case 'p': scan_envpath = 1; break;
1058 case 'R': dir_recurse = 1; break; 1735 case 'R': dir_recurse = 1; break;
1059 case 'm': dir_crossmount = 0; break; 1736 case 'm': dir_crossmount = 0; break;
1737 case 'X': ++fix_elf; break;
1060 case 'x': show_pax = 1; break; 1738 case 'x': show_pax = 1; break;
1061 case 'e': show_phdr = 1; break; 1739 case 'e': show_phdr = 1; break;
1062 case 't': show_textrel = 1; break; 1740 case 't': show_textrel = 1; break;
1063 case 'r': show_rpath = 1; break; 1741 case 'r': show_rpath = 1; break;
1064 case 'n': show_needed = 1; break; 1742 case 'n': show_needed = 1; break;
1065 case 'i': show_interp = 1; break; 1743 case 'i': show_interp = 1; break;
1066 case 'b': show_bind = 1; break; 1744 case 'b': show_bind = 1; break;
1745 case 'S': show_soname = 1; break;
1067 case 'T': show_textrels = 1; break; 1746 case 'T': show_textrels = 1; break;
1068 case 'q': be_quiet = 1; break; 1747 case 'q': be_quiet = 1; break;
1069 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1748 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1070 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \ 1749 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1071 show_needed = show_interp = show_bind = 1; break;
1072 1750
1073 case ':': 1751 case ':':
1074 err("Option missing parameter\n"); 1752 err("Option '%c' is missing parameter", optopt);
1075 case '?': 1753 case '?':
1076 err("Unknown option\n"); 1754 err("Unknown option '%c' or argument missing", optopt);
1077 default: 1755 default:
1078 err("Unhandled option '%c'", i); 1756 err("Unhandled option '%c'; please report this", i);
1079 } 1757 }
1080 } 1758 }
1081 1759
1082 /* let the format option override all other options */ 1760 /* let the format option override all other options */
1083 if (out_format) { 1761 if (out_format) {
1084 show_pax = show_phdr = show_textrel = show_rpath = \ 1762 show_pax = show_phdr = show_textrel = show_rpath = \
1085 show_needed = show_interp = show_bind = show_textrels = 0; 1763 show_needed = show_interp = show_bind = show_soname = \
1764 show_textrels = 0;
1086 for (i = 0; out_format[i]; ++i) { 1765 for (i = 0; out_format[i]; ++i) {
1087 if (!IS_MODIFIER(out_format[i])) continue; 1766 if (!IS_MODIFIER(out_format[i])) continue;
1088 1767
1089 switch (out_format[++i]) { 1768 switch (out_format[++i]) {
1769 case '+': break;
1090 case '%': break; 1770 case '%': break;
1091 case '#': break; 1771 case '#': break;
1092 case 'F': break; 1772 case 'F': break;
1093 case 'p': break; 1773 case 'p': break;
1094 case 'f': break; 1774 case 'f': break;
1775 case 'k': break;
1095 case 's': break; 1776 case 's': break;
1096 case 'N': break; 1777 case 'N': break;
1097 case 'o': break; 1778 case 'o': break;
1098 case 'x': show_pax = 1; break; 1779 case 'x': show_pax = 1; break;
1099 case 'e': show_phdr = 1; break; 1780 case 'e': show_phdr = 1; break;
1100 case 't': show_textrel = 1; break; 1781 case 't': show_textrel = 1; break;
1101 case 'r': show_rpath = 1; break; 1782 case 'r': show_rpath = 1; break;
1102 case 'n': show_needed = 1; break; 1783 case 'n': show_needed = 1; break;
1103 case 'i': show_interp = 1; break; 1784 case 'i': show_interp = 1; break;
1104 case 'b': show_bind = 1; break; 1785 case 'b': show_bind = 1; break;
1786 case 'S': show_soname = 1; break;
1105 case 'T': show_textrels = 1; break; 1787 case 'T': show_textrels = 1; break;
1106 default: 1788 default:
1107 err("Invalid format specifier '%c' (byte %i)", 1789 err("Invalid format specifier '%c' (byte %i)",
1108 out_format[i], i+1); 1790 out_format[i], i+1);
1109 } 1791 }
1119 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1801 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1120 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1802 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1121 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1803 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1122 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1804 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1123 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1805 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1806 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1124 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1807 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1125 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);
1126 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1810 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1127 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1811 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1128 } 1812 }
1129 if (be_verbose > 2) printf("Format: %s\n", out_format); 1813 if (be_verbose > 2) printf("Format: %s\n", out_format);
1130 1814
1131 /* now lets actually do the scanning */ 1815 /* now lets actually do the scanning */
1132 if (scan_ldpath || (show_rpath && be_quiet)) 1816 if (scan_ldpath || use_ldcache)
1133 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
1134 if (scan_ldpath) scanelf_ldpath(); 1822 if (scan_ldpath) scanelf_ldpath();
1135 if (scan_envpath) scanelf_envpath(); 1823 if (scan_envpath) scanelf_envpath();
1824 if (!from_file && optind == argc && ttyname(0) == NULL)
1825 from_file = "-";
1136 if (from_file) { 1826 if (from_file) {
1137 scanelf_from_file(from_file); 1827 scanelf_from_file(from_file);
1138 free(from_file);
1139 from_file = *argv; 1828 from_file = *argv;
1140 } 1829 }
1141 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1830 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1142 err("Nothing to scan !?"); 1831 err("Nothing to scan !?");
1143 while (optind < argc) { 1832 while (optind < argc) {
1144 search_path = argv[optind++]; 1833 search_path = argv[optind++];
1145 scanelf_dir(search_path); 1834 scanelf_dir(search_path);
1146 } 1835 }
1147 1836
1148 /* clean up */ 1837 /* clean up */
1149 if (find_sym) { 1838 if (versioned_symname) free(versioned_symname);
1150 free(find_sym);
1151 free(versioned_symname);
1152 }
1153 if (find_lib) free(find_lib);
1154 if (out_format) free(out_format);
1155 for (i = 0; ldpaths[i]; ++i) 1839 for (i = 0; ldpaths[i]; ++i)
1156 free(ldpaths[i]); 1840 free(ldpaths[i]);
1157}
1158 1841
1159 1842 if (ldcache != 0)
1160 1843 munmap(ldcache, ldcache_size);
1161/* utility funcs */
1162static char *xstrdup(const char *s)
1163{
1164 char *ret = strdup(s);
1165 if (!ret) err("Could not strdup(): %s", strerror(errno));
1166 return ret;
1167} 1844}
1168 1845
1169static void *xmalloc(size_t size) 1846static char **get_split_env(const char *envvar) {
1170{ 1847 char **envvals = NULL;
1171 void *ret = malloc(size); 1848 char *saveptr = NULL;
1172 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1849 char *env;
1173 return ret; 1850 char *s;
1174} 1851 int nentry;
1175 1852
1176static void xstrcat(char **dst, const char *src, size_t *curr_len) 1853 if ((env = getenv(envvar)) == NULL)
1177{ 1854 return NULL;
1178 size_t new_len;
1179 1855
1180 new_len = strlen(*dst) + strlen(src); 1856 env = xstrdup(env);
1181 if (*curr_len <= new_len) { 1857 if (env == NULL)
1182 *curr_len = new_len + (*curr_len / 2); 1858 return NULL;
1183 *dst = realloc(*dst, *curr_len);
1184 if (!*dst)
1185 err("could not realloc %li bytes", (unsigned long)*curr_len);
1186 }
1187 1859
1188 strcat(*dst, src); 1860 nentry = 0;
1189} 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;
1190 1867
1191static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1868 return envvals;
1192{ 1869}
1193 static char my_app[2]; 1870
1194 my_app[0] = append; 1871static void parseenv() {
1195 my_app[1] = '\0'; 1872 qa_textrels=get_split_env("QA_TEXTRELS");
1196 xstrcat(dst, my_app, curr_len); 1873 qa_execstack=get_split_env("QA_EXECSTACK");
1874 qa_wx_load=get_split_env("QA_WX_LOAD");
1197} 1875}
1198 1876
1199 1877
1200 1878
1201int main(int argc, char *argv[]) 1879int main(int argc, char *argv[])
1202{ 1880{
1203 if (argc < 2) 1881 if (argc < 2)
1204 usage(EXIT_FAILURE); 1882 usage(EXIT_FAILURE);
1883 parseenv();
1205 parseargs(argc, argv); 1884 parseargs(argc, argv);
1206 fclose(stdout); 1885 fclose(stdout);
1207#ifdef __BOUNDS_CHECKING_ON 1886#ifdef __BOUNDS_CHECKING_ON
1208 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()");
1209#endif 1888#endif

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

  ViewVC Help
Powered by ViewVC 1.1.20