/[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.35 Revision 1.97
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 2 * Copyright 2003-2005 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.35 2005/04/14 00:17:30 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.97 2005/12/29 14:03:25 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org>
8 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2005 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> 10#include <stdio.h>
25#include <stdlib.h> 11#include <stdlib.h>
26#include <sys/types.h> 12#include <sys/types.h>
27#define __USE_GNU 13#include <libgen.h>
14#include <limits.h>
28#include <string.h> 15#include <string.h>
29#include <errno.h> 16#include <errno.h>
30#include <unistd.h> 17#include <unistd.h>
31#include <sys/stat.h> 18#include <sys/stat.h>
19#include <sys/mman.h>
20#include <fcntl.h>
32#include <dirent.h> 21#include <dirent.h>
33#include <getopt.h> 22#include <getopt.h>
34#include <assert.h> 23#include <assert.h>
35
36#include "paxelf.h" 24#include "paxinc.h"
37 25
38static const char *rcsid = "$Id: scanelf.c,v 1.35 2005/04/14 00:17:30 solar Exp $"; 26static const char *rcsid = "$Id: scanelf.c,v 1.97 2005/12/29 14:03:25 vapier Exp $";
27#define argv0 "scanelf"
39 28
40 29#define IS_MODIFIER(c) (c == '%' || c == '#')
41/* helper functions for showing errors */
42#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
43#define warn(fmt, args...) \
44 fprintf(stderr, "%s: " fmt "\n", argv0, ## args)
45#define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args)
46#define err(fmt, args...) \
47 do { \
48 warn(fmt, ## args); \
49 exit(EXIT_FAILURE); \
50 } while (0)
51 30
52 31
53 32
54/* prototypes */ 33/* prototypes */
55static void scanelf_file(const char *filename); 34static void scanelf_file(const char *filename);
56static void scanelf_dir(const char *path); 35static void scanelf_dir(const char *path);
57static void scanelf_ldpath(); 36static void scanelf_ldpath();
58static void scanelf_envpath(); 37static void scanelf_envpath();
59static void usage(int status); 38static void usage(int status);
60static void parseargs(int argc, char *argv[]); 39static void parseargs(int argc, char *argv[]);
40static char *xstrdup(const char *s);
41static void *xmalloc(size_t size);
42static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
43#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
44static inline void xchrcat(char **dst, const char append, size_t *curr_len);
61 45
62/* variables to control behavior */ 46/* variables to control behavior */
47static char *ldpaths[256];
63static char scan_ldpath = 0; 48static char scan_ldpath = 0;
64static char scan_envpath = 0; 49static char scan_envpath = 0;
50static char scan_symlink = 1;
65static char dir_recurse = 0; 51static char dir_recurse = 0;
66static char dir_crossmount = 1; 52static char dir_crossmount = 1;
67static char show_pax = 0; 53static char show_pax = 0;
68static char show_stack = 0; 54static char show_phdr = 0;
69static char show_textrel = 0; 55static char show_textrel = 0;
70static char show_rpath = 0; 56static char show_rpath = 0;
71static char show_needed = 0; 57static char show_needed = 0;
58static char show_interp = 0;
59static char show_bind = 0;
60static char show_soname = 0;
61static char show_textrels = 0;
72static char show_banner = 1; 62static char show_banner = 1;
73static char be_quiet = 0; 63static char be_quiet = 0;
74static char be_verbose = 0; 64static char be_verbose = 0;
65static char be_wewy_wewy_quiet = 0;
66static char *find_sym = NULL, *versioned_symname = NULL;
75static char *find_sym = NULL; 67static char *find_lib = NULL;
68static char *out_format = NULL;
69static char *search_path = NULL;
70static char gmatch = 0;
71static char printcache = 0;
76 72
77 73
74caddr_t ldcache = 0;
75size_t ldcache_size = 0;
78 76
79/* scan an elf file and show all the fun stuff */ 77/* sub-funcs for scanelf_file() */
80static void scanelf_file(const char *filename) 78static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
81{ 79{
82 int i; 80 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
83 char found_pax, found_stack, found_relro, found_textrel, 81#define GET_SYMTABS(B) \
84 found_rpath, found_needed, found_sym; 82 if (elf->elf_class == ELFCLASS ## B) { \
85 elfobj *elf; 83 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
84 /* debug sections */ \
85 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
86 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
87 /* runtime sections */ \
88 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
89 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
90 if (symtab && dynsym) { \
91 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
92 } else { \
93 *sym = (void*)(symtab ? symtab : dynsym); \
94 } \
95 if (strtab && dynstr) { \
96 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
97 } else { \
98 *tab = (void*)(strtab ? strtab : dynstr); \
99 } \
100 }
101 GET_SYMTABS(32)
102 GET_SYMTABS(64)
103}
104static char *scanelf_file_pax(elfobj *elf, char *found_pax)
105{
106 static char ret[7];
107 unsigned long i, shown;
108
109 if (!show_pax) return NULL;
110
111 shown = 0;
112 memset(&ret, 0, sizeof(ret));
113
114 if (elf->phdr) {
115#define SHOW_PAX(B) \
116 if (elf->elf_class == ELFCLASS ## B) { \
117 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
118 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
119 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
120 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
121 continue; \
122 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
123 continue; \
124 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
125 *found_pax = 1; \
126 ++shown; \
127 break; \
128 } \
129 }
130 SHOW_PAX(32)
131 SHOW_PAX(64)
132 }
133
134 /* fall back to EI_PAX if no PT_PAX was found */
135 if (!*ret) {
136 static char *paxflags;
137 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
138 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
139 *found_pax = 1;
140 return (be_wewy_wewy_quiet ? NULL : paxflags);
141 }
142 strncpy(ret, paxflags, sizeof(ret));
143 }
144
145 if (be_wewy_wewy_quiet || (be_quiet && !shown))
146 return NULL;
147 else
148 return ret;
149}
150
151static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
152{
153 static char ret[12];
154 char *found;
155 unsigned long i, shown;
156 unsigned char multi_stack, multi_relro, multi_load;
157
158 if (!show_phdr) return NULL;
159
160 memcpy(ret, "--- --- ---\0", 12);
161
162 shown = 0;
163 multi_stack = multi_relro = multi_load = 0;
164
165#define SHOW_PHDR(B) \
166 if (elf->elf_class == ELFCLASS ## B) { \
167 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
168 Elf ## B ## _Off offset; \
169 uint32_t flags, check_flags; \
170 if (elf->phdr != NULL) { \
171 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
172 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
173 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
174 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
175 found = found_phdr; \
176 offset = 0; \
177 check_flags = PF_X; \
178 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
179 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
180 found = found_relro; \
181 offset = 4; \
182 check_flags = PF_X; \
183 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
184 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
185 found = found_load; \
186 offset = 8; \
187 check_flags = PF_W|PF_X; \
188 } else \
189 continue; \
190 flags = EGET(phdr[i].p_flags); \
191 if (be_quiet && ((flags & check_flags) != check_flags)) \
192 continue; \
193 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
194 *found = 1; \
195 ++shown; \
196 } \
197 } else if (elf->shdr != NULL) { \
198 /* no program headers which means this is prob an object file */ \
199 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
200 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
201 check_flags = SHF_WRITE|SHF_EXECINSTR; \
202 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
203 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
204 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
205 if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \
206 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
207 flags = EGET(shdr[i].sh_flags); \
208 if (be_quiet && ((flags & check_flags) != check_flags)) \
209 continue; \
210 ++*found_phdr; \
211 shown = 1; \
212 if (flags & SHF_WRITE) ret[0] = 'W'; \
213 if (flags & SHF_ALLOC) ret[1] = 'A'; \
214 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
215 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
216 break; \
217 } \
218 } \
219 if (!multi_stack) { \
220 *found_phdr = 1; \
221 shown = 1; \
222 memcpy(ret, "!WX", 3); \
223 } \
224 } \
225 }
226 SHOW_PHDR(32)
227 SHOW_PHDR(64)
228
229 if (be_wewy_wewy_quiet || (be_quiet && !shown))
230 return NULL;
231 else
232 return ret;
233}
234static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
235{
236 static const char *ret = "TEXTREL";
237 unsigned long i;
238
239 if (!show_textrel && !show_textrels) return NULL;
240
241 if (elf->phdr) {
242#define SHOW_TEXTREL(B) \
243 if (elf->elf_class == ELFCLASS ## B) { \
244 Elf ## B ## _Dyn *dyn; \
245 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
246 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
247 Elf ## B ## _Off offset; \
248 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
249 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
250 offset = EGET(phdr[i].p_offset); \
251 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
252 dyn = DYN ## B (elf->data + offset); \
253 while (EGET(dyn->d_tag) != DT_NULL) { \
254 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
255 *found_textrel = 1; \
256 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
257 return (be_wewy_wewy_quiet ? NULL : ret); \
258 } \
259 ++dyn; \
260 } \
261 } }
262 SHOW_TEXTREL(32)
263 SHOW_TEXTREL(64)
264 }
265
266 if (be_quiet || be_wewy_wewy_quiet)
267 return NULL;
268 else
269 return " - ";
270}
271static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
272{
273 unsigned long s, r, rmax;
274 void *symtab_void, *strtab_void, *text_void;
275
276 if (!show_textrels) return NULL;
277
278 /* don't search for TEXTREL's if the ELF doesn't have any */
279 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
280 if (!*found_textrel) return NULL;
281
282 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
283 text_void = elf_findsecbyname(elf, ".text");
284
285 if (symtab_void && strtab_void && text_void && elf->shdr) {
286#define SHOW_TEXTRELS(B) \
287 if (elf->elf_class == ELFCLASS ## B) { \
288 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
289 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
290 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
291 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
292 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
293 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
294 uint ## B ## _t memsz = EGET(text->sh_size); \
295 Elf ## B ## _Rel *rel; \
296 Elf ## B ## _Rela *rela; \
297 /* search the section headers for relocations */ \
298 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
299 uint32_t sh_type = EGET(shdr[s].sh_type); \
300 if (sh_type == SHT_REL) { \
301 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
302 rela = NULL; \
303 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
304 } else if (sh_type == SHT_RELA) { \
305 rel = NULL; \
306 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
307 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
308 } else \
309 continue; \
310 /* now see if any of the relocs are in the .text */ \
311 for (r = 0; r < rmax; ++r) { \
312 unsigned long sym_max; \
313 Elf ## B ## _Addr offset_tmp; \
314 Elf ## B ## _Sym *func; \
315 Elf ## B ## _Sym *sym; \
316 Elf ## B ## _Addr r_offset; \
317 uint ## B ## _t r_info; \
318 if (sh_type == SHT_REL) { \
319 r_offset = EGET(rel[r].r_offset); \
320 r_info = EGET(rel[r].r_info); \
321 } else { \
322 r_offset = EGET(rela[r].r_offset); \
323 r_info = EGET(rela[r].r_info); \
324 } \
325 /* make sure this relocation is inside of the .text */ \
326 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
327 if (be_verbose <= 2) continue; \
328 } else \
329 *found_textrels = 1; \
330 /* locate this relocation symbol name */ \
331 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
332 sym_max = ELF ## B ## _R_SYM(r_info); \
333 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
334 sym += sym_max; \
335 else \
336 sym = NULL; \
337 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
338 /* show the raw details about this reloc */ \
339 printf(" %s: ", elf->base_filename); \
340 if (sym && sym->st_name) \
341 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
342 else \
343 printf("(memory/fake?)"); \
344 printf(" [0x%lX]", (unsigned long)r_offset); \
345 /* now try to find the closest symbol that this rel is probably in */ \
346 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
347 func = NULL; \
348 offset_tmp = 0; \
349 while (sym_max--) { \
350 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
351 func = sym; \
352 offset_tmp = EGET(sym->st_value); \
353 } \
354 ++sym; \
355 } \
356 printf(" in "); \
357 if (func && func->st_name) \
358 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
359 else \
360 printf("(NULL: fake?)"); \
361 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
362 } \
363 } }
364 SHOW_TEXTRELS(32)
365 SHOW_TEXTRELS(64)
366 }
367 if (!*found_textrels)
368 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
369
370 return NULL;
371}
372
373static void rpath_security_checks(elfobj *, char *);
374static void rpath_security_checks(elfobj *elf, char *item) {
86 struct stat st; 375 struct stat st;
87 376 switch (*item) {
88 /* make sure path exists */ 377 case '/': break;
89 if (lstat(filename, &st) == -1) 378 case '.':
90 return; 379 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename);
91 if (!S_ISREG(st.st_mode)) 380 break;
92 return; 381 case '\0':
93 found_pax = found_stack = found_relro = found_textrel = \ 382 warnf("Security problem NULL RPATH in %s", elf->filename);
94 found_rpath = found_needed = found_sym = 0; 383 break;
95 384 case '$':
96 /* verify this is real ELF */ 385 if (fstat(elf->fd, &st) != -1)
97 if ((elf = readelf(filename)) == NULL) { 386 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
98 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 387 warnf("Security problem with RPATH='%s' in %s with mode set of %o",
99 return; 388 item, elf->filename, st.st_mode & 07777);
100 } 389 break;
101 390 default:
102 if (be_verbose > 1) 391 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename);
103 printf("%s: {%s,%s} scanning file\n", filename, 392 break;
104 get_elfeitype(elf, EI_CLASS, elf->elf_class),
105 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
106 else if (be_verbose)
107 printf("%s: scanning file\n", filename);
108
109 /* show the header */
110 if (!be_quiet && show_banner) {
111 printf(" TYPE ");
112 if (show_pax) printf(" PAX ");
113 if (show_stack) printf("STK/REL ");
114 if (show_textrel) printf("TEXTREL ");
115 if (show_rpath) printf("RPATH ");
116 if (show_needed) printf("NEEDED ");
117 printf(" FILE\n");
118 show_banner = 0;
119 }
120
121 /* dump all the good stuff */
122 if (!be_quiet)
123 printf("%-7s ", get_elfetype(elf));
124
125 if (show_pax) {
126 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
127 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
128 found_pax = 1;
129 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
130 } 393 }
131 } 394}
132 395static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
133 /* stack fun */ 396{
134 if (show_stack) { 397 unsigned long i, s;
135#define SHOW_STACK(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
138 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
139 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
140 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \
141 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \
142 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
143 continue; \
144 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \
145 found_stack = 1; \
146 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \
147 found_relro = 1; \
148 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \
149 } \
150 }
151 SHOW_STACK(32)
152 SHOW_STACK(64)
153 if (!be_quiet && !found_stack) printf("--- ");
154 if (!be_quiet && !found_relro) printf("--- ");
155 }
156
157 /* textrel fun */
158 if (show_textrel) {
159#define SHOW_TEXTREL(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Dyn *dyn; \
162 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
163 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
164 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
165 if (phdr[i].p_type != PT_DYNAMIC) continue; \
166 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
167 while (EGET(dyn->d_tag) != DT_NULL) { \
168 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
169 found_textrel = 1; \
170 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
171 fputs("TEXTREL ", stdout); \
172 } \
173 ++dyn; \
174 } \
175 } }
176 SHOW_TEXTREL(32)
177 SHOW_TEXTREL(64)
178 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
179 }
180
181 /* rpath fun */
182 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
183 if (show_rpath) {
184 char *rpath, *runpath; 398 char *rpath, *runpath, **r;
399 void *strtbl_void;
400
401 if (!show_rpath) return;
402
185 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 403 strtbl_void = elf_findsecbyname(elf, ".dynstr");
186 rpath = runpath = NULL; 404 rpath = runpath = NULL;
187 405
188 if (strtbl_void) { 406 if (elf->phdr && strtbl_void) {
189#define SHOW_RPATH(B) \ 407#define SHOW_RPATH(B) \
190 if (elf->elf_class == ELFCLASS ## B) { \ 408 if (elf->elf_class == ELFCLASS ## B) { \
191 Elf ## B ## _Dyn *dyn; \ 409 Elf ## B ## _Dyn *dyn; \
192 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 410 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
193 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 411 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
194 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 412 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
413 Elf ## B ## _Off offset; \
414 Elf ## B ## _Xword word; \
415 /* Scan all the program headers */ \
195 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 416 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
417 /* Just scan dynamic headers */ \
196 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 418 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
419 offset = EGET(phdr[i].p_offset); \
420 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
421 /* Just scan dynamic RPATH/RUNPATH headers */ \
197 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 422 dyn = DYN ## B (elf->data + offset); \
198 while (EGET(dyn->d_tag) != DT_NULL) { \ 423 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
199 if (EGET(dyn->d_tag) == DT_RPATH) { \ 424 if (word == DT_RPATH) { \
425 r = &rpath; \
426 } else if (word == DT_RUNPATH) { \
427 r = &runpath; \
428 } else { \
429 ++dyn; \
430 continue; \
431 } \
432 /* Verify the memory is somewhat sane */ \
200 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 433 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
434 if (offset < (Elf ## B ## _Off)elf->len) { \
435 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
436 *r = (char*)(elf->data + offset); \
437 /* If quiet, don't output paths in ld.so.conf */ \
438 if (be_quiet) { \
439 size_t len; \
440 char *start, *end; \
441 /* note that we only 'chop' off leading known paths. */ \
442 /* since *r is read-only memory, we can only move the ptr forward. */ \
443 start = *r; \
444 /* scan each path in : delimited list */ \
445 while (start) { \
446 rpath_security_checks(elf, start); \
447 end = strchr(start, ':'); \
448 len = (end ? abs(end - start) : strlen(start)); \
449 for (s = 0; ldpaths[s]; ++s) { \
450 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
451 *r = (end ? end + 1 : NULL); \
452 break; \
453 } \
454 } \
455 if (!*r || !ldpaths[s] || !end) \
456 start = NULL; \
457 else \
458 start = start + len + 1; \
459 } \
460 } \
201 found_rpath = 1; \ 461 if (*r) *found_rpath = 1; \
202 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
203 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204 found_rpath = 1; \
205 } \ 462 } \
206 ++dyn; \ 463 ++dyn; \
207 } \ 464 } \
208 } } 465 } }
209 SHOW_RPATH(32) 466 SHOW_RPATH(32)
210 SHOW_RPATH(64) 467 SHOW_RPATH(64)
468 }
469
470 if (be_wewy_wewy_quiet) return;
471
472 if (rpath && runpath) {
473 if (!strcmp(rpath, runpath)) {
474 xstrcat(ret, runpath, ret_len);
475 } else {
476 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
477 xchrcat(ret, '{', ret_len);
478 xstrcat(ret, rpath, ret_len);
479 xchrcat(ret, ',', ret_len);
480 xstrcat(ret, runpath, ret_len);
481 xchrcat(ret, '}', ret_len);
211 } 482 }
212 if (rpath && runpath) {
213 if (!strcmp(rpath, runpath))
214 printf("%-5s ", runpath);
215 else {
216 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath);
217 printf("{%s,%s} ", rpath, runpath);
218 }
219 } else if (rpath || runpath) 483 } else if (rpath || runpath)
220 printf("%-5s ", (runpath ? runpath : rpath)); 484 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
221 else if (!be_quiet && !found_rpath) 485 else if (!be_quiet)
222 printf(" - "); 486 xstrcat(ret, " - ", ret_len);
223 } 487}
224 488
225 /* print out all the NEEDED entries */ 489#define LDSO_CACHE_MAGIC "ld.so-"
226 if (show_needed) { 490#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
491#define LDSO_CACHE_VER "1.7.0"
492#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
493#define FLAG_ANY -1
494#define FLAG_TYPE_MASK 0x00ff
495#define FLAG_LIBC4 0x0000
496#define FLAG_ELF 0x0001
497#define FLAG_ELF_LIBC5 0x0002
498#define FLAG_ELF_LIBC6 0x0003
499#define FLAG_REQUIRED_MASK 0xff00
500#define FLAG_SPARC_LIB64 0x0100
501#define FLAG_IA64_LIB64 0x0200
502#define FLAG_X8664_LIB64 0x0300
503#define FLAG_S390_LIB64 0x0400
504#define FLAG_POWERPC_LIB64 0x0500
505#define FLAG_MIPS64_LIBN32 0x0600
506#define FLAG_MIPS64_LIBN64 0x0700
507
508static char *lookup_cache_lib(elfobj *, char *);
509static char *lookup_cache_lib(elfobj *elf, char *fname)
510{
511 int fd = 0;
512 char *strs;
513 static char buf[_POSIX_PATH_MAX] = "";
514 const char *cachefile = "/etc/ld.so.cache";
515 struct stat st;
516
517 typedef struct {
518 char magic[LDSO_CACHE_MAGIC_LEN];
519 char version[LDSO_CACHE_VER_LEN];
520 int nlibs;
521 } header_t;
522 header_t *header;
523
524 typedef struct {
525 int flags;
526 int sooffset;
527 int liboffset;
528 } libentry_t;
529 libentry_t *libent;
530
531 if (fname == NULL)
532 return NULL;
533
534 if (ldcache == 0) {
535 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
536 return NULL;
537
538 /* cache these values so we only map/unmap the cache file once */
539 ldcache_size = st.st_size;
540 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
541
542 close(fd);
543
544 if (ldcache == (caddr_t)-1)
545 return NULL;
546
547 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
548 return NULL;
549 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
550 return NULL;
551 }
552
553 header = (header_t *) ldcache;
554 libent = (libentry_t *) (ldcache + sizeof(header_t));
555 strs = (char *) &libent[header->nlibs];
556
557 for (fd = 0; fd < header->nlibs; fd++) {
558 /* this should be more fine grained, but for now we assume that
559 * diff arches will not be cached together. and we ignore the
560 * the different multilib mips cases. */
561 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
562 continue;
563 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
564 continue;
565
566 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
567 continue;
568 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
569 }
570 return buf;
571}
572
573
574static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
575{
576 unsigned long i;
227 char *needed; 577 char *needed;
578 void *strtbl_void;
579 char *p;
580
581 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
582
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 583 strtbl_void = elf_findsecbyname(elf, ".dynstr");
229 584
230 if (strtbl_void) { 585 if (elf->phdr && strtbl_void) {
231#define SHOW_NEEDED(B) \ 586#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \ 587 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \ 588 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 589 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 590 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 591 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
592 Elf ## B ## _Off offset; \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 593 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
238 if (be_verbose && EGET(phdr[i].p_type) == PT_INTERP) { \
239 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
240 printf("%s\n", elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr)); \
241 exit(0); \
242 } \
243 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 594 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
595 offset = EGET(phdr[i].p_offset); \
596 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 597 dyn = DYN ## B (elf->data + offset); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \ 598 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 599 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 600 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
248 if (found_needed) printf(","); \ 601 if (offset >= (Elf ## B ## _Off)elf->len) { \
249 printf("%s", needed); \ 602 ++dyn; \
603 continue; \
604 } \
605 needed = (char*)(elf->data + offset); \
606 if (op == 0) { \
607 if (!be_wewy_wewy_quiet) { \
608 if (*found_needed) xchrcat(ret, ',', ret_len); \
609 if (printcache) \
610 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
611 needed = p; \
612 xstrcat(ret, needed, ret_len); \
613 } \
250 found_needed = 1; \ 614 *found_needed = 1; \
615 } else { \
616 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
617 *found_lib = 1; \
618 return (be_wewy_wewy_quiet ? NULL : needed); \
619 } \
620 } \
251 } \ 621 } \
252 ++dyn; \ 622 ++dyn; \
253 } \ 623 } \
254 } } 624 } }
255 SHOW_NEEDED(32) 625 SHOW_NEEDED(32)
256 SHOW_NEEDED(64) 626 SHOW_NEEDED(64)
627 if (op == 0 && !*found_needed && be_verbose)
628 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
629 }
630
631 return NULL;
632}
633static char *scanelf_file_interp(elfobj *elf, char *found_interp)
634{
635 void *strtbl_void;
636
637 if (!show_interp) return NULL;
638
639 strtbl_void = elf_findsecbyname(elf, ".interp");
640
641 if (strtbl_void) {
642#define SHOW_INTERP(B) \
643 if (elf->elf_class == ELFCLASS ## B) { \
644 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
645 *found_interp = 1; \
646 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
257 } 647 }
258 if (!be_quiet && !found_needed) 648 SHOW_INTERP(32)
259 printf(" - "); 649 SHOW_INTERP(64)
260 else if (found_needed)
261 printf(" ");
262 } 650 }
651 return NULL;
652}
653static char *scanelf_file_bind(elfobj *elf, char *found_bind)
654{
655 unsigned long i;
656 struct stat s;
263 657
264 /* search the symbol table for a specified symbol */ 658 if (!show_bind) return NULL;
265 if (find_sym) { 659 if (!elf->phdr) return NULL;
660
661#define SHOW_BIND(B) \
662 if (elf->elf_class == ELFCLASS ## B) { \
663 Elf ## B ## _Dyn *dyn; \
664 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
665 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
666 Elf ## B ## _Off offset; \
667 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
668 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
669 offset = EGET(phdr[i].p_offset); \
670 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
671 dyn = DYN ## B (elf->data + offset); \
672 while (EGET(dyn->d_tag) != DT_NULL) { \
673 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
674 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
675 { \
676 if (be_quiet) return NULL; \
677 *found_bind = 1; \
678 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
679 } \
680 ++dyn; \
681 } \
682 } \
683 }
684 SHOW_BIND(32)
685 SHOW_BIND(64)
686
687 if (be_wewy_wewy_quiet) return NULL;
688
689 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
690 return NULL;
691 } else {
692 *found_bind = 1;
693 return (char *) "LAZY";
694 }
695}
696static char *scanelf_file_soname(elfobj *elf, char *found_soname)
697{
698 unsigned long i;
699 char *soname;
700 void *strtbl_void;
701
702 if (!show_soname) return NULL;
703
704 strtbl_void = elf_findsecbyname(elf, ".dynstr");
705
706 if (elf->phdr && strtbl_void) {
707#define SHOW_SONAME(B) \
708 if (elf->elf_class == ELFCLASS ## B) { \
709 Elf ## B ## _Dyn *dyn; \
710 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
711 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
712 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
713 Elf ## B ## _Off offset; \
714 /* only look for soname in shared objects */ \
715 if (ehdr->e_type != ET_DYN) \
716 return NULL; \
717 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
718 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
719 offset = EGET(phdr[i].p_offset); \
720 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
721 dyn = DYN ## B (elf->data + offset); \
722 while (EGET(dyn->d_tag) != DT_NULL) { \
723 if (EGET(dyn->d_tag) == DT_SONAME) { \
724 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
725 if (offset >= (Elf ## B ## _Off)elf->len) { \
726 ++dyn; \
727 continue; \
728 } \
729 soname = (char*)(elf->data + offset); \
730 *found_soname = 1; \
731 return (be_wewy_wewy_quiet ? NULL : soname); \
732 } \
733 ++dyn; \
734 } \
735 } }
736 SHOW_SONAME(32)
737 SHOW_SONAME(64)
738 }
739
740 return NULL;
741}
742static char *scanelf_file_sym(elfobj *elf, char *found_sym)
743{
744 unsigned long i;
745 char *ret;
266 void *symtab_void, *strtab_void; 746 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269 747
270 len = strlen(find_sym) + 1; 748 if (!find_sym) return NULL;
271 versioned_symname = (char *)malloc(sizeof(char) * (len+1)); 749 ret = find_sym;
272 if (!versioned_symname) {
273 warnf("Could not malloc() mem for sym scan");
274 return;
275 }
276 sprintf(versioned_symname, "%s@", find_sym);
277 750
278 symtab_void = elf_findsecbyname(elf, ".symtab"); 751 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
279 strtab_void = elf_findsecbyname(elf, ".strtab");
280 752
281 if (symtab_void && strtab_void) { 753 if (symtab_void && strtab_void) {
282#define FIND_SYM(B) \ 754#define FIND_SYM(B) \
283 if (elf->elf_class == ELFCLASS ## B) { \ 755 if (elf->elf_class == ELFCLASS ## B) { \
284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 756 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 757 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
286 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 758 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
287 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 759 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
288 char *symname; \ 760 char *symname; \
289 for (i = 0; i < cnt; ++i) { \ 761 for (i = 0; i < cnt; ++i) { \
290 if (sym->st_name) { \ 762 if (sym->st_name) { \
291 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 763 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
292 if (*find_sym == '*') { \ 764 if (*find_sym == '*') { \
293 printf("%s(%s) %5lX %15s %s\n", \ 765 printf("%s(%s) %5lX %15s %s\n", \
294 ((found_sym == 0) ? "\n\t" : "\t"), \ 766 ((*found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \ 767 elf->base_filename, \
296 (long)sym->st_size, \ 768 (unsigned long)sym->st_size, \
297 (char *)get_elfstttype(sym->st_info), \ 769 get_elfstttype(sym->st_info), \
298 symname); \ 770 symname); \
299 found_sym = 1; \ 771 *found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \ 772 } else { \
773 char *this_sym, *next_sym; \
774 this_sym = find_sym; \
775 do { \
776 next_sym = strchr(this_sym, ','); \
777 if (next_sym == NULL) \
778 next_sym = this_sym + strlen(this_sym); \
779 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
301 (strncmp(symname, versioned_symname, len) == 0)) \ 780 (strcmp(symname, versioned_symname) == 0)) { \
781 ret = this_sym; \
302 found_sym++; \ 782 (*found_sym)++; \
783 goto break_out; \
784 } \
785 this_sym = next_sym + 1; \
786 } while (*next_sym != '\0'); \
787 } \
303 } \ 788 } \
304 ++sym; \ 789 ++sym; \
305 } } 790 } }
306 FIND_SYM(32) 791 FIND_SYM(32)
307 FIND_SYM(64) 792 FIND_SYM(64)
793 }
794
795break_out:
796 if (be_wewy_wewy_quiet) return NULL;
797
798 if (*find_sym != '*' && *found_sym)
799 return ret;
800 if (be_quiet)
801 return NULL;
802 else
803 return (char *)" - ";
804}
805/* scan an elf file and show all the fun stuff */
806#define prints(str) write(fileno(stdout), str, strlen(str))
807static void scanelf_file(const char *filename)
808{
809 unsigned long i;
810 char found_pax, found_phdr, found_relro, found_load, found_textrel,
811 found_rpath, found_needed, found_interp, found_bind, found_soname,
812 found_sym, found_lib, found_file, found_textrels;
813 elfobj *elf;
814 struct stat st;
815 static char *out_buffer = NULL;
816 static size_t out_len;
817
818 /* make sure 'filename' exists */
819 if (lstat(filename, &st) == -1) {
820 if (be_verbose > 2) printf("%s: does not exist\n", filename);
821 return;
822 }
823 /* always handle regular files and handle symlinked files if no -y */
824 if (S_ISLNK(st.st_mode)) {
825 if (!scan_symlink) return;
826 stat(filename, &st);
827 }
828 if (!S_ISREG(st.st_mode)) {
829 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
830 return;
831 }
832
833 found_pax = found_phdr = found_relro = found_load = found_textrel = \
834 found_rpath = found_needed = found_interp = found_bind = found_soname = \
835 found_sym = found_lib = found_file = found_textrels = 0;
836
837 /* verify this is real ELF */
838 if ((elf = readelf(filename)) == NULL) {
839 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
840 return;
841 }
842
843 if (be_verbose > 1)
844 printf("%s: scanning file {%s,%s}\n", filename,
845 get_elfeitype(EI_CLASS, elf->elf_class),
846 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
847 else if (be_verbose)
848 printf("%s: scanning file\n", filename);
849
850 /* init output buffer */
851 if (!out_buffer) {
852 out_len = sizeof(char) * 80;
853 out_buffer = (char*)xmalloc(out_len);
854 }
855 *out_buffer = '\0';
856
857 /* show the header */
858 if (!be_quiet && show_banner) {
859 for (i = 0; out_format[i]; ++i) {
860 if (!IS_MODIFIER(out_format[i])) continue;
861
862 switch (out_format[++i]) {
863 case '%': break;
864 case '#': break;
865 case 'F':
866 case 'p':
867 case 'f': prints("FILE "); found_file = 1; break;
868 case 'o': prints(" TYPE "); break;
869 case 'x': prints(" PAX "); break;
870 case 'e': prints("STK/REL/PTL "); break;
871 case 't': prints("TEXTREL "); break;
872 case 'r': prints("RPATH "); break;
873 case 'n': prints("NEEDED "); break;
874 case 'i': prints("INTERP "); break;
875 case 'b': prints("BIND "); break;
876 case 'S': prints("SONAME "); break;
877 case 's': prints("SYM "); break;
878 case 'N': prints("LIB "); break;
879 case 'T': prints("TEXTRELS "); break;
880 default: warnf("'%c' has no title ?", out_format[i]);
881 }
308 } 882 }
309 free(versioned_symname); 883 if (!found_file) prints("FILE ");
310 if (*find_sym != '*') { 884 prints("\n");
311 if (found_sym) 885 found_file = 0;
312 printf(" %s ", find_sym); 886 show_banner = 0;
313 else if (!be_quiet) 887 }
314 fputs(" - ", stdout); 888
889 /* dump all the good stuff */
890 for (i = 0; out_format[i]; ++i) {
891 const char *out;
892 const char *tmp;
893
894 /* make sure we trim leading spaces in quiet mode */
895 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
896 *out_buffer = '\0';
897
898 if (!IS_MODIFIER(out_format[i])) {
899 xchrcat(&out_buffer, out_format[i], &out_len);
900 continue;
315 } 901 }
902
903 out = NULL;
904 be_wewy_wewy_quiet = (out_format[i] == '#');
905 switch (out_format[++i]) {
906 case '%':
907 case '#':
908 xchrcat(&out_buffer, out_format[i], &out_len); break;
909 case 'F':
910 found_file = 1;
911 if (be_wewy_wewy_quiet) break;
912 xstrcat(&out_buffer, filename, &out_len);
913 break;
914 case 'p':
915 found_file = 1;
916 if (be_wewy_wewy_quiet) break;
917 tmp = filename;
918 if (search_path) {
919 ssize_t len_search = strlen(search_path);
920 ssize_t len_file = strlen(filename);
921 if (!strncmp(filename, search_path, len_search) && \
922 len_file > len_search)
923 tmp += len_search;
924 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
925 }
926 xstrcat(&out_buffer, tmp, &out_len);
927 break;
928 case 'f':
929 found_file = 1;
930 if (be_wewy_wewy_quiet) break;
931 tmp = strrchr(filename, '/');
932 tmp = (tmp == NULL ? filename : tmp+1);
933 xstrcat(&out_buffer, tmp, &out_len);
934 break;
935 case 'o': out = get_elfetype(elf); break;
936 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
937 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
938 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
939 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
940 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
941 case 'n':
942 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
943 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
944 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
945 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
946 case 's': out = scanelf_file_sym(elf, &found_sym); break;
947 default: warnf("'%c' has no scan code?", out_format[i]);
316 } 948 }
949 if (out) {
950 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
951 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
952 xstrncat(&out_buffer, out, &out_len, (tmp-out));
953 else
954 xstrcat(&out_buffer, out, &out_len);
955 }
956 }
317 957
318 if (!be_quiet || found_pax || found_stack || found_textrel || \ 958#define FOUND_SOMETHING() \
319 found_rpath || found_needed || found_sym) 959 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
320 puts(filename); 960 found_rpath || found_needed || found_interp || found_bind || \
961 found_soname || found_sym || found_lib || found_textrels)
962
963 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
964 xchrcat(&out_buffer, ' ', &out_len);
965 xstrcat(&out_buffer, filename, &out_len);
966 }
967 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
968 puts(out_buffer);
969 fflush(stdout);
970 }
321 971
322 unreadelf(elf); 972 unreadelf(elf);
323} 973}
324 974
325/* scan a directory for ET_EXEC files and print when we find one */ 975/* scan a directory for ET_EXEC files and print when we find one */
330 struct stat st_top, st; 980 struct stat st_top, st;
331 char buf[_POSIX_PATH_MAX]; 981 char buf[_POSIX_PATH_MAX];
332 size_t pathlen = 0, len = 0; 982 size_t pathlen = 0, len = 0;
333 983
334 /* make sure path exists */ 984 /* make sure path exists */
335 if (lstat(path, &st_top) == -1) 985 if (lstat(path, &st_top) == -1) {
986 if (be_verbose > 2) printf("%s: does not exist\n", path);
336 return; 987 return;
988 }
337 989
338 /* ok, if it isn't a directory, assume we can open it */ 990 /* ok, if it isn't a directory, assume we can open it */
339 if (!S_ISDIR(st_top.st_mode)) { 991 if (!S_ISDIR(st_top.st_mode)) {
340 scanelf_file(path); 992 scanelf_file(path);
341 return; 993 return;
352 while ((dentry = readdir(dir))) { 1004 while ((dentry = readdir(dir))) {
353 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1005 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
354 continue; 1006 continue;
355 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1007 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
356 if (len >= sizeof(buf)) { 1008 if (len >= sizeof(buf)) {
357 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 1009 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1010 (unsigned long)len, (unsigned long)sizeof(buf));
358 continue; 1011 continue;
359 } 1012 }
360 sprintf(buf, "%s/%s", path, dentry->d_name); 1013 sprintf(buf, "%s/%s", path, dentry->d_name);
361 if (lstat(buf, &st) != -1) { 1014 if (lstat(buf, &st) != -1) {
362 if (S_ISREG(st.st_mode)) 1015 if (S_ISREG(st.st_mode))
368 } 1021 }
369 } 1022 }
370 closedir(dir); 1023 closedir(dir);
371} 1024}
372 1025
1026static int scanelf_from_file(char *filename)
1027{
1028 FILE *fp = NULL;
1029 char *p;
1030 char path[_POSIX_PATH_MAX];
1031
1032 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
1033 fp = stdin;
1034 else if ((fp = fopen(filename, "r")) == NULL)
1035 return 1;
1036
1037 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
1038 if ((p = strchr(path, '\n')) != NULL)
1039 *p = 0;
1040 search_path = path;
1041 scanelf_dir(path);
1042 }
1043 if (fp != stdin)
1044 fclose(fp);
1045 return 0;
1046}
1047
1048static void load_ld_so_conf()
1049{
1050 FILE *fp = NULL;
1051 char *p;
1052 char path[_POSIX_PATH_MAX];
1053 int i = 0;
1054
1055 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
1056 return;
1057
1058 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
1059 if (*path != '/')
1060 continue;
1061
1062 if ((p = strrchr(path, '\r')) != NULL)
1063 *p = 0;
1064 if ((p = strchr(path, '\n')) != NULL)
1065 *p = 0;
1066
1067 ldpaths[i++] = xstrdup(path);
1068
1069 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1070 break;
1071 }
1072 ldpaths[i] = NULL;
1073
1074 fclose(fp);
1075}
1076
373/* scan /etc/ld.so.conf for paths */ 1077/* scan /etc/ld.so.conf for paths */
374static void scanelf_ldpath() 1078static void scanelf_ldpath()
375{ 1079{
376 char scan_l, scan_ul, scan_ull; 1080 char scan_l, scan_ul, scan_ull;
377 char *path, *p; 1081 int i = 0;
378 FILE *fp;
379 1082
380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1083 if (!ldpaths[0])
381 err("Unable to open ld.so.conf: %s", strerror(errno)); 1084 err("Unable to load any paths from ld.so.conf");
382 1085
383 scan_l = scan_ul = scan_ull = 0; 1086 scan_l = scan_ul = scan_ull = 0;
384 1087
385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 1088 while (ldpaths[i]) {
386 warn("Can not malloc() memory for ldpath scanning");
387 return;
388 }
389 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
390 if (*path == '/') {
391 if ((p = strrchr(path, '\r')) != NULL)
392 *p = 0;
393 if ((p = strrchr(path, '\n')) != NULL)
394 *p = 0;
395 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 1089 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
396 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 1090 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
397 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 1091 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
398 scanelf_dir(path); 1092 scanelf_dir(ldpaths[i]);
1093 ++i;
399 } 1094 }
400 free(path);
401 fclose(fp);
402 1095
403 if (!scan_l) scanelf_dir("/lib"); 1096 if (!scan_l) scanelf_dir("/lib");
404 if (!scan_ul) scanelf_dir("/usr/lib"); 1097 if (!scan_ul) scanelf_dir("/usr/lib");
405 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1098 if (!scan_ull) scanelf_dir("/usr/local/lib");
406} 1099}
411 char *path, *p; 1104 char *path, *p;
412 1105
413 path = getenv("PATH"); 1106 path = getenv("PATH");
414 if (!path) 1107 if (!path)
415 err("PATH is not set in your env !"); 1108 err("PATH is not set in your env !");
416 1109 path = xstrdup(path);
417 if ((path = strdup(path)) == NULL)
418 err("strdup failed: %s", strerror(errno));
419 1110
420 while ((p = strrchr(path, ':')) != NULL) { 1111 while ((p = strrchr(path, ':')) != NULL) {
421 scanelf_dir(p + 1); 1112 scanelf_dir(p + 1);
422 *p = 0; 1113 *p = 0;
423 } 1114 }
424 1115
425 free(path); 1116 free(path);
426} 1117}
427 1118
428 1119
429
430/* usage / invocation handling functions */ 1120/* usage / invocation handling functions */
431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV" 1121#define PARSE_FLAGS "plRmyxetrnLibSs:gN:TaqvF:f:o:BhV"
432#define a_argument required_argument 1122#define a_argument required_argument
433static struct option const long_opts[] = { 1123static struct option const long_opts[] = {
434 {"path", no_argument, NULL, 'p'}, 1124 {"path", no_argument, NULL, 'p'},
435 {"ldpath", no_argument, NULL, 'l'}, 1125 {"ldpath", no_argument, NULL, 'l'},
436 {"recursive", no_argument, NULL, 'R'}, 1126 {"recursive", no_argument, NULL, 'R'},
437 {"mount", no_argument, NULL, 'm'}, 1127 {"mount", no_argument, NULL, 'm'},
1128 {"symlink", no_argument, NULL, 'y'},
438 {"pax", no_argument, NULL, 'x'}, 1129 {"pax", no_argument, NULL, 'x'},
439 {"header", no_argument, NULL, 'e'}, 1130 {"header", no_argument, NULL, 'e'},
440 {"textrel", no_argument, NULL, 't'}, 1131 {"textrel", no_argument, NULL, 't'},
441 {"rpath", no_argument, NULL, 'r'}, 1132 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'}, 1133 {"needed", no_argument, NULL, 'n'},
1134 {"ldcache", no_argument, NULL, 'L'},
1135 {"interp", no_argument, NULL, 'i'},
1136 {"bind", no_argument, NULL, 'b'},
1137 {"soname", no_argument, NULL, 'S'},
443 {"symbol", a_argument, NULL, 's'}, 1138 {"symbol", a_argument, NULL, 's'},
1139 {"lib", a_argument, NULL, 'N'},
1140 {"gmatch", no_argument, NULL, 'g'},
1141 {"textrels", no_argument, NULL, 'T'},
444 {"all", no_argument, NULL, 'a'}, 1142 {"all", no_argument, NULL, 'a'},
445 {"quiet", no_argument, NULL, 'q'}, 1143 {"quiet", no_argument, NULL, 'q'},
446 {"verbose", no_argument, NULL, 'v'}, 1144 {"verbose", no_argument, NULL, 'v'},
1145 {"format", a_argument, NULL, 'F'},
1146 {"from", a_argument, NULL, 'f'},
447 {"file", a_argument, NULL, 'o'}, 1147 {"file", a_argument, NULL, 'o'},
448 {"nobanner", no_argument, NULL, 'B'}, 1148 {"nobanner", no_argument, NULL, 'B'},
449 {"help", no_argument, NULL, 'h'}, 1149 {"help", no_argument, NULL, 'h'},
450 {"version", no_argument, NULL, 'V'}, 1150 {"version", no_argument, NULL, 'V'},
451 {NULL, no_argument, NULL, 0x0} 1151 {NULL, no_argument, NULL, 0x0}
452}; 1152};
1153
453static char *opts_help[] = { 1154static const char *opts_help[] = {
454 "Scan all directories in PATH environment", 1155 "Scan all directories in PATH environment",
455 "Scan all directories in /etc/ld.so.conf", 1156 "Scan all directories in /etc/ld.so.conf",
456 "Scan directories recursively", 1157 "Scan directories recursively",
457 "Don't recursively cross mount points\n", 1158 "Don't recursively cross mount points",
1159 "Don't scan symlinks\n",
458 "Print PaX markings", 1160 "Print PaX markings",
459 "Print GNU_STACK markings", 1161 "Print GNU_STACK/PT_LOAD markings",
460 "Print TEXTREL information", 1162 "Print TEXTREL information",
461 "Print RPATH information", 1163 "Print RPATH information",
462 "Print NEEDED information", 1164 "Print NEEDED information",
1165 "Resolve NEEDED information (use with -n)",
1166 "Print INTERP information",
1167 "Print BIND information",
1168 "Print SONAME information",
463 "Find a specified symbol", 1169 "Find a specified symbol",
1170 "Find a specified library",
1171 "Use strncmp to match libraries. (use with -N)",
1172 "Locate cause of TEXTREL",
464 "Print all scanned info (-x -e -t -r)\n", 1173 "Print all scanned info (-x -e -t -r -b)\n",
465 "Only output 'bad' things", 1174 "Only output 'bad' things",
466 "Be verbose (can be specified more than once)", 1175 "Be verbose (can be specified more than once)",
1176 "Use specified format for output",
1177 "Read input stream from a filename",
467 "Write output stream to a filename", 1178 "Write output stream to a filename",
468 "Don't display the header", 1179 "Don't display the header",
469 "Print this help and exit", 1180 "Print this help and exit",
470 "Print version and exit", 1181 "Print version and exit",
471 NULL 1182 NULL
472}; 1183};
473 1184
474/* display usage and exit */ 1185/* display usage and exit */
475static void usage(int status) 1186static void usage(int status)
476{ 1187{
477 int i; 1188 unsigned long i;
478 printf(" Scan ELF binaries for stuff\n" 1189 printf("* Scan ELF binaries for stuff\n\n"
479 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1190 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
480 printf("Options: -[%s]\n", PARSE_FLAGS); 1191 printf("Options: -[%s]\n", PARSE_FLAGS);
481 for (i = 0; long_opts[i].name; ++i) 1192 for (i = 0; long_opts[i].name; ++i)
482 if (long_opts[i].has_arg == no_argument) 1193 if (long_opts[i].has_arg == no_argument)
483 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1194 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
484 long_opts[i].name, opts_help[i]); 1195 long_opts[i].name, opts_help[i]);
485 else 1196 else
486 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1197 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
487 long_opts[i].name, opts_help[i]); 1198 long_opts[i].name, opts_help[i]);
1199
1200 if (status != EXIT_SUCCESS)
1201 exit(status);
1202
1203 puts("\nThe format modifiers for the -F option are:");
1204 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1205 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1206 puts(" i INTERP \tb BIND \ts symbol");
1207 puts(" N library \to Type \tT TEXTRELs");
1208 puts(" S SONAME");
1209 puts(" p filename (with search path removed)");
1210 puts(" f filename (short name/basename)");
1211 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1212
488 exit(status); 1213 exit(status);
489} 1214}
490 1215
491/* parse command line arguments and preform needed actions */ 1216/* parse command line arguments and preform needed actions */
492static void parseargs(int argc, char *argv[]) 1217static void parseargs(int argc, char *argv[])
493{ 1218{
494 int flag; 1219 int i;
1220 char *from_file = NULL;
495 1221
496 opterr = 0; 1222 opterr = 0;
497 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1223 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
498 switch (flag) { 1224 switch (i) {
499 1225
500 case 'V': /* version info */ 1226 case 'V':
501 printf("%s compiled %s\n%s\n" 1227 printf("pax-utils-%s: %s compiled %s\n%s\n"
502 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1228 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
503 __FILE__, __DATE__, rcsid, argv0); 1229 VERSION, __FILE__, __DATE__, rcsid, argv0);
504 exit(EXIT_SUCCESS); 1230 exit(EXIT_SUCCESS);
505 break; 1231 break;
506 case 'h': usage(EXIT_SUCCESS); break; 1232 case 'h': usage(EXIT_SUCCESS); break;
507 1233 case 'f':
1234 if (from_file) err("Don't specify -f twice");
1235 from_file = xstrdup(optarg);
1236 break;
508 case 'o': { 1237 case 'o': {
509 FILE *fp = NULL; 1238 FILE *fp = NULL;
510 fp = freopen(optarg, "w", stdout); 1239 if ((fp = freopen(optarg, "w", stdout)) == NULL)
511 if (fp == NULL)
512 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1240 err("Could not open output stream '%s': %s", optarg, strerror(errno));
513 stdout = fp; 1241 SET_STDOUT(fp);
514 break; 1242 break;
515 } 1243 }
516 1244
517 case 's': find_sym = strdup(optarg); break; 1245 case 's': {
1246 if (find_sym) warn("You prob don't want to specify -s twice");
1247 find_sym = optarg;
1248 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1249 sprintf(versioned_symname, "%s@", find_sym);
1250 break;
1251 }
1252 case 'N': {
1253 if (find_lib) warn("You prob don't want to specify -N twice");
1254 find_lib = optarg;
1255 break;
1256 }
518 1257
1258 case 'F': {
1259 if (out_format) warn("You prob don't want to specify -F twice");
1260 out_format = optarg;
1261 break;
1262 }
1263
1264 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */
1265 case 'L': printcache = 1; break;
1266 case 'y': scan_symlink = 0; break;
519 case 'B': show_banner = 0; break; 1267 case 'B': show_banner = 0; break;
520 case 'l': scan_ldpath = 1; break; 1268 case 'l': scan_ldpath = 1; break;
521 case 'p': scan_envpath = 1; break; 1269 case 'p': scan_envpath = 1; break;
522 case 'R': dir_recurse = 1; break; 1270 case 'R': dir_recurse = 1; break;
523 case 'm': dir_crossmount = 0; break; 1271 case 'm': dir_crossmount = 0; break;
524 case 'x': show_pax = 1; break; 1272 case 'x': show_pax = 1; break;
525 case 'e': show_stack = 1; break; 1273 case 'e': show_phdr = 1; break;
526 case 't': show_textrel = 1; break; 1274 case 't': show_textrel = 1; break;
527 case 'r': show_rpath = 1; break; 1275 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break; 1276 case 'n': show_needed = 1; break;
1277 case 'i': show_interp = 1; break;
1278 case 'b': show_bind = 1; break;
1279 case 'S': show_soname = 1; break;
1280 case 'T': show_textrels = 1; break;
529 case 'q': be_quiet = 1; break; 1281 case 'q': be_quiet = 1; break;
530 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1282 case 'v': be_verbose = (be_verbose % 20) + 1; break;
531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 1283 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
532 1284
533 case ':': 1285 case ':':
534 warn("Option missing parameter"); 1286 err("Option missing parameter\n");
535 usage(EXIT_FAILURE);
536 break;
537 case '?': 1287 case '?':
538 warn("Unknown option"); 1288 err("Unknown option\n");
539 usage(EXIT_FAILURE);
540 break;
541 default: 1289 default:
542 err("Unhandled option '%c'", flag); 1290 err("Unhandled option '%c'", i);
543 break;
544 } 1291 }
545 } 1292 }
546 1293
547 if (be_quiet && be_verbose) 1294 /* let the format option override all other options */
548 err("You can be quiet or you can be verbose, not both, stupid"); 1295 if (out_format) {
1296 show_pax = show_phdr = show_textrel = show_rpath = \
1297 show_needed = show_interp = show_bind = show_soname = \
1298 show_textrels = 0;
1299 for (i = 0; out_format[i]; ++i) {
1300 if (!IS_MODIFIER(out_format[i])) continue;
549 1301
1302 switch (out_format[++i]) {
1303 case '%': break;
1304 case '#': break;
1305 case 'F': break;
1306 case 'p': break;
1307 case 'f': break;
1308 case 's': break;
1309 case 'N': break;
1310 case 'o': break;
1311 case 'x': show_pax = 1; break;
1312 case 'e': show_phdr = 1; break;
1313 case 't': show_textrel = 1; break;
1314 case 'r': show_rpath = 1; break;
1315 case 'n': show_needed = 1; break;
1316 case 'i': show_interp = 1; break;
1317 case 'b': show_bind = 1; break;
1318 case 'S': show_soname = 1; break;
1319 case 'T': show_textrels = 1; break;
1320 default:
1321 err("Invalid format specifier '%c' (byte %i)",
1322 out_format[i], i+1);
1323 }
1324 }
1325
1326 /* construct our default format */
1327 } else {
1328 size_t fmt_len = 30;
1329 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1330 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1331 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1332 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1333 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1334 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1335 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1336 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1337 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1338 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1339 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1340 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1341 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1342 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1343 }
1344 if (be_verbose > 2) printf("Format: %s\n", out_format);
1345
1346 /* now lets actually do the scanning */
1347 if (scan_ldpath || (show_rpath && be_quiet))
1348 load_ld_so_conf();
550 if (scan_ldpath) scanelf_ldpath(); 1349 if (scan_ldpath) scanelf_ldpath();
551 if (scan_envpath) scanelf_envpath(); 1350 if (scan_envpath) scanelf_envpath();
1351 if (from_file) {
1352 scanelf_from_file(from_file);
1353 free(from_file);
1354 from_file = *argv;
1355 }
552 if (optind == argc && !scan_ldpath && !scan_envpath) 1356 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
553 err("Nothing to scan !?"); 1357 err("Nothing to scan !?");
554 while (optind < argc) 1358 while (optind < argc) {
555 scanelf_dir(argv[optind++]); 1359 search_path = argv[optind++];
1360 scanelf_dir(search_path);
1361 }
556 1362
557 if (find_sym) free(find_sym); 1363 /* clean up */
1364 if (versioned_symname) free(versioned_symname);
1365 for (i = 0; ldpaths[i]; ++i)
1366 free(ldpaths[i]);
1367
1368 if (ldcache != 0)
1369 munmap(ldcache, ldcache_size);
1370}
1371
1372
1373
1374/* utility funcs */
1375static char *xstrdup(const char *s)
1376{
1377 char *ret = strdup(s);
1378 if (!ret) err("Could not strdup(): %s", strerror(errno));
1379 return ret;
1380}
1381static void *xmalloc(size_t size)
1382{
1383 void *ret = malloc(size);
1384 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1385 return ret;
1386}
1387static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1388{
1389 size_t new_len;
1390
1391 new_len = strlen(*dst) + strlen(src);
1392 if (*curr_len <= new_len) {
1393 *curr_len = new_len + (*curr_len / 2);
1394 *dst = realloc(*dst, *curr_len);
1395 if (!*dst)
1396 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1397 }
1398
1399 if (n)
1400 strncat(*dst, src, n);
1401 else
1402 strcat(*dst, src);
1403}
1404static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1405{
1406 static char my_app[2];
1407 my_app[0] = append;
1408 my_app[1] = '\0';
1409 xstrcat(dst, my_app, curr_len);
558} 1410}
559 1411
560 1412
561 1413
562int main(int argc, char *argv[]) 1414int main(int argc, char *argv[])
563{ 1415{
564 if (argc < 2) 1416 if (argc < 2)
565 usage(EXIT_FAILURE); 1417 usage(EXIT_FAILURE);
566 parseargs(argc, argv); 1418 parseargs(argc, argv);
567 fclose(stdout); 1419 fclose(stdout);
1420#ifdef __BOUNDS_CHECKING_ON
1421 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1422#endif
568 return EXIT_SUCCESS; 1423 return EXIT_SUCCESS;
569} 1424}

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.97

  ViewVC Help
Powered by ViewVC 1.1.20