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

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.203

  ViewVC Help
Powered by ViewVC 1.1.20