/[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.215
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.215 2009/12/03 08:01:45 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>
25#include <stdlib.h>
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
36#include "paxelf.h"
37
38static const char *rcsid = "$Id: scanelf.c,v 1.32 2005/04/07 00:01:40 vapier Exp $"; 10static const char *rcsid = "$Id: scanelf.c,v 1.215 2009/12/03 08:01:45 vapier Exp $";
11const char * const argv0 = "scanelf";
39 12
13#include "paxinc.h"
40 14
41/* helper functions for showing errors */ 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
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[]);
61 30
62/* variables to control behavior */ 31/* variables to control behavior */
32static char match_etypes[126] = "";
33static char *ldpaths[256];
63static char scan_ldpath = 0; 34static char scan_ldpath = 0;
64static char scan_envpath = 0; 35static char scan_envpath = 0;
36static char scan_symlink = 1;
37static char scan_archives = 0;
65static char dir_recurse = 0; 38static char dir_recurse = 0;
66static char dir_crossmount = 1; 39static char dir_crossmount = 1;
67static char show_pax = 0; 40static char show_pax = 0;
41static char show_perms = 0;
68static char show_stack = 0; 42static char show_size = 0;
43static char show_phdr = 0;
69static char show_textrel = 0; 44static char show_textrel = 0;
70static char show_rpath = 0; 45static char show_rpath = 0;
71static char show_needed = 0; 46static char show_needed = 0;
47static char show_interp = 0;
48static char show_bind = 0;
49static char show_soname = 0;
50static char show_textrels = 0;
72static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
53static char show_osabi = 0;
54static char show_eabi = 0;
73static char be_quiet = 0; 55static char be_quiet = 0;
74static char be_verbose = 0; 56static char be_verbose = 0;
57static char be_wewy_wewy_quiet = 0;
58static char be_semi_verbose = 0;
75static char *find_sym = NULL; 59static char *find_sym = NULL;
60static char *find_lib = NULL;
61static char *find_section = NULL;
62static char *out_format = NULL;
63static char *search_path = NULL;
64static char fix_elf = 0;
65static char g_match = 0;
66static char use_ldcache = 0;
76 67
68static char **qa_textrels = NULL;
69static char **qa_execstack = NULL;
70static char **qa_wx_load = NULL;
77 71
72static int match_bits = 0;
73static unsigned int match_perms = 0;
74static void *ldcache = NULL;
75static size_t ldcache_size = 0;
76static unsigned long setpax = 0UL;
78 77
79/* scan an elf file and show all the fun stuff */ 78static 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 79
87 found_pax = found_stack = found_relro = found_textrel = \ 80/* find the path to a file by name */
88 found_rpath = found_needed = found_sym = 0; 81static char *which(const char *fname)
82{
83 static char fullpath[__PAX_UTILS_PATH_MAX];
84 char *path, *p;
89 85
90 /* verify this is real ELF */ 86 path = getenv("PATH");
91 if ((elf = readelf(filename)) == NULL) { 87 if (!path)
92 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
93 return; 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;
94 } 97 }
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 } 98 }
125 } 99 free(path);
100 return NULL;
101}
126 102
127 /* stack fun */ 103/* 1 on failure. 0 otherwise */
128 if (show_stack) { 104static int rematch(const char *regex, const char *match, int cflags)
129#define SHOW_STACK(B) \ 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}
127
128/* sub-funcs for scanelf_file() */
129static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
130{
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
140#define GET_SYMTABS(B) \
130 if (elf->elf_class == ELFCLASS ## B) { \ 141 if (elf->elf_class == ELFCLASS ## B) { \
142 if (symtab && dynsym) { \
143 Elf ## B ## _Shdr *esymtab = symtab; \
144 Elf ## B ## _Shdr *edynsym = dynsym; \
145 *sym = (EGET(esymtab->sh_size) > EGET(edynsym->sh_size)) ? symtab : dynsym; \
146 } else \
147 *sym = symtab ? symtab : dynsym; \
148 if (strtab && dynstr) { \
149 Elf ## B ## _Shdr *estrtab = strtab; \
150 Elf ## B ## _Shdr *edynstr = dynstr; \
151 *tab = (EGET(estrtab->sh_size) > EGET(edynstr->sh_size)) ? strtab : dynstr; \
152 } else \
153 *tab = strtab ? strtab : dynstr; \
154 }
155 GET_SYMTABS(32)
156 GET_SYMTABS(64)
157}
158
159static char *scanelf_file_pax(elfobj *elf, char *found_pax)
160{
161 static char ret[7];
162 unsigned long i, shown;
163
164 if (!show_pax) return NULL;
165
166 shown = 0;
167 memset(&ret, 0, sizeof(ret));
168
169 if (elf->phdr) {
170#define SHOW_PAX(B) \
171 if (elf->elf_class == ELFCLASS ## B) { \
131 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 172 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
173 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
174 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
175 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
176 continue; \
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))) \
182 continue; \
183 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
184 *found_pax = 1; \
185 ++shown; \
186 break; \
187 } \
188 }
189 SHOW_PAX(32)
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 }
202 }
203
204 /* fall back to EI_PAX if no PT_PAX was found */
205 if (!*ret) {
206 static char *paxflags;
207 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
208 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
209 *found_pax = 1;
210 return (be_wewy_wewy_quiet ? NULL : paxflags);
211 }
212 strncpy(ret, paxflags, sizeof(ret));
213 }
214
215 if (be_wewy_wewy_quiet || (be_quiet && !shown))
216 return NULL;
217 else
218 return ret;
219}
220
221static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
222{
223 static char ret[12];
224 char *found;
225 unsigned long i, shown, multi_stack, multi_relro, multi_load;
226 int max_pt_load;
227
228 if (!show_phdr) return NULL;
229
230 memcpy(ret, "--- --- ---\0", 12);
231
232 shown = 0;
233 multi_stack = multi_relro = multi_load = 0;
234 max_pt_load = elf_max_pt_load(elf);
235
236#define NOTE_GNU_STACK ".note.GNU-stack"
237#define SHOW_PHDR(B) \
238 if (elf->elf_class == ELFCLASS ## B) { \
239 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
240 Elf ## B ## _Off offset; \
241 uint32_t flags, check_flags; \
242 if (elf->phdr != NULL) { \
132 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 243 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
133 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 244 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
134 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \ 245 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
246 if (multi_stack++) \
247 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
248 if (file_matches_list(elf->filename, qa_execstack)) \
249 continue; \
250 found = found_phdr; \
251 offset = 0; \
252 check_flags = PF_X; \
135 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \ 253 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
136 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 254 if (multi_relro++) \
255 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
256 found = found_relro; \
257 offset = 4; \
258 check_flags = PF_X; \
259 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
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; \
265 found = found_load; \
266 offset = 8; \
267 check_flags = PF_W|PF_X; \
268 } else \
137 continue; \ 269 continue; \
138 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \ 270 flags = EGET(phdr[i].p_flags); \
271 if (be_quiet && ((flags & check_flags) != check_flags)) \
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 } \
278 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
139 found_stack = 1; \ 279 *found = 1; \
140 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \ 280 ++shown; \
141 found_relro = 1; \
142 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \
143 } \ 281 } \
282 } else if (elf->shdr != NULL) { \
283 /* no program headers which means this is prob an object file */ \
284 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
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; \
289 check_flags = SHF_WRITE|SHF_EXECINSTR; \
290 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
291 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
292 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
293 str = elf->data + offset; \
294 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
295 if (!strcmp(str, NOTE_GNU_STACK)) { \
296 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
297 flags = EGET(shdr[i].sh_flags); \
298 if (be_quiet && ((flags & check_flags) != check_flags)) \
299 continue; \
300 ++*found_phdr; \
301 shown = 1; \
302 if (flags & SHF_WRITE) ret[0] = 'W'; \
303 if (flags & SHF_ALLOC) ret[1] = 'A'; \
304 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
305 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
306 break; \
307 } \
308 } \
309 skip_this_shdr##B: \
310 if (!multi_stack) { \
311 if (file_matches_list(elf->filename, qa_execstack)) \
312 return NULL; \
313 *found_phdr = 1; \
314 shown = 1; \
315 memcpy(ret, "!WX", 3); \
316 } \
317 } \
144 } 318 }
145 SHOW_STACK(32) 319 SHOW_PHDR(32)
146 SHOW_STACK(64) 320 SHOW_PHDR(64)
147 if (!be_quiet && !found_stack) printf("--- ");
148 if (!be_quiet && !found_relro) printf("--- ");
149 }
150 321
151 /* textrel fun */ 322 if (be_wewy_wewy_quiet || (be_quiet && !shown))
152 if (show_textrel) { 323 return NULL;
324 else
325 return ret;
326}
327
328/*
329 * See if this ELF contains a DT_TEXTREL tag in any of its
330 * PT_DYNAMIC sections.
331 */
332static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
333{
334 static const char *ret = "TEXTREL";
335 unsigned long i;
336
337 if (!show_textrel && !show_textrels) return NULL;
338
339 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
340
341 if (elf->phdr) {
153#define SHOW_TEXTREL(B) \ 342#define SHOW_TEXTREL(B) \
154 if (elf->elf_class == ELFCLASS ## B) { \ 343 if (elf->elf_class == ELFCLASS ## B) { \
155 Elf ## B ## _Dyn *dyn; \ 344 Elf ## B ## _Dyn *dyn; \
156 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 345 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
157 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 346 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
347 Elf ## B ## _Off offset; \
158 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 348 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
159 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 349 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
350 offset = EGET(phdr[i].p_offset); \
351 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
160 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 352 dyn = DYN ## B (elf->data + offset); \
161 while (EGET(dyn->d_tag) != DT_NULL) { \ 353 while (EGET(dyn->d_tag) != DT_NULL) { \
162 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)*/ \
163 found_textrel = 1; \ 355 *found_textrel = 1; \
164 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 356 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
165 printf("TEXTREL "); \ 357 return (be_wewy_wewy_quiet ? NULL : ret); \
358 } \
359 ++dyn; \
360 } \
361 } }
362 SHOW_TEXTREL(32)
363 SHOW_TEXTREL(64)
364 }
365
366 if (be_quiet || be_wewy_wewy_quiet)
367 return NULL;
368 else
369 return " - ";
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 */
377static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
378{
379 unsigned long s, r, rmax;
380 void *symtab_void, *strtab_void, *text_void;
381
382 if (!show_textrels) return NULL;
383
384 /* don't search for TEXTREL's if the ELF doesn't have any */
385 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
386 if (!*found_textrel) return NULL;
387
388 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
389 text_void = elf_findsecbyname(elf, ".text");
390
391 if (symtab_void && strtab_void && text_void && elf->shdr) {
392#define SHOW_TEXTRELS(B) \
393 if (elf->elf_class == ELFCLASS ## B) { \
394 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
395 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
396 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
397 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
398 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
399 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
400 uint ## B ## _t memsz = EGET(text->sh_size); \
401 Elf ## B ## _Rel *rel; \
402 Elf ## B ## _Rela *rela; \
403 /* search the section headers for relocations */ \
404 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
405 uint32_t sh_type = EGET(shdr[s].sh_type); \
406 if (sh_type == SHT_REL) { \
407 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
408 rela = NULL; \
409 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
410 } else if (sh_type == SHT_RELA) { \
411 rel = NULL; \
412 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
413 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
414 } else \
415 continue; \
416 /* now see if any of the relocs are in the .text */ \
417 for (r = 0; r < rmax; ++r) { \
418 unsigned long sym_max; \
419 Elf ## B ## _Addr offset_tmp; \
420 Elf ## B ## _Sym *func; \
421 Elf ## B ## _Sym *sym; \
422 Elf ## B ## _Addr r_offset; \
423 uint ## B ## _t r_info; \
424 if (sh_type == SHT_REL) { \
425 r_offset = EGET(rel[r].r_offset); \
426 r_info = EGET(rel[r].r_info); \
427 } else { \
428 r_offset = EGET(rela[r].r_offset); \
429 r_info = EGET(rela[r].r_info); \
430 } \
431 /* make sure this relocation is inside of the .text */ \
432 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
433 if (be_verbose <= 2) continue; \
434 } else \
435 *found_textrels = 1; \
436 /* locate this relocation symbol name */ \
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 } \
442 sym_max = ELF ## B ## _R_SYM(r_info); \
443 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
444 sym += sym_max; \
445 else \
446 sym = NULL; \
447 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
448 /* show the raw details about this reloc */ \
449 printf(" %s: ", elf->base_filename); \
450 if (sym && sym->st_name) \
451 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
452 else \
453 printf("(memory/data?)"); \
454 printf(" [0x%lX]", (unsigned long)r_offset); \
455 /* now try to find the closest symbol that this rel is probably in */ \
456 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
457 func = NULL; \
458 offset_tmp = 0; \
459 while (sym_max--) { \
460 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
461 func = sym; \
462 offset_tmp = EGET(sym->st_value); \
166 } \ 463 } \
167 ++dyn; \ 464 ++sym; \
168 } \ 465 } \
466 printf(" in "); \
467 if (func && 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); \
471 else \
472 printf("%s", func_name); \
473 } else \
474 printf("(optimized out)"); \
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 } \
497 } \
169 } } 498 } }
170 SHOW_TEXTREL(32) 499 SHOW_TEXTRELS(32)
171 SHOW_TEXTREL(64) 500 SHOW_TEXTRELS(64)
172 if (!be_quiet && !found_textrel) printf("------- ");
173 } 501 }
502 if (!*found_textrels)
503 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
174 504
175 /* rpath fun */ 505 return NULL;
176 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 506}
177 if (show_rpath) { 507
508static void rpath_security_checks(elfobj *, char *, const char *);
509static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
510{
511 struct stat st;
512 switch (*item) {
513 case '/': break;
514 case '.':
515 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
516 break;
517 case ':':
518 case '\0':
519 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
520 break;
521 case '$':
522 if (fstat(elf->fd, &st) != -1)
523 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
524 warnf("Security problem with %s='%s' in %s with mode set of %o",
525 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
526 break;
527 default:
528 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
529 break;
530 }
531}
532static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
533{
534 unsigned long i, s;
178 char *rpath, *runpath; 535 char *rpath, *runpath, **r;
536 void *strtbl_void;
537
538 if (!show_rpath) return;
539
179 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 540 strtbl_void = elf_findsecbyname(elf, ".dynstr");
180 rpath = runpath = NULL; 541 rpath = runpath = NULL;
181 542
182 if (strtbl_void) { 543 if (elf->phdr && strtbl_void) {
183#define SHOW_RPATH(B) \ 544#define SHOW_RPATH(B) \
184 if (elf->elf_class == ELFCLASS ## B) { \ 545 if (elf->elf_class == ELFCLASS ## B) { \
185 Elf ## B ## _Dyn *dyn; \ 546 Elf ## B ## _Dyn *dyn; \
186 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 547 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
187 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 548 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
188 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 549 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
550 Elf ## B ## _Off offset; \
551 Elf ## B ## _Xword word; \
552 /* Scan all the program headers */ \
189 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 553 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
554 /* Just scan dynamic headers */ \
190 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; \
556 offset = EGET(phdr[i].p_offset); \
557 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
558 /* Just scan dynamic RPATH/RUNPATH headers */ \
191 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 559 dyn = DYN ## B (elf->data + offset); \
192 while (EGET(dyn->d_tag) != DT_NULL) { \ 560 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
193 if (EGET(dyn->d_tag) == DT_RPATH) { \ 561 if (word == DT_RPATH) { \
562 r = &rpath; \
563 } else if (word == DT_RUNPATH) { \
564 r = &runpath; \
565 } else { \
566 ++dyn; \
567 continue; \
568 } \
569 /* Verify the memory is somewhat sane */ \
194 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 570 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
571 if (offset < (Elf ## B ## _Off)elf->len) { \
572 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
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); \
577 /* If quiet, don't output paths in ld.so.conf */ \
578 if (be_quiet) { \
579 size_t len; \
580 char *start, *end; \
581 /* note that we only 'chop' off leading known paths. */ \
582 /* since *r is read-only memory, we can only move the ptr forward. */ \
583 start = *r; \
584 /* scan each path in : delimited list */ \
585 while (start) { \
586 rpath_security_checks(elf, start, get_elfdtype(word)); \
587 end = strchr(start, ':'); \
588 len = (end ? abs(end - start) : strlen(start)); \
589 if (use_ldcache) \
590 for (s = 0; ldpaths[s]; ++s) \
591 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
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)++; \
597 break; \
598 } \
599 if (!*r || !end) \
600 break; \
601 else \
602 start = start + len + 1; \
603 } \
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) \
195 found_rpath = 1; \ 645 *found_rpath = 1; \
196 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \ 646 } \
197 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
198 found_rpath = 1; \
199 } \ 647 } \
200 ++dyn; \ 648 ++dyn; \
201 } \ 649 } \
202 } } 650 } }
203 SHOW_RPATH(32) 651 SHOW_RPATH(32)
204 SHOW_RPATH(64) 652 SHOW_RPATH(64)
205 } 653 }
654
655 if (be_wewy_wewy_quiet) return;
656
206 if (rpath && runpath) { 657 if (rpath && runpath) {
207 if (!strcmp(rpath, runpath)) 658 if (!strcmp(rpath, runpath)) {
208 printf("%-5s ", runpath); 659 xstrcat(ret, runpath, ret_len);
209 else { 660 } else {
210 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath); 661 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
211 printf("{%s,%s} ", rpath, runpath); 662 xchrcat(ret, '{', ret_len);
663 xstrcat(ret, rpath, ret_len);
664 xchrcat(ret, ',', ret_len);
665 xstrcat(ret, runpath, ret_len);
666 xchrcat(ret, '}', ret_len);
212 } 667 }
213 } else if (rpath || runpath) 668 } else if (rpath || runpath)
214 printf("%-5s ", (runpath ? runpath : rpath)); 669 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
215 else if (!be_quiet && !found_rpath) 670 else if (!be_quiet)
216 printf(" - "); 671 xstrcat(ret, " - ", ret_len);
672}
673
674#define LDSO_CACHE_MAGIC "ld.so-"
675#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
676#define LDSO_CACHE_VER "1.7.0"
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
692
693static char *lookup_cache_lib(elfobj *, char *);
694
695#if defined(__GLIBC__) || defined(__UCLIBC__)
696
697static char *lookup_cache_lib(elfobj *elf, char *fname)
698{
699 int fd;
700 char *strs;
701 static char buf[__PAX_UTILS_PATH_MAX] = "";
702 const char cachefile[] = "/etc/ld.so.cache";
703 struct stat st;
704
705 typedef struct {
706 char magic[LDSO_CACHE_MAGIC_LEN];
707 char version[LDSO_CACHE_VER_LEN];
708 int nlibs;
709 } header_t;
710 header_t *header;
711
712 typedef struct {
713 int flags;
714 int sooffset;
715 int liboffset;
716 } libentry_t;
717 libentry_t *libent;
718
719 if (fname == NULL)
720 return NULL;
721
722 if (ldcache == NULL) {
723 if (stat(cachefile, &st))
724 return NULL;
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 */
731 ldcache_size = st.st_size;
732 header = ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
733 close(fd);
734
735 if (ldcache == MAP_FAILED) {
736 ldcache = NULL;
737 return NULL;
217 } 738 }
218 739
219 /* print out all the NEEDED entries */ 740 if (memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
220 if (show_needed) { 741 memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
742 {
743 munmap(ldcache, ldcache_size);
744 ldcache = NULL;
745 return NULL;
746 }
747 } else
748 header = ldcache;
749
750 libent = ldcache + sizeof(header_t);
751 strs = (char *) &libent[header->nlibs];
752
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
763 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
764 continue;
765
766 /* Return first hit because that is how the ldso rolls */
767 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
768 break;
769 }
770
771 return buf;
772}
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
808
809static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
810{
811 unsigned long i;
221 char *needed; 812 char *needed;
813 void *strtbl_void;
814 char *p;
815
816 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
817
222 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 818 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 819
224 if (strtbl_void) { 820 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 821#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 822 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 823 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 824 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 825 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 826 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
827 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 828 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; \ 829 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
830 offset = EGET(phdr[i].p_offset); \
831 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
238 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 832 dyn = DYN ## B (elf->data + offset); \
239 while (EGET(dyn->d_tag) != DT_NULL) { \ 833 while (EGET(dyn->d_tag) != DT_NULL) { \
240 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 834 if (EGET(dyn->d_tag) == DT_NEEDED) { \
241 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 835 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
242 if (found_needed) printf(","); \ 836 if (offset >= (Elf ## B ## _Off)elf->len) { \
243 printf("%s", needed); \ 837 ++dyn; \
838 continue; \
839 } \
840 needed = (char*)(elf->data + offset); \
841 if (op == 0) { \
842 if (!be_wewy_wewy_quiet) { \
843 if (*found_needed) xchrcat(ret, ',', ret_len); \
844 if (use_ldcache) \
845 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
846 needed = p; \
847 xstrcat(ret, needed, ret_len); \
848 } \
244 found_needed = 1; \ 849 *found_needed = 1; \
850 } else { \
851 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
852 *found_lib = 1; \
853 return (be_wewy_wewy_quiet ? NULL : needed); \
854 } \
855 } \
245 } \ 856 } \
246 ++dyn; \ 857 ++dyn; \
247 } \ 858 } \
248 } } 859 } }
249 SHOW_NEEDED(32) 860 SHOW_NEEDED(32)
250 SHOW_NEEDED(64) 861 SHOW_NEEDED(64)
862 if (op == 0 && !*found_needed && be_verbose)
863 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
864 }
865
866 return NULL;
867}
868static char *scanelf_file_interp(elfobj *elf, char *found_interp)
869{
870 void *strtbl_void;
871
872 if (!show_interp) return NULL;
873
874 strtbl_void = elf_findsecbyname(elf, ".interp");
875
876 if (strtbl_void) {
877#define SHOW_INTERP(B) \
878 if (elf->elf_class == ELFCLASS ## B) { \
879 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
880 *found_interp = 1; \
881 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
882 }
883 SHOW_INTERP(32)
884 SHOW_INTERP(64)
885 }
886 return NULL;
887}
888static char *scanelf_file_bind(elfobj *elf, char *found_bind)
889{
890 unsigned long i;
891 struct stat s;
892 char dynamic = 0;
893
894 if (!show_bind) return NULL;
895 if (!elf->phdr) return NULL;
896
897#define SHOW_BIND(B) \
898 if (elf->elf_class == ELFCLASS ## B) { \
899 Elf ## B ## _Dyn *dyn; \
900 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
901 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
902 Elf ## B ## _Off offset; \
903 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
904 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
905 dynamic = 1; \
906 offset = EGET(phdr[i].p_offset); \
907 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
908 dyn = DYN ## B (elf->data + offset); \
909 while (EGET(dyn->d_tag) != DT_NULL) { \
910 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
911 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
912 { \
913 if (be_quiet) return NULL; \
914 *found_bind = 1; \
915 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
916 } \
917 ++dyn; \
918 } \
919 } \
920 }
921 SHOW_BIND(32)
922 SHOW_BIND(64)
923
924 if (be_wewy_wewy_quiet) return NULL;
925
926 /* don't output anything if quiet mode and the ELF is static or not setuid */
927 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
928 return NULL;
929 } else {
930 *found_bind = 1;
931 return (char *) (dynamic ? "LAZY" : "STATIC");
932 }
933}
934static char *scanelf_file_soname(elfobj *elf, char *found_soname)
935{
936 unsigned long i;
937 char *soname;
938 void *strtbl_void;
939
940 if (!show_soname) return NULL;
941
942 strtbl_void = elf_findsecbyname(elf, ".dynstr");
943
944 if (elf->phdr && strtbl_void) {
945#define SHOW_SONAME(B) \
946 if (elf->elf_class == ELFCLASS ## B) { \
947 Elf ## B ## _Dyn *dyn; \
948 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
949 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
950 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
951 Elf ## B ## _Off offset; \
952 /* only look for soname in shared objects */ \
953 if (EGET(ehdr->e_type) != ET_DYN) \
954 return NULL; \
955 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
956 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
957 offset = EGET(phdr[i].p_offset); \
958 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
959 dyn = DYN ## B (elf->data + offset); \
960 while (EGET(dyn->d_tag) != DT_NULL) { \
961 if (EGET(dyn->d_tag) == DT_SONAME) { \
962 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
963 if (offset >= (Elf ## B ## _Off)elf->len) { \
964 ++dyn; \
965 continue; \
966 } \
967 soname = (char*)(elf->data + offset); \
968 *found_soname = 1; \
969 return (be_wewy_wewy_quiet ? NULL : soname); \
970 } \
971 ++dyn; \
972 } \
973 } }
974 SHOW_SONAME(32)
975 SHOW_SONAME(64)
976 }
977
978 return NULL;
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 }
251 } 1064 }
252 if (!be_quiet && !found_needed) 1065
253 printf(" - "); 1066 /* If no types are matched, not match all */
254 else if (found_needed) 1067 if (!inc_notype && !inc_object && !inc_func && !inc_file)
255 printf(" "); 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;
256 } 1081 }
257 1082
258 /* search the symbol table for a specified symbol */ 1083 /* filter symbols */
259 if (find_sym) { 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
1148static char *scanelf_file_sym(elfobj *elf, char *found_sym)
1149{
1150 unsigned long i;
1151 char *ret;
260 void *symtab_void, *strtab_void; 1152 void *symtab_void, *strtab_void;
261 char *versioned_symname;
262 size_t len;
263 1153
264 len = strlen(find_sym) + 1; 1154 if (!find_sym) return NULL;
265 versioned_symname = (char *)malloc(sizeof(char) * (len+1)); 1155 ret = NULL;
266 if (!versioned_symname) {
267 warnf("Could not malloc() mem for sym scan");
268 return;
269 }
270 sprintf(versioned_symname, "%s@", find_sym);
271 1156
272 symtab_void = elf_findsecbyname(elf, ".symtab"); 1157 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
273 strtab_void = elf_findsecbyname(elf, ".strtab");
274 1158
275 if (symtab_void && strtab_void) { 1159 if (symtab_void && strtab_void) {
276#define FIND_SYM(B) \ 1160#define FIND_SYM(B) \
277 if (elf->elf_class == ELFCLASS ## B) { \ 1161 if (elf->elf_class == ELFCLASS ## B) { \
278 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 1162 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
279 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 1163 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
280 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)); \
281 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 1165 unsigned long cnt = EGET(symtab->sh_entsize); \
282 char *symname; \ 1166 char *symname; \
1167 size_t ret_len = 0; \
1168 if (cnt) \
1169 cnt = EGET(symtab->sh_size) / cnt; \
283 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 } \
284 if (sym->st_name) { \ 1175 if (sym->st_name) { \
1176 /* make sure the symbol name is in acceptable memory range */ \
285 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)); \
286 if (*find_sym == '*') { \ 1178 if ((void*)symname > (void*)elf->data_end) { \
287 printf("%s(%s) %5lX %15s %s\n", \ 1179 warnf("%s: corrupt ELF symbols", elf->filename); \
288 ((found_sym == 0) ? "\n\t" : "\t"), \ 1180 ++sym; \
289 (char *)basename(filename), \ 1181 continue; \
290 (long)sym->st_size, \ 1182 } \
291 (char *)get_elfstttype(sym->st_info), \ 1183 scanelf_match_symname(elf, found_sym, \
292 symname); \ 1184 &ret, &ret_len, symname, \
293 found_sym = 1; \ 1185 ELF##B##_ST_TYPE(EGET(sym->st_info)), \
294 } else if ((strcmp(find_sym, symname) == 0) || \ 1186 ELF##B##_ST_BIND(EGET(sym->st_info)), \
295 (strncmp(symname, versioned_symname, len) == 0)) \ 1187 EGET(sym->st_shndx), \
296 found_sym++; \ 1188 /* st_size can be 64bit, but no one is really that big, so screw em */ \
1189 EGET(sym->st_size)); \
297 } \ 1190 } \
298 ++sym; \ 1191 ++sym; \
299 } } 1192 } }
300 FIND_SYM(32) 1193 FIND_SYM(32)
301 FIND_SYM(64) 1194 FIND_SYM(64)
1195 }
1196
1197break_out:
1198 if (be_wewy_wewy_quiet) return NULL;
1199
1200 if (*find_sym != '*' && *found_sym)
1201 return ret;
1202 if (be_quiet)
1203 return NULL;
1204 else
1205 return (char *)" - ";
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
1237/* scan an elf file and show all the fun stuff */
1238#define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
1239static int scanelf_elfobj(elfobj *elf)
1240{
1241 unsigned long i;
1242 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1243 found_rpath, found_needed, found_interp, found_bind, found_soname,
1244 found_sym, found_lib, found_file, found_textrels, found_section;
1245 static char *out_buffer = NULL;
1246 static size_t out_len;
1247
1248 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1249 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1250 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1251
1252 if (be_verbose > 2)
1253 printf("%s: scanning file {%s,%s}\n", elf->filename,
1254 get_elfeitype(EI_CLASS, elf->elf_class),
1255 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1256 else if (be_verbose > 1)
1257 printf("%s: scanning file\n", elf->filename);
1258
1259 /* init output buffer */
1260 if (!out_buffer) {
1261 out_len = sizeof(char) * 80;
1262 out_buffer = xmalloc(out_len);
1263 }
1264 *out_buffer = '\0';
1265
1266 /* show the header */
1267 if (!be_quiet && show_banner) {
1268 for (i = 0; out_format[i]; ++i) {
1269 if (!IS_MODIFIER(out_format[i])) continue;
1270
1271 switch (out_format[++i]) {
1272 case '+': break;
1273 case '%': break;
1274 case '#': break;
1275 case 'F':
1276 case 'p':
1277 case 'f': prints("FILE "); found_file = 1; break;
1278 case 'o': prints(" TYPE "); break;
1279 case 'x': prints(" PAX "); break;
1280 case 'e': prints("STK/REL/PTL "); break;
1281 case 't': prints("TEXTREL "); break;
1282 case 'r': prints("RPATH "); break;
1283 case 'M': prints("CLASS "); break;
1284 case 'n': prints("NEEDED "); break;
1285 case 'i': prints("INTERP "); break;
1286 case 'b': prints("BIND "); break;
1287 case 'Z': prints("SIZE "); break;
1288 case 'S': prints("SONAME "); break;
1289 case 's': prints("SYM "); break;
1290 case 'N': prints("LIB "); 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;
1298 default: warnf("'%c' has no title ?", out_format[i]);
302 } 1299 }
303 free(versioned_symname); 1300 }
304 if (*find_sym != '*') { 1301 if (!found_file) prints("FILE ");
305 if (found_sym) 1302 prints("\n");
306 printf(" %s ", find_sym); 1303 found_file = 0;
307 else if (!be_quiet) 1304 show_banner = 0;
308 printf(" - "); 1305 }
1306
1307 /* dump all the good stuff */
1308 for (i = 0; out_format[i]; ++i) {
1309 const char *out;
1310 const char *tmp;
1311 static char ubuf[sizeof(unsigned long)*2];
1312 if (!IS_MODIFIER(out_format[i])) {
1313 xchrcat(&out_buffer, out_format[i], &out_len);
1314 continue;
1315 }
1316
1317 out = NULL;
1318 be_wewy_wewy_quiet = (out_format[i] == '#');
1319 be_semi_verbose = (out_format[i] == '+');
1320 switch (out_format[++i]) {
1321 case '+':
1322 case '%':
1323 case '#':
1324 xchrcat(&out_buffer, out_format[i], &out_len); break;
1325 case 'F':
1326 found_file = 1;
1327 if (be_wewy_wewy_quiet) break;
1328 xstrcat(&out_buffer, elf->filename, &out_len);
1329 break;
1330 case 'p':
1331 found_file = 1;
1332 if (be_wewy_wewy_quiet) break;
1333 tmp = elf->filename;
1334 if (search_path) {
1335 ssize_t len_search = strlen(search_path);
1336 ssize_t len_file = strlen(elf->filename);
1337 if (!strncmp(elf->filename, search_path, len_search) && \
1338 len_file > len_search)
1339 tmp += len_search;
1340 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
309 } 1341 }
1342 xstrcat(&out_buffer, tmp, &out_len);
1343 break;
1344 case 'f':
1345 found_file = 1;
1346 if (be_wewy_wewy_quiet) break;
1347 tmp = strrchr(elf->filename, '/');
1348 tmp = (tmp == NULL ? elf->filename : tmp+1);
1349 xstrcat(&out_buffer, tmp, &out_len);
1350 break;
1351 case 'o': out = get_elfetype(elf); break;
1352 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1353 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1354 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1355 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); 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;
1360 case 'n':
1361 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1362 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1363 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1364 case 'S': out = scanelf_file_soname(elf, &found_soname); 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;;
1371 default: warnf("'%c' has no scan code?", out_format[i]);
310 } 1372 }
1373 if (out)
1374 xstrcat(&out_buffer, out, &out_len);
1375 }
311 1376
312 if (!be_quiet || found_pax || found_stack || found_textrel || \ 1377#define FOUND_SOMETHING() \
313 found_rpath || found_needed || found_sym) 1378 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
314 printf("%s\n", filename); 1379 found_rpath || found_needed || found_interp || found_bind || \
1380 found_soname || found_sym || found_lib || found_textrels || found_section )
315 1381
1382 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1383 xchrcat(&out_buffer, ' ', &out_len);
1384 xstrcat(&out_buffer, elf->filename, &out_len);
1385 }
1386 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1387 puts(out_buffer);
1388 fflush(stdout);
1389 }
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:
316 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;
317} 1495}
318 1496
319/* 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 */
320static void scanelf_dir(const char *path) 1498static int scanelf_dir(const char *path)
321{ 1499{
322 register DIR *dir; 1500 register DIR *dir;
323 register struct dirent *dentry; 1501 register struct dirent *dentry;
324 struct stat st_top, st; 1502 struct stat st_top, st;
325 char buf[_POSIX_PATH_MAX]; 1503 char buf[__PAX_UTILS_PATH_MAX];
326 size_t pathlen = 0, len = 0; 1504 size_t pathlen = 0, len = 0;
1505 int ret = 0;
327 1506
328 /* make sure path exists */ 1507 /* make sure path exists */
329 if (lstat(path, &st_top) == -1) 1508 if (lstat(path, &st_top) == -1) {
1509 if (be_verbose > 2) printf("%s: does not exist\n", path);
330 return; 1510 return 1;
1511 }
331 1512
332 /* 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 */
333 if (!S_ISDIR(st_top.st_mode)) { 1514 if (!S_ISDIR(st_top.st_mode)) {
334 scanelf_file(path); 1515 return scanelf_file(path, &st_top);
335 return;
336 } 1516 }
337 1517
338 /* now scan the dir looking for fun stuff */ 1518 /* now scan the dir looking for fun stuff */
339 if ((dir = opendir(path)) == NULL) { 1519 if ((dir = opendir(path)) == NULL) {
340 warnf("could not opendir %s: %s", path, strerror(errno)); 1520 warnf("could not opendir %s: %s", path, strerror(errno));
341 return; 1521 return 1;
342 } 1522 }
343 if (be_verbose) printf("%s: scanning dir\n", path); 1523 if (be_verbose > 1) printf("%s: scanning dir\n", path);
344 1524
345 pathlen = strlen(path); 1525 pathlen = strlen(path);
346 while ((dentry = readdir(dir))) { 1526 while ((dentry = readdir(dir))) {
347 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1527 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
348 continue; 1528 continue;
349 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1529 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
350 if (len >= sizeof(buf)) { 1530 if (len >= sizeof(buf)) {
351 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 1531 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1532 (unsigned long)len, (unsigned long)sizeof(buf));
352 continue; 1533 continue;
353 } 1534 }
354 sprintf(buf, "%s/%s", path, dentry->d_name); 1535 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
355 if (lstat(buf, &st) != -1) { 1536 if (lstat(buf, &st) != -1) {
356 if (S_ISREG(st.st_mode)) 1537 if (S_ISREG(st.st_mode))
357 scanelf_file(buf); 1538 ret = scanelf_file(buf, &st);
358 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1539 else if (dir_recurse && S_ISDIR(st.st_mode)) {
359 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1540 if (dir_crossmount || (st_top.st_dev == st.st_dev))
360 scanelf_dir(buf); 1541 ret = scanelf_dir(buf);
361 } 1542 }
362 } 1543 }
363 } 1544 }
364 closedir(dir); 1545 closedir(dir);
1546 return ret;
365} 1547}
1548
1549static int scanelf_from_file(const char *filename)
1550{
1551 FILE *fp = NULL;
1552 char *p;
1553 char path[__PAX_UTILS_PATH_MAX];
1554 int ret = 0;
1555
1556 if (strcmp(filename, "-") == 0)
1557 fp = stdin;
1558 else if ((fp = fopen(filename, "r")) == NULL)
1559 return 1;
1560
1561 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1562 if ((p = strchr(path, '\n')) != NULL)
1563 *p = 0;
1564 search_path = path;
1565 ret = scanelf_dir(path);
1566 }
1567 if (fp != stdin)
1568 fclose(fp);
1569 return ret;
1570}
1571
1572#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1573
1574static int load_ld_cache_config(int i, const char *fname)
1575{
1576 FILE *fp = NULL;
1577 char *p;
1578 char path[__PAX_UTILS_PATH_MAX];
1579
1580 if (i + 1 == ARRAY_SIZE(ldpaths))
1581 return i;
1582
1583 if ((fp = fopen(fname, "r")) == NULL)
1584 return i;
1585
1586 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1587 if ((p = strrchr(path, '\r')) != NULL)
1588 *p = 0;
1589 if ((p = strchr(path, '\n')) != NULL)
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;
1623
1624 ldpaths[i++] = xstrdup(path);
1625
1626 if (i + 1 == ARRAY_SIZE(ldpaths))
1627 break;
1628 }
1629 ldpaths[i] = NULL;
1630
1631 fclose(fp);
1632 return i;
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
366 1688
367/* scan /etc/ld.so.conf for paths */ 1689/* scan /etc/ld.so.conf for paths */
368static void scanelf_ldpath() 1690static void scanelf_ldpath(void)
369{ 1691{
370 char scan_l, scan_ul, scan_ull; 1692 char scan_l, scan_ul, scan_ull;
371 char *path, *p; 1693 int i = 0;
372 FILE *fp;
373 1694
374 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1695 if (!ldpaths[0])
375 err("Unable to open ld.so.conf: %s", strerror(errno)); 1696 err("Unable to load any paths from ld.so.conf");
376 1697
377 scan_l = scan_ul = scan_ull = 0; 1698 scan_l = scan_ul = scan_ull = 0;
378 1699
379 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 1700 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; 1701 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
390 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 1702 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
391 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 1703 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
392 scanelf_dir(path); 1704 scanelf_dir(ldpaths[i]);
1705 ++i;
393 } 1706 }
394 free(path);
395 fclose(fp);
396 1707
397 if (!scan_l) scanelf_dir("/lib"); 1708 if (!scan_l) scanelf_dir("/lib");
398 if (!scan_ul) scanelf_dir("/usr/lib"); 1709 if (!scan_ul) scanelf_dir("/usr/lib");
399 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1710 if (!scan_ull) scanelf_dir("/usr/local/lib");
400} 1711}
401 1712
402/* scan env PATH for paths */ 1713/* scan env PATH for paths */
403static void scanelf_envpath() 1714static void scanelf_envpath(void)
404{ 1715{
405 char *path, *p; 1716 char *path, *p;
406 1717
407 path = getenv("PATH"); 1718 path = getenv("PATH");
408 if (!path) 1719 if (!path)
409 err("PATH is not set in your env !"); 1720 err("PATH is not set in your env !");
410 1721 path = xstrdup(path);
411 if ((path = strdup(path)) == NULL)
412 err("strdup failed: %s", strerror(errno));
413 1722
414 while ((p = strrchr(path, ':')) != NULL) { 1723 while ((p = strrchr(path, ':')) != NULL) {
415 scanelf_dir(p + 1); 1724 scanelf_dir(p + 1);
416 *p = 0; 1725 *p = 0;
417 } 1726 }
418 1727
419 free(path); 1728 free(path);
420} 1729}
421 1730
422 1731/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H J K P Q U W */
423 1732#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 1733#define a_argument required_argument
427static struct option const long_opts[] = { 1734static struct option const long_opts[] = {
428 {"path", no_argument, NULL, 'p'}, 1735 {"path", no_argument, NULL, 'p'},
429 {"ldpath", no_argument, NULL, 'l'}, 1736 {"ldpath", no_argument, NULL, 'l'},
430 {"recursive", no_argument, NULL, 'R'}, 1737 {"recursive", no_argument, NULL, 'R'},
431 {"mount", no_argument, NULL, 'm'}, 1738 {"mount", no_argument, NULL, 'm'},
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'},
432 {"pax", no_argument, NULL, 'x'}, 1744 {"pax", no_argument, NULL, 'x'},
433 {"header", no_argument, NULL, 'e'}, 1745 {"header", no_argument, NULL, 'e'},
434 {"textrel", no_argument, NULL, 't'}, 1746 {"textrel", no_argument, NULL, 't'},
435 {"rpath", no_argument, NULL, 'r'}, 1747 {"rpath", no_argument, NULL, 'r'},
436 {"needed", no_argument, NULL, 'n'}, 1748 {"needed", no_argument, NULL, 'n'},
1749 {"interp", no_argument, NULL, 'i'},
1750 {"bind", no_argument, NULL, 'b'},
1751 {"soname", no_argument, NULL, 'S'},
437 {"symbol", a_argument, NULL, 's'}, 1752 {"symbol", a_argument, NULL, 's'},
1753 {"section", a_argument, NULL, 'k'},
1754 {"lib", a_argument, NULL, 'N'},
1755 {"gmatch", no_argument, NULL, 'g'},
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'},
438 {"all", no_argument, NULL, 'a'}, 1764 {"all", no_argument, NULL, 'a'},
439 {"quiet", no_argument, NULL, 'q'}, 1765 {"quiet", no_argument, NULL, 'q'},
440 {"verbose", no_argument, NULL, 'v'}, 1766 {"verbose", no_argument, NULL, 'v'},
1767 {"format", a_argument, NULL, 'F'},
1768 {"from", a_argument, NULL, 'f'},
441 {"file", a_argument, NULL, 'o'}, 1769 {"file", a_argument, NULL, 'o'},
442 {"nobanner", no_argument, NULL, 'B'}, 1770 {"nobanner", no_argument, NULL, 'B'},
443 {"help", no_argument, NULL, 'h'}, 1771 {"help", no_argument, NULL, 'h'},
444 {"version", no_argument, NULL, 'V'}, 1772 {"version", no_argument, NULL, 'V'},
445 {NULL, no_argument, NULL, 0x0} 1773 {NULL, no_argument, NULL, 0x0}
446}; 1774};
1775
447static char *opts_help[] = { 1776static const char *opts_help[] = {
448 "Scan all directories in PATH environment", 1777 "Scan all directories in PATH environment",
449 "Scan all directories in /etc/ld.so.conf", 1778 "Scan all directories in /etc/ld.so.conf",
450 "Scan directories recursively", 1779 "Scan directories recursively",
451 "Don't recursively cross mount points\n", 1780 "Don't recursively cross mount points",
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",
452 "Print PaX markings", 1786 "Print PaX markings",
453 "Print GNU_STACK markings", 1787 "Print GNU_STACK/PT_LOAD markings",
454 "Print TEXTREL information", 1788 "Print TEXTREL information",
455 "Print RPATH information", 1789 "Print RPATH information",
456 "Print NEEDED information", 1790 "Print NEEDED information",
1791 "Print INTERP information",
1792 "Print BIND information",
1793 "Print SONAME information",
457 "Find a specified symbol", 1794 "Find a specified symbol",
1795 "Find a specified section",
1796 "Find a specified library",
1797 "Use strncmp to match libraries. (use with -N)",
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",
458 "Print all scanned info (-x -e -t -r)\n", 1806 "Print all scanned info (-x -e -t -r -b)\n",
459 "Only output 'bad' things", 1807 "Only output 'bad' things",
460 "Be verbose (can be specified more than once)", 1808 "Be verbose (can be specified more than once)",
1809 "Use specified format for output",
1810 "Read input stream from a filename",
461 "Write output stream to a filename", 1811 "Write output stream to a filename",
462 "Don't display the header", 1812 "Don't display the header",
463 "Print this help and exit", 1813 "Print this help and exit",
464 "Print version and exit", 1814 "Print version and exit",
465 NULL 1815 NULL
466}; 1816};
467 1817
468/* display usage and exit */ 1818/* display usage and exit */
469static void usage(int status) 1819static void usage(int status)
470{ 1820{
471 int i; 1821 unsigned long i;
472 printf(" Scan ELF binaries for stuff\n" 1822 printf("* Scan ELF binaries for stuff\n\n"
473 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); 1823 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
474 printf("Options:\n"); 1824 printf("Options: -[%s]\n", PARSE_FLAGS);
475 for (i = 0; long_opts[i].name; ++i) 1825 for (i = 0; long_opts[i].name; ++i)
476 if (long_opts[i].has_arg == no_argument) 1826 if (long_opts[i].has_arg == no_argument)
477 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1827 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
478 long_opts[i].name, opts_help[i]); 1828 long_opts[i].name, opts_help[i]);
479 else 1829 else
480 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1830 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
481 long_opts[i].name, opts_help[i]); 1831 long_opts[i].name, opts_help[i]);
1832
1833 puts("\nFor more information, see the scanelf(1) manpage");
482 exit(status); 1834 exit(status);
483} 1835}
484 1836
485/* 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 }
486static void parseargs(int argc, char *argv[]) 1846static int parseargs(int argc, char *argv[])
487{ 1847{
488 int flag; 1848 int i;
1849 const char *from_file = NULL;
1850 int ret = 0;
489 1851
490 opterr = 0; 1852 opterr = 0;
491 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1853 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
492 switch (flag) { 1854 switch (i) {
493 1855
494 case 'V': /* version info */ 1856 case 'V':
495 printf("%s compiled %s\n%s\n" 1857 printf("pax-utils-%s: %s compiled %s\n%s\n"
496 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1858 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
497 __FILE__, __DATE__, rcsid, argv0); 1859 VERSION, __FILE__, __DATE__, rcsid, argv0);
498 exit(EXIT_SUCCESS); 1860 exit(EXIT_SUCCESS);
499 break; 1861 break;
500 case 'h': usage(EXIT_SUCCESS); break; 1862 case 'h': usage(EXIT_SUCCESS); break;
501 1863 case 'f':
1864 if (from_file) warn("You prob don't want to specify -f twice");
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;
1882 break;
502 case 'o': { 1883 case 'o': {
503 FILE *fp = NULL;
504 fp = freopen(optarg, "w", stdout); 1884 if (freopen(optarg, "w", stdout) == NULL)
505 if (fp == NULL)
506 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1885 err("Could not open output stream '%s': %s", optarg, strerror(errno));
507 stdout = fp;
508 break; 1886 break;
509 } 1887 }
1888 case 'k':
1889 if (find_section) warn("You prob don't want to specify -k twice");
1890 find_section = optarg;
1891 break;
1892 case 's': {
1893 if (find_sym) warn("You prob don't want to specify -s twice");
1894 find_sym = optarg;
1895 break;
1896 }
1897 case 'N': {
1898 if (find_lib) warn("You prob don't want to specify -N twice");
1899 find_lib = optarg;
1900 break;
1901 }
510 1902
511 case 's': find_sym = strdup(optarg); break; 1903 case 'F': {
1904 if (out_format) warn("You prob don't want to specify -F twice");
1905 out_format = optarg;
1906 break;
1907 }
1908 case 'z': {
1909 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1910 size_t x;
512 1911
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;
1953 case 'L': use_ldcache = 1; break;
1954 case 'y': scan_symlink = 0; break;
1955 case 'A': scan_archives = 1; break;
513 case 'B': show_banner = 0; break; 1956 case 'B': show_banner = 0; break;
514 case 'l': scan_ldpath = 1; break; 1957 case 'l': scan_ldpath = 1; break;
515 case 'p': scan_envpath = 1; break; 1958 case 'p': scan_envpath = 1; break;
516 case 'R': dir_recurse = 1; break; 1959 case 'R': dir_recurse = 1; break;
517 case 'm': dir_crossmount = 0; break; 1960 case 'm': dir_crossmount = 0; break;
1961 case 'X': ++fix_elf; break;
518 case 'x': show_pax = 1; break; 1962 case 'x': show_pax = 1; break;
519 case 'e': show_stack = 1; break; 1963 case 'e': show_phdr = 1; break;
520 case 't': show_textrel = 1; break; 1964 case 't': show_textrel = 1; break;
521 case 'r': show_rpath = 1; break; 1965 case 'r': show_rpath = 1; break;
522 case 'n': show_needed = 1; break; 1966 case 'n': show_needed = 1; break;
1967 case 'i': show_interp = 1; break;
1968 case 'b': show_bind = 1; break;
1969 case 'S': show_soname = 1; break;
1970 case 'T': show_textrels = 1; break;
523 case 'q': be_quiet = 1; break; 1971 case 'q': be_quiet = 1; break;
524 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1972 case 'v': be_verbose = (be_verbose % 20) + 1; break;
525 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 1973 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
526 1974 case 'D': show_endian = 1; break;
1975 case 'I': show_osabi = 1; break;
1976 case 'Y': show_eabi = 1; break;
527 case ':': 1977 case ':':
528 warn("Option missing parameter"); 1978 err("Option '%c' is missing parameter", optopt);
529 usage(EXIT_FAILURE);
530 break;
531 case '?': 1979 case '?':
532 warn("Unknown option"); 1980 err("Unknown option '%c' or argument missing", optopt);
533 usage(EXIT_FAILURE);
534 break;
535 default: 1981 default:
536 err("Unhandled option '%c'", flag); 1982 err("Unhandled option '%c'; please report this", i);
537 break; 1983 }
1984 }
1985 if (show_textrels && be_verbose) {
1986 if (which("objdump") != NULL)
1987 has_objdump = 1;
1988 }
1989 /* let the format option override all other options */
1990 if (out_format) {
1991 show_pax = show_phdr = show_textrel = show_rpath = \
1992 show_needed = show_interp = show_bind = show_soname = \
1993 show_textrels = show_perms = show_endian = show_size = \
1994 show_osabi = show_eabi = 0;
1995 for (i = 0; out_format[i]; ++i) {
1996 if (!IS_MODIFIER(out_format[i])) continue;
1997
1998 switch (out_format[++i]) {
1999 case '+': break;
2000 case '%': break;
2001 case '#': break;
2002 case 'F': break;
2003 case 'p': break;
2004 case 'f': break;
2005 case 'k': break;
2006 case 's': break;
2007 case 'N': 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;
2016 case 'x': show_pax = 1; break;
2017 case 'e': show_phdr = 1; break;
2018 case 't': show_textrel = 1; break;
2019 case 'r': show_rpath = 1; break;
2020 case 'n': show_needed = 1; break;
2021 case 'i': show_interp = 1; break;
2022 case 'b': show_bind = 1; break;
2023 case 'S': show_soname = 1; break;
2024 case 'T': show_textrels = 1; break;
2025 default:
2026 err("Invalid format specifier '%c' (byte %i)",
2027 out_format[i], i+1);
538 } 2028 }
539 } 2029 }
540 2030
541 if (be_quiet && be_verbose) 2031 /* construct our default format */
542 err("You can be quiet or you can be verbose, not both, stupid"); 2032 } else {
2033 size_t fmt_len = 30;
2034 out_format = xmalloc(sizeof(char) * fmt_len);
2035 *out_format = '\0';
2036 if (!be_quiet) xstrcat(&out_format, "%o ", &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);
2043 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
2044 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
2045 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
2046 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
2047 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
2048 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
2049 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
2050 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
2051 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
2052 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
2053 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
2054 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
2055 }
2056 if (be_verbose > 2) printf("Format: %s\n", out_format);
543 2057
2058 /* now lets actually do the scanning */
2059 if (scan_ldpath || use_ldcache)
2060 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
544 if (scan_ldpath) scanelf_ldpath(); 2061 if (scan_ldpath) scanelf_ldpath();
545 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 = "-";
2065 if (from_file) {
2066 scanelf_from_file(from_file);
2067 from_file = *argv;
2068 }
546 if (optind == argc && !scan_ldpath && !scan_envpath) 2069 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
547 err("Nothing to scan !?"); 2070 err("Nothing to scan !?");
548 while (optind < argc) 2071 while (optind < argc) {
549 scanelf_dir(argv[optind++]); 2072 search_path = argv[optind++];
2073 ret = scanelf_dir(search_path);
2074 }
550 2075
551 if (find_sym) free(find_sym); 2076 /* clean up */
552} 2077 for (i = 0; ldpaths[i]; ++i)
2078 free(ldpaths[i]);
553 2079
2080 if (ldcache != 0)
2081 munmap(ldcache, ldcache_size);
2082 return ret;
2083}
554 2084
2085static char **get_split_env(const char *envvar)
2086{
2087 const char *delims = " \t\n";
2088 char **envvals = NULL;
2089 char *env, *s;
2090 int nentry;
2091
2092 if ((env = getenv(envvar)) == NULL)
2093 return NULL;
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
555 2135
556int main(int argc, char *argv[]) 2136int main(int argc, char *argv[])
557{ 2137{
2138 int ret;
558 if (argc < 2) 2139 if (argc < 2)
559 usage(EXIT_FAILURE); 2140 usage(EXIT_FAILURE);
2141 parseenv();
560 parseargs(argc, argv); 2142 ret = parseargs(argc, argv);
561 fclose(stdout); 2143 fclose(stdout);
562 return EXIT_SUCCESS; 2144#ifdef __PAX_UTILS_CLEANUP
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");
2149#endif
2150 return ret;
563} 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.32  
changed lines
  Added in v.1.215

  ViewVC Help
Powered by ViewVC 1.1.20