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

  ViewVC Help
Powered by ViewVC 1.1.20