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

Legend:
Removed from v.1.96  
changed lines
  Added in v.1.215

  ViewVC Help
Powered by ViewVC 1.1.20