/[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.155
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.155 2006/06/11 00:07:33 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.155 2006/06/11 00:07:33 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, *next_sym; \
930 this_sym = ret; \
931 do { \
932 next_sym = strchr(this_sym, ','); \
933 if (next_sym == NULL) \
934 next_sym = this_sym + strlen(this_sym); \
935 /* do we want a defined symbol ? */ \
936 if (*this_sym == '+') { \
937 if (sym->st_shndx == SHN_UNDEF) \
938 goto skip_this_sym##B; \
939 ++this_sym; \
940 /* do we want an undefined symbol ? */ \
941 } else if (*this_sym == '-') { \
942 if (sym->st_shndx != SHN_UNDEF) \
943 goto skip_this_sym##B; \
944 ++this_sym; \
945 } \
946 /* ok, lets compare the name now */ \
947 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
948 (strncmp(symname, versioned_symname, strlen(versioned_symname)) == 0)) { \
949 if (be_semi_verbose) { \
950 char buf[126]; \
951 snprintf(buf, sizeof(buf), "%lX %s %s", \
952 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
953 ret = buf; \
954 } else \
955 ret = this_sym; \
321 (*found_sym)++; \ 956 (*found_sym)++; \
957 goto break_out; \
958 } \
959 skip_this_sym##B: this_sym = next_sym + 1; \
960 } while (*next_sym != '\0'); \
961 } \
322 } \ 962 } \
323 ++sym; \ 963 ++sym; \
324 } } 964 } }
325 FIND_SYM(32) 965 FIND_SYM(32)
326 FIND_SYM(64) 966 FIND_SYM(64)
327 } 967 }
968
969break_out:
970 if (be_wewy_wewy_quiet) return NULL;
971
328 if (*find_sym != '*' && *found_sym) 972 if (*find_sym != '*' && *found_sym)
329 return find_sym; 973 return ret;
330 if (be_quiet) 974 if (be_quiet)
331 return NULL; 975 return NULL;
332 else 976 else
333 return " - "; 977 return (char *)" - ";
334} 978}
979
980
981static char *scanelf_file_sections(elfobj *elf, char *found_section)
982{
983 if (!find_section)
984 return NULL;
985
986#define FIND_SECTION(B) \
987 if (elf->elf_class == ELFCLASS ## B) { \
988 int invert; \
989 Elf ## B ## _Shdr *section; \
990 invert = (*find_section == '!' ? 1 : 0); \
991 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
992 if ((section == NULL && invert) || (section != NULL && !invert)) \
993 *found_section = 1; \
994 }
995 FIND_SECTION(32)
996 FIND_SECTION(64)
997
998 if (be_wewy_wewy_quiet)
999 return NULL;
1000
1001 if (*found_section)
1002 return find_section;
1003
1004 if (be_quiet)
1005 return NULL;
1006 else
1007 return (char *)" - ";
1008}
1009
335/* scan an elf file and show all the fun stuff */ 1010/* scan an elf file and show all the fun stuff */
336#define prints(str) fputs(str, stdout) 1011#define prints(str) write(fileno(stdout), str, strlen(str))
337static void scanelf_file(const char *filename) 1012static int scanelf_elfobj(elfobj *elf)
338{ 1013{
339 unsigned long i; 1014 unsigned long i;
340 char found_pax, found_stack, found_relro, found_textrel, 1015 char found_pax, found_phdr, found_relro, found_load, found_textrel,
341 found_rpath, found_needed, found_interp, found_sym, 1016 found_rpath, found_needed, found_interp, found_bind, found_soname,
342 found_file; 1017 found_sym, found_lib, found_file, found_textrels, found_section;
343 elfobj *elf;
344 struct stat st;
345 static char *out_buffer = NULL; 1018 static char *out_buffer = NULL;
346 static size_t out_len; 1019 static size_t out_len;
1020
1021 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1022 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1023 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1024
1025 if (be_verbose > 2)
1026 printf("%s: scanning file {%s,%s}\n", elf->filename,
1027 get_elfeitype(EI_CLASS, elf->elf_class),
1028 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1029 else if (be_verbose > 1)
1030 printf("%s: scanning file\n", elf->filename);
1031
1032 /* init output buffer */
1033 if (!out_buffer) {
1034 out_len = sizeof(char) * 80;
1035 out_buffer = (char*)xmalloc(out_len);
1036 }
1037 *out_buffer = '\0';
1038
1039 /* show the header */
1040 if (!be_quiet && show_banner) {
1041 for (i = 0; out_format[i]; ++i) {
1042 if (!IS_MODIFIER(out_format[i])) continue;
1043
1044 switch (out_format[++i]) {
1045 case '+': break;
1046 case '%': break;
1047 case '#': break;
1048 case 'F':
1049 case 'p':
1050 case 'f': prints("FILE "); found_file = 1; break;
1051 case 'o': prints(" TYPE "); break;
1052 case 'x': prints(" PAX "); break;
1053 case 'e': prints("STK/REL/PTL "); break;
1054 case 't': prints("TEXTREL "); break;
1055 case 'r': prints("RPATH "); break;
1056 case 'n': prints("NEEDED "); break;
1057 case 'i': prints("INTERP "); break;
1058 case 'b': prints("BIND "); break;
1059 case 'S': prints("SONAME "); break;
1060 case 's': prints("SYM "); break;
1061 case 'N': prints("LIB "); break;
1062 case 'T': prints("TEXTRELS "); break;
1063 case 'k': prints("SECTION "); break;
1064 default: warnf("'%c' has no title ?", out_format[i]);
1065 }
1066 }
1067 if (!found_file) prints("FILE ");
1068 prints("\n");
1069 found_file = 0;
1070 show_banner = 0;
1071 }
1072
1073 /* dump all the good stuff */
1074 for (i = 0; out_format[i]; ++i) {
1075 const char *out;
1076 const char *tmp;
1077
1078 if (!IS_MODIFIER(out_format[i])) {
1079 xchrcat(&out_buffer, out_format[i], &out_len);
1080 continue;
1081 }
1082
1083 out = NULL;
1084 be_wewy_wewy_quiet = (out_format[i] == '#');
1085 be_semi_verbose = (out_format[i] == '+');
1086 switch (out_format[++i]) {
1087 case '+':
1088 case '%':
1089 case '#':
1090 xchrcat(&out_buffer, out_format[i], &out_len); break;
1091 case 'F':
1092 found_file = 1;
1093 if (be_wewy_wewy_quiet) break;
1094 xstrcat(&out_buffer, elf->filename, &out_len);
1095 break;
1096 case 'p':
1097 found_file = 1;
1098 if (be_wewy_wewy_quiet) break;
1099 tmp = elf->filename;
1100 if (search_path) {
1101 ssize_t len_search = strlen(search_path);
1102 ssize_t len_file = strlen(elf->filename);
1103 if (!strncmp(elf->filename, search_path, len_search) && \
1104 len_file > len_search)
1105 tmp += len_search;
1106 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1107 }
1108 xstrcat(&out_buffer, tmp, &out_len);
1109 break;
1110 case 'f':
1111 found_file = 1;
1112 if (be_wewy_wewy_quiet) break;
1113 tmp = strrchr(elf->filename, '/');
1114 tmp = (tmp == NULL ? elf->filename : tmp+1);
1115 xstrcat(&out_buffer, tmp, &out_len);
1116 break;
1117 case 'o': out = get_elfetype(elf); break;
1118 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1119 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1120 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1121 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1122 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1123 case 'n':
1124 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1125 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1126 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1127 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1128 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1129 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1130 default: warnf("'%c' has no scan code?", out_format[i]);
1131 }
1132 if (out) {
1133 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1134 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1135 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1136 else
1137 xstrcat(&out_buffer, out, &out_len);
1138 }
1139 }
1140
1141#define FOUND_SOMETHING() \
1142 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1143 found_rpath || found_needed || found_interp || found_bind || \
1144 found_soname || found_sym || found_lib || found_textrels || found_section )
1145
1146 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1147 xchrcat(&out_buffer, ' ', &out_len);
1148 xstrcat(&out_buffer, elf->filename, &out_len);
1149 }
1150 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1151 puts(out_buffer);
1152 fflush(stdout);
1153 }
1154
1155 return 0;
1156}
1157
1158/* scan a single elf */
1159static int scanelf_elf(const char *filename, int fd, size_t len)
1160{
1161 int ret = 1;
1162 elfobj *elf;
1163
1164 /* verify this is real ELF */
1165 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1166 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1167 return ret;
1168 }
1169 switch (match_bits) {
1170 case 32:
1171 if (elf->elf_class != ELFCLASS32)
1172 goto label_done;
1173 break;
1174 case 64:
1175 if (elf->elf_class != ELFCLASS64)
1176 goto label_done;
1177 break;
1178 default: break;
1179 }
1180 if (strlen(match_etypes)) {
1181 char sbuf[126];
1182 strncpy(sbuf, match_etypes, sizeof(sbuf));
1183 if (strchr(match_etypes, ',') != NULL) {
1184 char *p;
1185 while((p = strrchr(sbuf, ',')) != NULL) {
1186 *p = 0;
1187 if (etype_lookup(p+1) == get_etype(elf))
1188 goto label_ret;
1189 }
1190 }
1191 if (etype_lookup(sbuf) != get_etype(elf))
1192 goto label_done;
1193 }
1194
1195label_ret:
1196 ret = scanelf_elfobj(elf);
1197
1198label_done:
1199 unreadelf(elf);
1200 return ret;
1201}
1202
1203/* scan an archive of elfs */
1204static int scanelf_archive(const char *filename, int fd, size_t len)
1205{
1206 archive_handle *ar;
1207 archive_member *m;
1208 char *ar_buffer;
1209 elfobj *elf;
1210
1211 ar = ar_open_fd(filename, fd);
1212 if (ar == NULL)
1213 return 1;
1214
1215 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1216 while ((m=ar_next(ar)) != NULL) {
1217 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1218 if (elf) {
1219 scanelf_elfobj(elf);
1220 unreadelf(elf);
1221 }
1222 }
1223 munmap(ar_buffer, len);
1224
1225 return 0;
1226}
1227/* scan a file which may be an elf or an archive or some other magical beast */
1228static void scanelf_file(const char *filename)
1229{
1230 struct stat st;
1231 int fd;
347 1232
348 /* make sure 'filename' exists */ 1233 /* make sure 'filename' exists */
349 if (lstat(filename, &st) == -1) { 1234 if (lstat(filename, &st) == -1) {
350 if (be_verbose > 2) printf("%s: does not exist\n", filename); 1235 if (be_verbose > 2) printf("%s: does not exist\n", filename);
351 return; 1236 return;
352 } 1237 }
1238
353 /* always handle regular files and handle symlinked files if no -y */ 1239 /* 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))) { 1240 if (S_ISLNK(st.st_mode)) {
1241 if (!scan_symlink) return;
1242 stat(filename, &st);
1243 }
1244 if (!S_ISREG(st.st_mode)) {
355 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1245 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
356 return; 1246 return;
357 } 1247 }
358 1248
359 found_pax = found_stack = found_relro = found_textrel = \ 1249 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; 1250 return;
367 }
368 1251
369 if (be_verbose > 1) 1252 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
370 printf("%s: scanning file {%s,%s}\n", filename, 1253 /* if it isn't an ELF, maybe it's an .a archive */
371 get_elfeitype(elf, EI_CLASS, elf->elf_class), 1254 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 1255
376 /* init output buffer */ 1256 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} 1257}
444 1258
445/* scan a directory for ET_EXEC files and print when we find one */ 1259/* scan a directory for ET_EXEC files and print when we find one */
446static void scanelf_dir(const char *path) 1260static void scanelf_dir(const char *path)
447{ 1261{
448 register DIR *dir; 1262 register DIR *dir;
449 register struct dirent *dentry; 1263 register struct dirent *dentry;
450 struct stat st_top, st; 1264 struct stat st_top, st;
451 char buf[_POSIX_PATH_MAX]; 1265 char buf[__PAX_UTILS_PATH_MAX];
452 size_t pathlen = 0, len = 0; 1266 size_t pathlen = 0, len = 0;
453 1267
454 /* make sure path exists */ 1268 /* make sure path exists */
455 if (lstat(path, &st_top) == -1) { 1269 if (lstat(path, &st_top) == -1) {
456 if (be_verbose > 2) printf("%s: does not exist\n", path); 1270 if (be_verbose > 2) printf("%s: does not exist\n", path);
466 /* now scan the dir looking for fun stuff */ 1280 /* now scan the dir looking for fun stuff */
467 if ((dir = opendir(path)) == NULL) { 1281 if ((dir = opendir(path)) == NULL) {
468 warnf("could not opendir %s: %s", path, strerror(errno)); 1282 warnf("could not opendir %s: %s", path, strerror(errno));
469 return; 1283 return;
470 } 1284 }
471 if (be_verbose) printf("%s: scanning dir\n", path); 1285 if (be_verbose > 1) printf("%s: scanning dir\n", path);
472 1286
473 pathlen = strlen(path); 1287 pathlen = strlen(path);
474 while ((dentry = readdir(dir))) { 1288 while ((dentry = readdir(dir))) {
475 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1289 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
476 continue; 1290 continue;
477 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1291 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
478 if (len >= sizeof(buf)) { 1292 if (len >= sizeof(buf)) {
479 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 1293 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1294 (unsigned long)len, (unsigned long)sizeof(buf));
480 continue; 1295 continue;
481 } 1296 }
482 sprintf(buf, "%s/%s", path, dentry->d_name); 1297 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
483 if (lstat(buf, &st) != -1) { 1298 if (lstat(buf, &st) != -1) {
484 if (S_ISREG(st.st_mode)) 1299 if (S_ISREG(st.st_mode))
485 scanelf_file(buf); 1300 scanelf_file(buf);
486 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1301 else if (dir_recurse && S_ISDIR(st.st_mode)) {
487 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1302 if (dir_crossmount || (st_top.st_dev == st.st_dev))
490 } 1305 }
491 } 1306 }
492 closedir(dir); 1307 closedir(dir);
493} 1308}
494 1309
1310static int scanelf_from_file(const char *filename)
1311{
1312 FILE *fp = NULL;
1313 char *p;
1314 char path[__PAX_UTILS_PATH_MAX];
1315
1316 if (strcmp(filename, "-") == 0)
1317 fp = stdin;
1318 else if ((fp = fopen(filename, "r")) == NULL)
1319 return 1;
1320
1321 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1322 if ((p = strchr(path, '\n')) != NULL)
1323 *p = 0;
1324 search_path = path;
1325 scanelf_dir(path);
1326 }
1327 if (fp != stdin)
1328 fclose(fp);
1329 return 0;
1330}
1331
1332#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1333
1334static int load_ld_cache_config(int i, const char *fname)
1335{
1336 FILE *fp = NULL;
1337 char *p;
1338 char path[__PAX_UTILS_PATH_MAX];
1339
1340 if (i + 1 == ARRAY_SIZE(ldpaths))
1341 return i;
1342
1343 if ((fp = fopen(fname, "r")) == NULL)
1344 return i;
1345
1346 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1347 if ((p = strrchr(path, '\r')) != NULL)
1348 *p = 0;
1349 if ((p = strchr(path, '\n')) != NULL)
1350 *p = 0;
1351#ifdef __linux__
1352 // recursive includes of the same file will make this segfault.
1353 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1354 glob64_t gl;
1355 size_t x;
1356 char gpath[__PAX_UTILS_PATH_MAX];
1357
1358 memset(gpath, 0, sizeof(gpath));
1359
1360 if (path[8] != '/')
1361 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1362 else
1363 strncpy(gpath, &path[8], sizeof(gpath));
1364
1365 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1366 for (x = 0; x < gl.gl_pathc; ++x) {
1367 /* try to avoid direct loops */
1368 if (strcmp(gl.gl_pathv[x], fname) == 0)
1369 continue;
1370 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1371 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1372 globfree64(&gl);
1373 return i;
1374 }
1375 }
1376 globfree64 (&gl);
1377 continue;
1378 } else
1379 abort();
1380 }
1381#endif
1382 if (*path != '/')
1383 continue;
1384
1385 ldpaths[i++] = xstrdup(path);
1386
1387 if (i + 1 == ARRAY_SIZE(ldpaths))
1388 break;
1389 }
1390 ldpaths[i] = NULL;
1391
1392 fclose(fp);
1393 return i;
1394}
1395
1396#elif defined(__FreeBSD__) || (__DragonFly__)
1397
1398static int load_ld_cache_config(int i, const char *fname)
1399{
1400 FILE *fp = NULL;
1401 char *b = NULL, *p;
1402 struct elfhints_hdr hdr;
1403
1404 if (i + 1 == ARRAY_SIZE(ldpaths))
1405 return i;
1406
1407 if ((fp = fopen(fname, "r")) == NULL)
1408 return i;
1409
1410 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1411 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1412 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1413 {
1414 fclose(fp);
1415 return i;
1416 }
1417
1418 b = (char*)malloc(hdr.dirlistlen+1);
1419 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1420 fclose(fp);
1421 free(b);
1422 return i;
1423 }
1424
1425 while ((p = strsep(&b, ":"))) {
1426 if (*p == '\0') continue;
1427 ldpaths[i++] = xstrdup(p);
1428
1429 if (i + 1 == ARRAY_SIZE(ldpaths))
1430 break;
1431 }
1432 ldpaths[i] = NULL;
1433
1434 free(b);
1435 fclose(fp);
1436 return i;
1437}
1438
1439#else
1440
1441#warning Cache config support not implemented for your target
1442static int load_ld_cache_config(int i, const char *fname)
1443{
1444 memset(ldpaths, 0x00, sizeof(ldpaths));
1445}
1446
1447#endif
1448
495/* scan /etc/ld.so.conf for paths */ 1449/* scan /etc/ld.so.conf for paths */
496static void scanelf_ldpath() 1450static void scanelf_ldpath()
497{ 1451{
498 char scan_l, scan_ul, scan_ull; 1452 char scan_l, scan_ul, scan_ull;
499 char *path, *p; 1453 int i = 0;
500 FILE *fp;
501 1454
502 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1455 if (!ldpaths[0])
503 err("Unable to open ld.so.conf: %s", strerror(errno)); 1456 err("Unable to load any paths from ld.so.conf");
504 1457
505 scan_l = scan_ul = scan_ull = 0; 1458 scan_l = scan_ul = scan_ull = 0;
506 1459
507 path = (char*)xmalloc(_POSIX_PATH_MAX); 1460 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; 1461 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
515 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 1462 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
516 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 1463 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
517 scanelf_dir(path); 1464 scanelf_dir(ldpaths[i]);
1465 ++i;
518 } 1466 }
519 free(path);
520 fclose(fp);
521 1467
522 if (!scan_l) scanelf_dir("/lib"); 1468 if (!scan_l) scanelf_dir("/lib");
523 if (!scan_ul) scanelf_dir("/usr/lib"); 1469 if (!scan_ul) scanelf_dir("/usr/lib");
524 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1470 if (!scan_ull) scanelf_dir("/usr/local/lib");
525} 1471}
540 } 1486 }
541 1487
542 free(path); 1488 free(path);
543} 1489}
544 1490
545
546
547/* usage / invocation handling functions */ 1491/* usage / invocation handling functions */
548#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 1492#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
549#define a_argument required_argument 1493#define a_argument required_argument
550static struct option const long_opts[] = { 1494static struct option const long_opts[] = {
551 {"path", no_argument, NULL, 'p'}, 1495 {"path", no_argument, NULL, 'p'},
552 {"ldpath", no_argument, NULL, 'l'}, 1496 {"ldpath", no_argument, NULL, 'l'},
553 {"recursive", no_argument, NULL, 'R'}, 1497 {"recursive", no_argument, NULL, 'R'},
554 {"mount", no_argument, NULL, 'm'}, 1498 {"mount", no_argument, NULL, 'm'},
555 {"symlink", no_argument, NULL, 'y'}, 1499 {"symlink", no_argument, NULL, 'y'},
1500 {"archives", no_argument, NULL, 'A'},
1501 {"ldcache", no_argument, NULL, 'L'},
1502 {"fix", no_argument, NULL, 'X'},
1503 {"setpax", a_argument, NULL, 'z'},
556 {"pax", no_argument, NULL, 'x'}, 1504 {"pax", no_argument, NULL, 'x'},
557 {"header", no_argument, NULL, 'e'}, 1505 {"header", no_argument, NULL, 'e'},
558 {"textrel", no_argument, NULL, 't'}, 1506 {"textrel", no_argument, NULL, 't'},
559 {"rpath", no_argument, NULL, 'r'}, 1507 {"rpath", no_argument, NULL, 'r'},
560 {"needed", no_argument, NULL, 'n'}, 1508 {"needed", no_argument, NULL, 'n'},
561 {"interp", no_argument, NULL, 'i'}, 1509 {"interp", no_argument, NULL, 'i'},
1510 {"bind", no_argument, NULL, 'b'},
1511 {"soname", no_argument, NULL, 'S'},
562 {"symbol", a_argument, NULL, 's'}, 1512 {"symbol", a_argument, NULL, 's'},
1513 {"section", a_argument, NULL, 'k'},
1514 {"lib", a_argument, NULL, 'N'},
1515 {"gmatch", no_argument, NULL, 'g'},
1516 {"textrels", no_argument, NULL, 'T'},
1517 {"etype", a_argument, NULL, 'E'},
1518 {"bits", a_argument, NULL, 'M'},
563 {"all", no_argument, NULL, 'a'}, 1519 {"all", no_argument, NULL, 'a'},
564 {"quiet", no_argument, NULL, 'q'}, 1520 {"quiet", no_argument, NULL, 'q'},
565 {"verbose", no_argument, NULL, 'v'}, 1521 {"verbose", no_argument, NULL, 'v'},
566 {"format", a_argument, NULL, 'F'}, 1522 {"format", a_argument, NULL, 'F'},
1523 {"from", a_argument, NULL, 'f'},
567 {"file", a_argument, NULL, 'o'}, 1524 {"file", a_argument, NULL, 'o'},
568 {"nobanner", no_argument, NULL, 'B'}, 1525 {"nobanner", no_argument, NULL, 'B'},
569 {"help", no_argument, NULL, 'h'}, 1526 {"help", no_argument, NULL, 'h'},
570 {"version", no_argument, NULL, 'V'}, 1527 {"version", no_argument, NULL, 'V'},
571 {NULL, no_argument, NULL, 0x0} 1528 {NULL, no_argument, NULL, 0x0}
572}; 1529};
1530
573static char *opts_help[] = { 1531static const char *opts_help[] = {
574 "Scan all directories in PATH environment", 1532 "Scan all directories in PATH environment",
575 "Scan all directories in /etc/ld.so.conf", 1533 "Scan all directories in /etc/ld.so.conf",
576 "Scan directories recursively", 1534 "Scan directories recursively",
577 "Don't recursively cross mount points", 1535 "Don't recursively cross mount points",
578 "Don't scan symlinks\n", 1536 "Don't scan symlinks",
1537 "Scan archives (.a files)",
1538 "Utilize ld.so.cache information (use with -r/-n)",
1539 "Try and 'fix' bad things (use with -r/-e)",
1540 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
579 "Print PaX markings", 1541 "Print PaX markings",
580 "Print GNU_STACK markings", 1542 "Print GNU_STACK/PT_LOAD markings",
581 "Print TEXTREL information", 1543 "Print TEXTREL information",
582 "Print RPATH information", 1544 "Print RPATH information",
583 "Print NEEDED information", 1545 "Print NEEDED information",
584 "Print INTERP information", 1546 "Print INTERP information",
1547 "Print BIND information",
1548 "Print SONAME information",
585 "Find a specified symbol", 1549 "Find a specified symbol",
1550 "Find a specified section",
1551 "Find a specified library",
1552 "Use strncmp to match libraries. (use with -N)",
1553 "Locate cause of TEXTREL",
1554 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1555 "Print only ELF files matching numeric bits",
586 "Print all scanned info (-x -e -t -r)\n", 1556 "Print all scanned info (-x -e -t -r -b)\n",
587 "Only output 'bad' things", 1557 "Only output 'bad' things",
588 "Be verbose (can be specified more than once)", 1558 "Be verbose (can be specified more than once)",
589 "Use specified format for output", 1559 "Use specified format for output",
1560 "Read input stream from a filename",
590 "Write output stream to a filename", 1561 "Write output stream to a filename",
591 "Don't display the header", 1562 "Don't display the header",
592 "Print this help and exit", 1563 "Print this help and exit",
593 "Print version and exit", 1564 "Print version and exit",
594 NULL 1565 NULL
596 1567
597/* display usage and exit */ 1568/* display usage and exit */
598static void usage(int status) 1569static void usage(int status)
599{ 1570{
600 unsigned long i; 1571 unsigned long i;
601 printf(" Scan ELF binaries for stuff\n\n" 1572 printf("* Scan ELF binaries for stuff\n\n"
602 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1573 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
603 printf("Options: -[%s]\n", PARSE_FLAGS); 1574 printf("Options: -[%s]\n", PARSE_FLAGS);
604 for (i = 0; long_opts[i].name; ++i) 1575 for (i = 0; long_opts[i].name; ++i)
605 if (long_opts[i].has_arg == no_argument) 1576 if (long_opts[i].has_arg == no_argument)
606 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1577 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
607 long_opts[i].name, opts_help[i]); 1578 long_opts[i].name, opts_help[i]);
608 else 1579 else
609 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1580 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
610 long_opts[i].name, opts_help[i]); 1581 long_opts[i].name, opts_help[i]);
1582
1583 if (status != EXIT_SUCCESS)
1584 exit(status);
1585
1586 puts("\nThe format modifiers for the -F option are:");
1587 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1588 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1589 puts(" i INTERP \tb BIND \ts symbol");
1590 puts(" N library \to Type \tT TEXTRELs");
1591 puts(" S SONAME \tk section");
1592 puts(" p filename (with search path removed)");
1593 puts(" f filename (short name/basename)");
1594 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1595
1596 puts("\nELF Etypes:");
1597 print_etypes(stdout);
1598
611 exit(status); 1599 exit(status);
612} 1600}
613 1601
614/* parse command line arguments and preform needed actions */ 1602/* parse command line arguments and preform needed actions */
615static void parseargs(int argc, char *argv[]) 1603static void parseargs(int argc, char *argv[])
616{ 1604{
617 int flag; 1605 int i;
1606 const char *from_file = NULL;
618 1607
619 opterr = 0; 1608 opterr = 0;
620 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1609 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
621 switch (flag) { 1610 switch (i) {
622 1611
623 case 'V': 1612 case 'V':
624 printf("%s compiled %s\n%s\n" 1613 printf("pax-utils-%s: %s compiled %s\n%s\n"
625 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1614 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
626 __FILE__, __DATE__, rcsid, argv0); 1615 VERSION, __FILE__, __DATE__, rcsid, argv0);
627 exit(EXIT_SUCCESS); 1616 exit(EXIT_SUCCESS);
628 break; 1617 break;
629 case 'h': usage(EXIT_SUCCESS); break; 1618 case 'h': usage(EXIT_SUCCESS); break;
630 1619 case 'f':
1620 if (from_file) warn("You prob don't want to specify -f twice");
1621 from_file = optarg;
1622 break;
1623 case 'E':
1624 strncpy(match_etypes, optarg, sizeof(match_etypes));
1625 break;
1626 case 'M':
1627 match_bits = atoi(optarg);
1628 break;
631 case 'o': { 1629 case 'o': {
632 FILE *fp = NULL;
633 fp = freopen(optarg, "w", stdout); 1630 if (freopen(optarg, "w", stdout) == NULL)
634 if (fp == NULL)
635 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1631 err("Could not open output stream '%s': %s", optarg, strerror(errno));
636 stdout = fp;
637 break; 1632 break;
638 } 1633 }
639 1634 case 'k':
1635 if (find_section) warn("You prob don't want to specify -k twice");
1636 find_section = optarg;
1637 break;
640 case 's': { 1638 case 's': {
641 size_t len; 1639 if (find_sym) warn("You prob don't want to specify -s twice");
642 find_sym = xstrdup(optarg); 1640 find_sym = optarg;
643 len = strlen(find_sym) + 1;
644 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1641 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
645 sprintf(versioned_symname, "%s@", find_sym); 1642 sprintf(versioned_symname, "%s@", find_sym);
646 break; 1643 break;
647 } 1644 }
1645 case 'N': {
1646 if (find_lib) warn("You prob don't want to specify -N twice");
1647 find_lib = optarg;
1648 break;
1649 }
648 1650
649 case 'F': { 1651 case 'F': {
1652 if (out_format) warn("You prob don't want to specify -F twice");
650 out_format = strdup(optarg); 1653 out_format = optarg;
1654 break;
1655 }
1656 case 'z': {
1657 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1658 size_t x;
1659
1660 for (x = 0 ; x < strlen(optarg); x++) {
1661 switch(optarg[x]) {
1662 case 'p':
1663 case 'P':
1664 do_state(optarg[x], PAGEEXEC);
651 break; 1665 break;
1666 case 's':
1667 case 'S':
1668 do_state(optarg[x], SEGMEXEC);
1669 break;
1670 case 'm':
1671 case 'M':
1672 do_state(optarg[x], MPROTECT);
1673 break;
1674 case 'e':
1675 case 'E':
1676 do_state(optarg[x], EMUTRAMP);
1677 break;
1678 case 'r':
1679 case 'R':
1680 do_state(optarg[x], RANDMMAP);
1681 break;
1682 case 'x':
1683 case 'X':
1684 do_state(optarg[x], RANDEXEC);
1685 break;
1686 default:
1687 break;
1688 }
652 } 1689 }
653 1690 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1691 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1692 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1693 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1694 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1695 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1696 setpax = flags;
1697 break;
1698 }
1699 case 'g': gmatch = 1; break;
1700 case 'L': use_ldcache = 1; break;
654 case 'y': scan_symlink = 0; break; 1701 case 'y': scan_symlink = 0; break;
1702 case 'A': scan_archives = 1; break;
655 case 'B': show_banner = 0; break; 1703 case 'B': show_banner = 0; break;
656 case 'l': scan_ldpath = 1; break; 1704 case 'l': scan_ldpath = 1; break;
657 case 'p': scan_envpath = 1; break; 1705 case 'p': scan_envpath = 1; break;
658 case 'R': dir_recurse = 1; break; 1706 case 'R': dir_recurse = 1; break;
659 case 'm': dir_crossmount = 0; break; 1707 case 'm': dir_crossmount = 0; break;
1708 case 'X': ++fix_elf; break;
660 case 'x': show_pax = 1; break; 1709 case 'x': show_pax = 1; break;
661 case 'e': show_stack = 1; break; 1710 case 'e': show_phdr = 1; break;
662 case 't': show_textrel = 1; break; 1711 case 't': show_textrel = 1; break;
663 case 'r': show_rpath = 1; break; 1712 case 'r': show_rpath = 1; break;
664 case 'n': show_needed = 1; break; 1713 case 'n': show_needed = 1; break;
665 case 'i': show_interp = 1; break; 1714 case 'i': show_interp = 1; break;
1715 case 'b': show_bind = 1; break;
1716 case 'S': show_soname = 1; break;
1717 case 'T': show_textrels = 1; break;
666 case 'q': be_quiet = 1; break; 1718 case 'q': be_quiet = 1; break;
667 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1719 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; 1720 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
669 1721
670 case ':': 1722 case ':':
671 warn("Option missing parameter\n"); 1723 err("Option '%c' is missing parameter", optopt);
672 usage(EXIT_FAILURE);
673 break;
674 case '?': 1724 case '?':
675 warn("Unknown option\n"); 1725 err("Unknown option '%c' or argument missing", optopt);
676 usage(EXIT_FAILURE);
677 break;
678 default: 1726 default:
679 err("Unhandled option '%c'", flag); 1727 err("Unhandled option '%c'; please report this", i);
680 break;
681 }
682 } 1728 }
683 1729 }
684 if (be_quiet && be_verbose)
685 err("You can be quiet or you can be verbose, not both, stupid");
686 1730
687 /* let the format option override all other options */ 1731 /* let the format option override all other options */
688 if (out_format) { 1732 if (out_format) {
689 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 1733 show_pax = show_phdr = show_textrel = show_rpath = \
1734 show_needed = show_interp = show_bind = show_soname = \
1735 show_textrels = 0;
690 for (flag=0; out_format[flag]; ++flag) { 1736 for (i = 0; out_format[i]; ++i) {
691 if (out_format[flag] != '%') continue; 1737 if (!IS_MODIFIER(out_format[i])) continue;
692 1738
693 switch (out_format[++flag]) { 1739 switch (out_format[++i]) {
1740 case '+': break;
694 case '%': break; 1741 case '%': break;
1742 case '#': break;
695 case 'F': break; 1743 case 'F': break;
1744 case 'p': break;
1745 case 'f': break;
1746 case 'k': break;
696 case 's': break; 1747 case 's': break;
1748 case 'N': break;
697 case 'o': break; 1749 case 'o': break;
698 case 'x': show_pax = 1; break; 1750 case 'x': show_pax = 1; break;
699 case 'e': show_stack = 1; break; 1751 case 'e': show_phdr = 1; break;
700 case 't': show_textrel = 1; break; 1752 case 't': show_textrel = 1; break;
701 case 'r': show_rpath = 1; break; 1753 case 'r': show_rpath = 1; break;
702 case 'n': show_needed = 1; break; 1754 case 'n': show_needed = 1; break;
703 case 'i': show_interp = 1; break; 1755 case 'i': show_interp = 1; break;
1756 case 'b': show_bind = 1; break;
1757 case 'S': show_soname = 1; break;
1758 case 'T': show_textrels = 1; break;
704 default: 1759 default:
705 err("Invalid format specifier '%c' (byte %i)", 1760 err("Invalid format specifier '%c' (byte %i)",
706 out_format[flag], flag+1); 1761 out_format[i], i+1);
707 } 1762 }
708 } 1763 }
709 1764
710 /* construct our default format */ 1765 /* construct our default format */
711 } else { 1766 } else {
712 size_t fmt_len = 30; 1767 size_t fmt_len = 30;
713 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1768 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
714 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1769 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
715 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1770 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
716 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1771 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
717 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1772 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
718 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1773 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
719 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1774 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
720 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1775 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1776 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1777 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1778 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
721 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1779 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1780 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1781 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
722 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1782 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
723 } 1783 }
724 if (be_verbose > 2) printf("Format: %s\n", out_format); 1784 if (be_verbose > 2) printf("Format: %s\n", out_format);
725 1785
726 /* now lets actually do the scanning */ 1786 /* now lets actually do the scanning */
1787 if (scan_ldpath || use_ldcache)
1788 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
727 if (scan_ldpath) scanelf_ldpath(); 1789 if (scan_ldpath) scanelf_ldpath();
728 if (scan_envpath) scanelf_envpath(); 1790 if (scan_envpath) scanelf_envpath();
1791 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1792 from_file = "-";
1793 if (from_file) {
1794 scanelf_from_file(from_file);
1795 from_file = *argv;
1796 }
729 if (optind == argc && !scan_ldpath && !scan_envpath) 1797 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
730 err("Nothing to scan !?"); 1798 err("Nothing to scan !?");
731 while (optind < argc) 1799 while (optind < argc) {
732 scanelf_dir(argv[optind++]); 1800 search_path = argv[optind++];
1801 scanelf_dir(search_path);
1802 }
733 1803
734 /* clean up */ 1804 /* clean up */
735 if (find_sym) {
736 free(find_sym);
737 free(versioned_symname); 1805 free(versioned_symname);
1806 for (i = 0; ldpaths[i]; ++i)
1807 free(ldpaths[i]);
1808
1809 if (ldcache != 0)
1810 munmap(ldcache, ldcache_size);
1811}
1812
1813static char **get_split_env(const char *envvar)
1814{
1815 const char *delims = " \t\n";
1816 char **envvals = NULL;
1817 char *env, *s;
1818 int nentry;
1819
1820 if ((env = getenv(envvar)) == NULL)
1821 return NULL;
1822
1823 env = xstrdup(env);
1824 if (env == NULL)
1825 return NULL;
1826
1827 s = strtok(env, delims);
1828 if (s == NULL) {
1829 free(env);
1830 return NULL;
738 } 1831 }
739 if (out_format) free(out_format); 1832
1833 nentry = 0;
1834 while (s != NULL) {
1835 ++nentry;
1836 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1837 envvals[nentry-1] = s;
1838 s = strtok(NULL, delims);
1839 }
1840 envvals[nentry] = NULL;
1841
1842 /* don't want to free(env) as it contains the memory that backs
1843 * the envvals array of strings */
1844 return envvals;
1845}
1846static void parseenv()
1847{
1848 qa_textrels = get_split_env("QA_TEXTRELS");
1849 qa_execstack = get_split_env("QA_EXECSTACK");
1850 qa_wx_load = get_split_env("QA_WX_LOAD");
1851}
1852#ifdef __PAX_UTILS_CLEANUP
1853static void cleanup()
1854{
1855 free(out_format);
1856 free(qa_textrels);
1857 free(qa_execstack);
1858 free(qa_wx_load);
1859}
1860#endif
1861
1862
1863
1864int main(int argc, char *argv[])
1865{
1866 if (argc < 2)
1867 usage(EXIT_FAILURE);
1868 parseenv();
1869 parseargs(argc, argv);
1870 fclose(stdout);
1871#ifdef __PAX_UTILS_CLEANUP
1872 cleanup();
1873 warn("The calls to add/delete heap should be off:\n"
1874 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1875 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1876#endif
1877 return EXIT_SUCCESS;
740} 1878}
741 1879
742 1880
743 1881
744/* utility funcs */ 1882/* utility funcs */
745static char *xstrdup(char *s) 1883static char *xstrdup(const char *s)
746{ 1884{
747 char *ret = strdup(s); 1885 char *ret = strdup(s);
748 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1886 if (!ret) err("Could not strdup(): %s", strerror(errno));
749 return ret; 1887 return ret;
750} 1888}
752{ 1890{
753 void *ret = malloc(size); 1891 void *ret = malloc(size);
754 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1892 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
755 return ret; 1893 return ret;
756} 1894}
1895static void *xrealloc(void *ptr, size_t size)
1896{
1897 void *ret = realloc(ptr, size);
1898 if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
1899 return ret;
1900}
757static void xstrcat(char **dst, const char *src, size_t *curr_len) 1901static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
758{ 1902{
759 long new_len; 1903 size_t new_len;
760 1904
761 new_len = strlen(*dst) + strlen(src); 1905 new_len = strlen(*dst) + strlen(src);
762 if (*curr_len <= new_len) { 1906 if (*curr_len <= new_len) {
763 *curr_len = new_len + (*curr_len / 2); 1907 *curr_len = new_len + (*curr_len / 2);
764 *dst = realloc(*dst, *curr_len); 1908 *dst = realloc(*dst, *curr_len);
765 if (!*dst) 1909 if (!*dst)
766 err("could not realloc %li bytes", (unsigned long)*curr_len); 1910 err("could not realloc() %li bytes", (unsigned long)*curr_len);
767 } 1911 }
768 1912
1913 if (n)
1914 strncat(*dst, src, n);
1915 else
769 strcat(*dst, src); 1916 strcat(*dst, src);
770} 1917}
771static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1918static inline void xchrcat(char **dst, const char append, size_t *curr_len)
772{ 1919{
773 static char my_app[2]; 1920 static char my_app[2];
774 my_app[0] = append; 1921 my_app[0] = append;
775 my_app[1] = '\0'; 1922 my_app[1] = '\0';
776 xstrcat(dst, my_app, curr_len); 1923 xstrcat(dst, my_app, curr_len);
777} 1924}
778static int xemptybuffer(const char *buff) 1925
1926/* Match filename against entries in matchlist, return TRUE
1927 * if the file is listed */
1928static int file_matches_list(const char *filename, char **matchlist)
779{ 1929{
780 long i; 1930 char **file;
781 for (i=0; buff[i]; ++i) 1931 char *match;
782 if (buff[i] != ' ') 1932 char buf[__PAX_UTILS_PATH_MAX];
1933
1934 if (matchlist == NULL)
783 return 0; 1935 return 0;
1936
1937 for (file = matchlist; *file != NULL; file++) {
1938 if (search_path) {
1939 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
1940 match = buf;
1941 } else {
1942 match = *file;
1943 }
1944 if (fnmatch(match, filename, 0) == 0)
784 return 1; 1945 return 1;
1946 }
1947 return 0;
785} 1948}
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.155

  ViewVC Help
Powered by ViewVC 1.1.20