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

  ViewVC Help
Powered by ViewVC 1.1.20