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

  ViewVC Help
Powered by ViewVC 1.1.20