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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.168

  ViewVC Help
Powered by ViewVC 1.1.20