/[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.96
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.96 2005/12/28 22:26:47 solar 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.96 2005/12/28 22:26:47 solar 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
494static char *lookup_cache_lib(char *);
495static char *lookup_cache_lib(char *fname)
496{
497 int fd = 0;
498 char *strs;
499 static char buf[_POSIX_PATH_MAX] = "";
500 const char *cachefile = "/etc/ld.so.cache";
501 struct stat st;
502
503 typedef struct {
504 char magic[LDSO_CACHE_MAGIC_LEN];
505 char version[LDSO_CACHE_VER_LEN];
506 int nlibs;
507 } header_t;
508
509 typedef struct {
510 int flags;
511 int sooffset;
512 int liboffset;
513 } libentry_t;
514
515 header_t *header;
516 libentry_t *libent;
517
518 if (fname == NULL)
519 return NULL;
520
521 if (ldcache == 0) {
522 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) < 0)
523 return NULL;
524 /* save the cache size for latter unmapping */
525 ldcache_size = st.st_size;
526
527 if ((ldcache = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) -1)
528 return NULL;
529
530 close(fd);
531
532 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
533 return NULL;
534
535 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
536 return NULL;
537 }
538
539 header = (header_t *) ldcache;
540 libent = (libentry_t *) (ldcache + sizeof(header_t));
541 strs = (char *) &libent[header->nlibs];
542
543 for (fd = 0; fd < header->nlibs; fd++) {
544 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
545 continue;
546 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
547 }
548 return buf;
549}
550
551
552static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
553{
554 unsigned long i;
227 char *needed; 555 char *needed;
556 void *strtbl_void;
557 char *p;
558
559 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
560
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 561 strtbl_void = elf_findsecbyname(elf, ".dynstr");
229 562
230 if (strtbl_void) { 563 if (elf->phdr && strtbl_void) {
231#define SHOW_NEEDED(B) \ 564#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \ 565 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \ 566 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 567 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 568 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 569 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
570 Elf ## B ## _Off offset; \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 571 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; \ 572 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
573 offset = EGET(phdr[i].p_offset); \
574 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 575 dyn = DYN ## B (elf->data + offset); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \ 576 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 577 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 578 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
248 if (found_needed) printf(","); \ 579 if (offset >= (Elf ## B ## _Off)elf->len) { \
249 printf("%s", needed); \ 580 ++dyn; \
581 continue; \
582 } \
583 needed = (char*)(elf->data + offset); \
584 if (op == 0) { \
585 if (!be_wewy_wewy_quiet) { \
586 if (*found_needed) xchrcat(ret, ',', ret_len); \
587 if (printcache) \
588 if ((p = lookup_cache_lib(needed)) != NULL) \
589 needed = p; \
590 xstrcat(ret, needed, ret_len); \
591 } \
250 found_needed = 1; \ 592 *found_needed = 1; \
593 } else { \
594 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
595 *found_lib = 1; \
596 return (be_wewy_wewy_quiet ? NULL : needed); \
597 } \
598 } \
251 } \ 599 } \
252 ++dyn; \ 600 ++dyn; \
253 } \ 601 } \
254 } } 602 } }
255 SHOW_NEEDED(32) 603 SHOW_NEEDED(32)
256 SHOW_NEEDED(64) 604 SHOW_NEEDED(64)
605 if (op == 0 && !*found_needed && be_verbose)
606 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
607 }
608
609 return NULL;
610}
611static char *scanelf_file_interp(elfobj *elf, char *found_interp)
612{
613 void *strtbl_void;
614
615 if (!show_interp) return NULL;
616
617 strtbl_void = elf_findsecbyname(elf, ".interp");
618
619 if (strtbl_void) {
620#define SHOW_INTERP(B) \
621 if (elf->elf_class == ELFCLASS ## B) { \
622 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
623 *found_interp = 1; \
624 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
257 } 625 }
258 if (!be_quiet && !found_needed) 626 SHOW_INTERP(32)
259 printf(" - "); 627 SHOW_INTERP(64)
260 else if (found_needed)
261 printf(" ");
262 } 628 }
629 return NULL;
630}
631static char *scanelf_file_bind(elfobj *elf, char *found_bind)
632{
633 unsigned long i;
634 struct stat s;
263 635
264 /* search the symbol table for a specified symbol */ 636 if (!show_bind) return NULL;
265 if (find_sym) { 637 if (!elf->phdr) return NULL;
638
639#define SHOW_BIND(B) \
640 if (elf->elf_class == ELFCLASS ## B) { \
641 Elf ## B ## _Dyn *dyn; \
642 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
643 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
644 Elf ## B ## _Off offset; \
645 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
646 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
647 offset = EGET(phdr[i].p_offset); \
648 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
649 dyn = DYN ## B (elf->data + offset); \
650 while (EGET(dyn->d_tag) != DT_NULL) { \
651 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
652 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
653 { \
654 if (be_quiet) return NULL; \
655 *found_bind = 1; \
656 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
657 } \
658 ++dyn; \
659 } \
660 } \
661 }
662 SHOW_BIND(32)
663 SHOW_BIND(64)
664
665 if (be_wewy_wewy_quiet) return NULL;
666
667 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
668 return NULL;
669 } else {
670 *found_bind = 1;
671 return (char *) "LAZY";
672 }
673}
674static char *scanelf_file_soname(elfobj *elf, char *found_soname)
675{
676 unsigned long i;
677 char *soname;
678 void *strtbl_void;
679
680 if (!show_soname) return NULL;
681
682 strtbl_void = elf_findsecbyname(elf, ".dynstr");
683
684 if (elf->phdr && strtbl_void) {
685#define SHOW_SONAME(B) \
686 if (elf->elf_class == ELFCLASS ## B) { \
687 Elf ## B ## _Dyn *dyn; \
688 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
689 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
690 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
691 Elf ## B ## _Off offset; \
692 /* only look for soname in shared objects */ \
693 if (ehdr->e_type != ET_DYN) \
694 return NULL; \
695 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
696 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
697 offset = EGET(phdr[i].p_offset); \
698 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
699 dyn = DYN ## B (elf->data + offset); \
700 while (EGET(dyn->d_tag) != DT_NULL) { \
701 if (EGET(dyn->d_tag) == DT_SONAME) { \
702 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
703 if (offset >= (Elf ## B ## _Off)elf->len) { \
704 ++dyn; \
705 continue; \
706 } \
707 soname = (char*)(elf->data + offset); \
708 *found_soname = 1; \
709 return (be_wewy_wewy_quiet ? NULL : soname); \
710 } \
711 ++dyn; \
712 } \
713 } }
714 SHOW_SONAME(32)
715 SHOW_SONAME(64)
716 }
717
718 return NULL;
719}
720static char *scanelf_file_sym(elfobj *elf, char *found_sym)
721{
722 unsigned long i;
723 char *ret;
266 void *symtab_void, *strtab_void; 724 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269 725
270 len = strlen(find_sym) + 1; 726 if (!find_sym) return NULL;
271 versioned_symname = (char *)malloc(sizeof(char) * (len+1)); 727 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 728
278 symtab_void = elf_findsecbyname(elf, ".symtab"); 729 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
279 strtab_void = elf_findsecbyname(elf, ".strtab");
280 730
281 if (symtab_void && strtab_void) { 731 if (symtab_void && strtab_void) {
282#define FIND_SYM(B) \ 732#define FIND_SYM(B) \
283 if (elf->elf_class == ELFCLASS ## B) { \ 733 if (elf->elf_class == ELFCLASS ## B) { \
284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 734 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 735 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
286 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 736 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
287 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 737 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
288 char *symname; \ 738 char *symname; \
289 for (i = 0; i < cnt; ++i) { \ 739 for (i = 0; i < cnt; ++i) { \
290 if (sym->st_name) { \ 740 if (sym->st_name) { \
291 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 741 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
292 if (*find_sym == '*') { \ 742 if (*find_sym == '*') { \
293 printf("%s(%s) %5lX %15s %s\n", \ 743 printf("%s(%s) %5lX %15s %s\n", \
294 ((found_sym == 0) ? "\n\t" : "\t"), \ 744 ((*found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \ 745 elf->base_filename, \
296 (long)sym->st_size, \ 746 (unsigned long)sym->st_size, \
297 (char *)get_elfstttype(sym->st_info), \ 747 get_elfstttype(sym->st_info), \
298 symname); \ 748 symname); \
299 found_sym = 1; \ 749 *found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \ 750 } else { \
751 char *this_sym, *next_sym; \
752 this_sym = find_sym; \
753 do { \
754 next_sym = strchr(this_sym, ','); \
755 if (next_sym == NULL) \
756 next_sym = this_sym + strlen(this_sym); \
757 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
301 (strncmp(symname, versioned_symname, len) == 0)) \ 758 (strcmp(symname, versioned_symname) == 0)) { \
759 ret = this_sym; \
302 found_sym++; \ 760 (*found_sym)++; \
761 goto break_out; \
762 } \
763 this_sym = next_sym + 1; \
764 } while (*next_sym != '\0'); \
765 } \
303 } \ 766 } \
304 ++sym; \ 767 ++sym; \
305 } } 768 } }
306 FIND_SYM(32) 769 FIND_SYM(32)
307 FIND_SYM(64) 770 FIND_SYM(64)
771 }
772
773break_out:
774 if (be_wewy_wewy_quiet) return NULL;
775
776 if (*find_sym != '*' && *found_sym)
777 return ret;
778 if (be_quiet)
779 return NULL;
780 else
781 return (char *)" - ";
782}
783/* scan an elf file and show all the fun stuff */
784#define prints(str) write(fileno(stdout), str, strlen(str))
785static void scanelf_file(const char *filename)
786{
787 unsigned long i;
788 char found_pax, found_phdr, found_relro, found_load, found_textrel,
789 found_rpath, found_needed, found_interp, found_bind, found_soname,
790 found_sym, found_lib, found_file, found_textrels;
791 elfobj *elf;
792 struct stat st;
793 static char *out_buffer = NULL;
794 static size_t out_len;
795
796 /* make sure 'filename' exists */
797 if (lstat(filename, &st) == -1) {
798 if (be_verbose > 2) printf("%s: does not exist\n", filename);
799 return;
800 }
801 /* always handle regular files and handle symlinked files if no -y */
802 if (S_ISLNK(st.st_mode)) {
803 if (!scan_symlink) return;
804 stat(filename, &st);
805 }
806 if (!S_ISREG(st.st_mode)) {
807 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
808 return;
809 }
810
811 found_pax = found_phdr = found_relro = found_load = found_textrel = \
812 found_rpath = found_needed = found_interp = found_bind = found_soname = \
813 found_sym = found_lib = found_file = found_textrels = 0;
814
815 /* verify this is real ELF */
816 if ((elf = readelf(filename)) == NULL) {
817 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
818 return;
819 }
820
821 if (be_verbose > 1)
822 printf("%s: scanning file {%s,%s}\n", filename,
823 get_elfeitype(EI_CLASS, elf->elf_class),
824 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
825 else if (be_verbose)
826 printf("%s: scanning file\n", filename);
827
828 /* init output buffer */
829 if (!out_buffer) {
830 out_len = sizeof(char) * 80;
831 out_buffer = (char*)xmalloc(out_len);
832 }
833 *out_buffer = '\0';
834
835 /* show the header */
836 if (!be_quiet && show_banner) {
837 for (i = 0; out_format[i]; ++i) {
838 if (!IS_MODIFIER(out_format[i])) continue;
839
840 switch (out_format[++i]) {
841 case '%': break;
842 case '#': break;
843 case 'F':
844 case 'p':
845 case 'f': prints("FILE "); found_file = 1; break;
846 case 'o': prints(" TYPE "); break;
847 case 'x': prints(" PAX "); break;
848 case 'e': prints("STK/REL/PTL "); break;
849 case 't': prints("TEXTREL "); break;
850 case 'r': prints("RPATH "); break;
851 case 'n': prints("NEEDED "); break;
852 case 'i': prints("INTERP "); break;
853 case 'b': prints("BIND "); break;
854 case 'S': prints("SONAME "); break;
855 case 's': prints("SYM "); break;
856 case 'N': prints("LIB "); break;
857 case 'T': prints("TEXTRELS "); break;
858 default: warnf("'%c' has no title ?", out_format[i]);
859 }
308 } 860 }
309 free(versioned_symname); 861 if (!found_file) prints("FILE ");
310 if (*find_sym != '*') { 862 prints("\n");
311 if (found_sym) 863 found_file = 0;
312 printf(" %s ", find_sym); 864 show_banner = 0;
313 else if (!be_quiet) 865 }
314 fputs(" - ", stdout); 866
867 /* dump all the good stuff */
868 for (i = 0; out_format[i]; ++i) {
869 const char *out;
870 const char *tmp;
871
872 /* make sure we trim leading spaces in quiet mode */
873 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
874 *out_buffer = '\0';
875
876 if (!IS_MODIFIER(out_format[i])) {
877 xchrcat(&out_buffer, out_format[i], &out_len);
878 continue;
315 } 879 }
880
881 out = NULL;
882 be_wewy_wewy_quiet = (out_format[i] == '#');
883 switch (out_format[++i]) {
884 case '%':
885 case '#':
886 xchrcat(&out_buffer, out_format[i], &out_len); break;
887 case 'F':
888 found_file = 1;
889 if (be_wewy_wewy_quiet) break;
890 xstrcat(&out_buffer, filename, &out_len);
891 break;
892 case 'p':
893 found_file = 1;
894 if (be_wewy_wewy_quiet) break;
895 tmp = filename;
896 if (search_path) {
897 ssize_t len_search = strlen(search_path);
898 ssize_t len_file = strlen(filename);
899 if (!strncmp(filename, search_path, len_search) && \
900 len_file > len_search)
901 tmp += len_search;
902 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
903 }
904 xstrcat(&out_buffer, tmp, &out_len);
905 break;
906 case 'f':
907 found_file = 1;
908 if (be_wewy_wewy_quiet) break;
909 tmp = strrchr(filename, '/');
910 tmp = (tmp == NULL ? filename : tmp+1);
911 xstrcat(&out_buffer, tmp, &out_len);
912 break;
913 case 'o': out = get_elfetype(elf); break;
914 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
915 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
916 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
917 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
918 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
919 case 'n':
920 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
921 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
922 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
923 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
924 case 's': out = scanelf_file_sym(elf, &found_sym); break;
925 default: warnf("'%c' has no scan code?", out_format[i]);
316 } 926 }
927 if (out) {
928 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
929 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
930 xstrncat(&out_buffer, out, &out_len, (tmp-out));
931 else
932 xstrcat(&out_buffer, out, &out_len);
933 }
934 }
317 935
318 if (!be_quiet || found_pax || found_stack || found_textrel || \ 936#define FOUND_SOMETHING() \
319 found_rpath || found_needed || found_sym) 937 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
320 puts(filename); 938 found_rpath || found_needed || found_interp || found_bind || \
939 found_soname || found_sym || found_lib || found_textrels)
940
941 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
942 xchrcat(&out_buffer, ' ', &out_len);
943 xstrcat(&out_buffer, filename, &out_len);
944 }
945 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
946 puts(out_buffer);
947 fflush(stdout);
948 }
321 949
322 unreadelf(elf); 950 unreadelf(elf);
323} 951}
324 952
325/* scan a directory for ET_EXEC files and print when we find one */ 953/* scan a directory for ET_EXEC files and print when we find one */
330 struct stat st_top, st; 958 struct stat st_top, st;
331 char buf[_POSIX_PATH_MAX]; 959 char buf[_POSIX_PATH_MAX];
332 size_t pathlen = 0, len = 0; 960 size_t pathlen = 0, len = 0;
333 961
334 /* make sure path exists */ 962 /* make sure path exists */
335 if (lstat(path, &st_top) == -1) 963 if (lstat(path, &st_top) == -1) {
964 if (be_verbose > 2) printf("%s: does not exist\n", path);
336 return; 965 return;
966 }
337 967
338 /* ok, if it isn't a directory, assume we can open it */ 968 /* ok, if it isn't a directory, assume we can open it */
339 if (!S_ISDIR(st_top.st_mode)) { 969 if (!S_ISDIR(st_top.st_mode)) {
340 scanelf_file(path); 970 scanelf_file(path);
341 return; 971 return;
352 while ((dentry = readdir(dir))) { 982 while ((dentry = readdir(dir))) {
353 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 983 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
354 continue; 984 continue;
355 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 985 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
356 if (len >= sizeof(buf)) { 986 if (len >= sizeof(buf)) {
357 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 987 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
988 (unsigned long)len, (unsigned long)sizeof(buf));
358 continue; 989 continue;
359 } 990 }
360 sprintf(buf, "%s/%s", path, dentry->d_name); 991 sprintf(buf, "%s/%s", path, dentry->d_name);
361 if (lstat(buf, &st) != -1) { 992 if (lstat(buf, &st) != -1) {
362 if (S_ISREG(st.st_mode)) 993 if (S_ISREG(st.st_mode))
368 } 999 }
369 } 1000 }
370 closedir(dir); 1001 closedir(dir);
371} 1002}
372 1003
1004static int scanelf_from_file(char *filename)
1005{
1006 FILE *fp = NULL;
1007 char *p;
1008 char path[_POSIX_PATH_MAX];
1009
1010 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
1011 fp = stdin;
1012 else if ((fp = fopen(filename, "r")) == NULL)
1013 return 1;
1014
1015 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
1016 if ((p = strchr(path, '\n')) != NULL)
1017 *p = 0;
1018 search_path = path;
1019 scanelf_dir(path);
1020 }
1021 if (fp != stdin)
1022 fclose(fp);
1023 return 0;
1024}
1025
1026static void load_ld_so_conf()
1027{
1028 FILE *fp = NULL;
1029 char *p;
1030 char path[_POSIX_PATH_MAX];
1031 int i = 0;
1032
1033 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
1034 return;
1035
1036 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
1037 if (*path != '/')
1038 continue;
1039
1040 if ((p = strrchr(path, '\r')) != NULL)
1041 *p = 0;
1042 if ((p = strchr(path, '\n')) != NULL)
1043 *p = 0;
1044
1045 ldpaths[i++] = xstrdup(path);
1046
1047 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1048 break;
1049 }
1050 ldpaths[i] = NULL;
1051
1052 fclose(fp);
1053}
1054
373/* scan /etc/ld.so.conf for paths */ 1055/* scan /etc/ld.so.conf for paths */
374static void scanelf_ldpath() 1056static void scanelf_ldpath()
375{ 1057{
376 char scan_l, scan_ul, scan_ull; 1058 char scan_l, scan_ul, scan_ull;
377 char *path, *p; 1059 int i = 0;
378 FILE *fp;
379 1060
380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1061 if (!ldpaths[0])
381 err("Unable to open ld.so.conf: %s", strerror(errno)); 1062 err("Unable to load any paths from ld.so.conf");
382 1063
383 scan_l = scan_ul = scan_ull = 0; 1064 scan_l = scan_ul = scan_ull = 0;
384 1065
385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 1066 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; 1067 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
396 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 1068 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
397 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 1069 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
398 scanelf_dir(path); 1070 scanelf_dir(ldpaths[i]);
1071 ++i;
399 } 1072 }
400 free(path);
401 fclose(fp);
402 1073
403 if (!scan_l) scanelf_dir("/lib"); 1074 if (!scan_l) scanelf_dir("/lib");
404 if (!scan_ul) scanelf_dir("/usr/lib"); 1075 if (!scan_ul) scanelf_dir("/usr/lib");
405 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1076 if (!scan_ull) scanelf_dir("/usr/local/lib");
406} 1077}
411 char *path, *p; 1082 char *path, *p;
412 1083
413 path = getenv("PATH"); 1084 path = getenv("PATH");
414 if (!path) 1085 if (!path)
415 err("PATH is not set in your env !"); 1086 err("PATH is not set in your env !");
416 1087 path = xstrdup(path);
417 if ((path = strdup(path)) == NULL)
418 err("strdup failed: %s", strerror(errno));
419 1088
420 while ((p = strrchr(path, ':')) != NULL) { 1089 while ((p = strrchr(path, ':')) != NULL) {
421 scanelf_dir(p + 1); 1090 scanelf_dir(p + 1);
422 *p = 0; 1091 *p = 0;
423 } 1092 }
424 1093
425 free(path); 1094 free(path);
426} 1095}
427 1096
428 1097
429
430/* usage / invocation handling functions */ 1098/* usage / invocation handling functions */
431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV" 1099#define PARSE_FLAGS "plRmyxetrnLibSs:gN:TaqvF:f:o:BhV"
432#define a_argument required_argument 1100#define a_argument required_argument
433static struct option const long_opts[] = { 1101static struct option const long_opts[] = {
434 {"path", no_argument, NULL, 'p'}, 1102 {"path", no_argument, NULL, 'p'},
435 {"ldpath", no_argument, NULL, 'l'}, 1103 {"ldpath", no_argument, NULL, 'l'},
436 {"recursive", no_argument, NULL, 'R'}, 1104 {"recursive", no_argument, NULL, 'R'},
437 {"mount", no_argument, NULL, 'm'}, 1105 {"mount", no_argument, NULL, 'm'},
1106 {"symlink", no_argument, NULL, 'y'},
438 {"pax", no_argument, NULL, 'x'}, 1107 {"pax", no_argument, NULL, 'x'},
439 {"header", no_argument, NULL, 'e'}, 1108 {"header", no_argument, NULL, 'e'},
440 {"textrel", no_argument, NULL, 't'}, 1109 {"textrel", no_argument, NULL, 't'},
441 {"rpath", no_argument, NULL, 'r'}, 1110 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'}, 1111 {"needed", no_argument, NULL, 'n'},
1112 {"ldcache", no_argument, NULL, 'L'},
1113 {"interp", no_argument, NULL, 'i'},
1114 {"bind", no_argument, NULL, 'b'},
1115 {"soname", no_argument, NULL, 'S'},
443 {"symbol", a_argument, NULL, 's'}, 1116 {"symbol", a_argument, NULL, 's'},
1117 {"lib", a_argument, NULL, 'N'},
1118 {"gmatch", no_argument, NULL, 'g'},
1119 {"textrels", no_argument, NULL, 'T'},
444 {"all", no_argument, NULL, 'a'}, 1120 {"all", no_argument, NULL, 'a'},
445 {"quiet", no_argument, NULL, 'q'}, 1121 {"quiet", no_argument, NULL, 'q'},
446 {"verbose", no_argument, NULL, 'v'}, 1122 {"verbose", no_argument, NULL, 'v'},
1123 {"format", a_argument, NULL, 'F'},
1124 {"from", a_argument, NULL, 'f'},
447 {"file", a_argument, NULL, 'o'}, 1125 {"file", a_argument, NULL, 'o'},
448 {"nobanner", no_argument, NULL, 'B'}, 1126 {"nobanner", no_argument, NULL, 'B'},
449 {"help", no_argument, NULL, 'h'}, 1127 {"help", no_argument, NULL, 'h'},
450 {"version", no_argument, NULL, 'V'}, 1128 {"version", no_argument, NULL, 'V'},
451 {NULL, no_argument, NULL, 0x0} 1129 {NULL, no_argument, NULL, 0x0}
452}; 1130};
1131
453static char *opts_help[] = { 1132static const char *opts_help[] = {
454 "Scan all directories in PATH environment", 1133 "Scan all directories in PATH environment",
455 "Scan all directories in /etc/ld.so.conf", 1134 "Scan all directories in /etc/ld.so.conf",
456 "Scan directories recursively", 1135 "Scan directories recursively",
457 "Don't recursively cross mount points\n", 1136 "Don't recursively cross mount points",
1137 "Don't scan symlinks\n",
458 "Print PaX markings", 1138 "Print PaX markings",
459 "Print GNU_STACK markings", 1139 "Print GNU_STACK/PT_LOAD markings",
460 "Print TEXTREL information", 1140 "Print TEXTREL information",
461 "Print RPATH information", 1141 "Print RPATH information",
462 "Print NEEDED information", 1142 "Print NEEDED information",
1143 "Resolve NEEDED information (use with -n)",
1144 "Print INTERP information",
1145 "Print BIND information",
1146 "Print SONAME information",
463 "Find a specified symbol", 1147 "Find a specified symbol",
1148 "Find a specified library",
1149 "Use strncmp to match libraries. (use with -N)",
1150 "Locate cause of TEXTREL",
464 "Print all scanned info (-x -e -t -r)\n", 1151 "Print all scanned info (-x -e -t -r -b)\n",
465 "Only output 'bad' things", 1152 "Only output 'bad' things",
466 "Be verbose (can be specified more than once)", 1153 "Be verbose (can be specified more than once)",
1154 "Use specified format for output",
1155 "Read input stream from a filename",
467 "Write output stream to a filename", 1156 "Write output stream to a filename",
468 "Don't display the header", 1157 "Don't display the header",
469 "Print this help and exit", 1158 "Print this help and exit",
470 "Print version and exit", 1159 "Print version and exit",
471 NULL 1160 NULL
472}; 1161};
473 1162
474/* display usage and exit */ 1163/* display usage and exit */
475static void usage(int status) 1164static void usage(int status)
476{ 1165{
477 int i; 1166 unsigned long i;
478 printf(" Scan ELF binaries for stuff\n" 1167 printf("* Scan ELF binaries for stuff\n\n"
479 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1168 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
480 printf("Options: -[%s]\n", PARSE_FLAGS); 1169 printf("Options: -[%s]\n", PARSE_FLAGS);
481 for (i = 0; long_opts[i].name; ++i) 1170 for (i = 0; long_opts[i].name; ++i)
482 if (long_opts[i].has_arg == no_argument) 1171 if (long_opts[i].has_arg == no_argument)
483 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1172 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
484 long_opts[i].name, opts_help[i]); 1173 long_opts[i].name, opts_help[i]);
485 else 1174 else
486 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1175 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
487 long_opts[i].name, opts_help[i]); 1176 long_opts[i].name, opts_help[i]);
1177
1178 if (status != EXIT_SUCCESS)
1179 exit(status);
1180
1181 puts("\nThe format modifiers for the -F option are:");
1182 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1183 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1184 puts(" i INTERP \tb BIND \ts symbol");
1185 puts(" N library \to Type \tT TEXTRELs");
1186 puts(" S SONAME");
1187 puts(" p filename (with search path removed)");
1188 puts(" f filename (short name/basename)");
1189 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1190
488 exit(status); 1191 exit(status);
489} 1192}
490 1193
491/* parse command line arguments and preform needed actions */ 1194/* parse command line arguments and preform needed actions */
492static void parseargs(int argc, char *argv[]) 1195static void parseargs(int argc, char *argv[])
493{ 1196{
494 int flag; 1197 int i;
1198 char *from_file = NULL;
495 1199
496 opterr = 0; 1200 opterr = 0;
497 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1201 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
498 switch (flag) { 1202 switch (i) {
499 1203
500 case 'V': /* version info */ 1204 case 'V':
501 printf("%s compiled %s\n%s\n" 1205 printf("pax-utils-%s: %s compiled %s\n%s\n"
502 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1206 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
503 __FILE__, __DATE__, rcsid, argv0); 1207 VERSION, __FILE__, __DATE__, rcsid, argv0);
504 exit(EXIT_SUCCESS); 1208 exit(EXIT_SUCCESS);
505 break; 1209 break;
506 case 'h': usage(EXIT_SUCCESS); break; 1210 case 'h': usage(EXIT_SUCCESS); break;
507 1211 case 'f':
1212 if (from_file) err("Don't specify -f twice");
1213 from_file = xstrdup(optarg);
1214 break;
508 case 'o': { 1215 case 'o': {
509 FILE *fp = NULL; 1216 FILE *fp = NULL;
510 fp = freopen(optarg, "w", stdout); 1217 if ((fp = freopen(optarg, "w", stdout)) == NULL)
511 if (fp == NULL)
512 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1218 err("Could not open output stream '%s': %s", optarg, strerror(errno));
513 stdout = fp; 1219 SET_STDOUT(fp);
514 break; 1220 break;
515 } 1221 }
516 1222
517 case 's': find_sym = strdup(optarg); break; 1223 case 's': {
1224 if (find_sym) warn("You prob don't want to specify -s twice");
1225 find_sym = optarg;
1226 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1227 sprintf(versioned_symname, "%s@", find_sym);
1228 break;
1229 }
1230 case 'N': {
1231 if (find_lib) warn("You prob don't want to specify -N twice");
1232 find_lib = optarg;
1233 break;
1234 }
518 1235
1236 case 'F': {
1237 if (out_format) warn("You prob don't want to specify -F twice");
1238 out_format = optarg;
1239 break;
1240 }
1241
1242 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */
1243 case 'L': printcache = 1; break;
1244 case 'y': scan_symlink = 0; break;
519 case 'B': show_banner = 0; break; 1245 case 'B': show_banner = 0; break;
520 case 'l': scan_ldpath = 1; break; 1246 case 'l': scan_ldpath = 1; break;
521 case 'p': scan_envpath = 1; break; 1247 case 'p': scan_envpath = 1; break;
522 case 'R': dir_recurse = 1; break; 1248 case 'R': dir_recurse = 1; break;
523 case 'm': dir_crossmount = 0; break; 1249 case 'm': dir_crossmount = 0; break;
524 case 'x': show_pax = 1; break; 1250 case 'x': show_pax = 1; break;
525 case 'e': show_stack = 1; break; 1251 case 'e': show_phdr = 1; break;
526 case 't': show_textrel = 1; break; 1252 case 't': show_textrel = 1; break;
527 case 'r': show_rpath = 1; break; 1253 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break; 1254 case 'n': show_needed = 1; break;
1255 case 'i': show_interp = 1; break;
1256 case 'b': show_bind = 1; break;
1257 case 'S': show_soname = 1; break;
1258 case 'T': show_textrels = 1; break;
529 case 'q': be_quiet = 1; break; 1259 case 'q': be_quiet = 1; break;
530 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1260 case 'v': be_verbose = (be_verbose % 20) + 1; break;
531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 1261 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
532 1262
533 case ':': 1263 case ':':
534 warn("Option missing parameter"); 1264 err("Option missing parameter\n");
535 usage(EXIT_FAILURE);
536 break;
537 case '?': 1265 case '?':
538 warn("Unknown option"); 1266 err("Unknown option\n");
539 usage(EXIT_FAILURE);
540 break;
541 default: 1267 default:
542 err("Unhandled option '%c'", flag); 1268 err("Unhandled option '%c'", i);
543 break;
544 } 1269 }
545 } 1270 }
546 1271
547 if (be_quiet && be_verbose) 1272 /* let the format option override all other options */
548 err("You can be quiet or you can be verbose, not both, stupid"); 1273 if (out_format) {
1274 show_pax = show_phdr = show_textrel = show_rpath = \
1275 show_needed = show_interp = show_bind = show_soname = \
1276 show_textrels = 0;
1277 for (i = 0; out_format[i]; ++i) {
1278 if (!IS_MODIFIER(out_format[i])) continue;
549 1279
1280 switch (out_format[++i]) {
1281 case '%': break;
1282 case '#': break;
1283 case 'F': break;
1284 case 'p': break;
1285 case 'f': break;
1286 case 's': break;
1287 case 'N': break;
1288 case 'o': break;
1289 case 'x': show_pax = 1; break;
1290 case 'e': show_phdr = 1; break;
1291 case 't': show_textrel = 1; break;
1292 case 'r': show_rpath = 1; break;
1293 case 'n': show_needed = 1; break;
1294 case 'i': show_interp = 1; break;
1295 case 'b': show_bind = 1; break;
1296 case 'S': show_soname = 1; break;
1297 case 'T': show_textrels = 1; break;
1298 default:
1299 err("Invalid format specifier '%c' (byte %i)",
1300 out_format[i], i+1);
1301 }
1302 }
1303
1304 /* construct our default format */
1305 } else {
1306 size_t fmt_len = 30;
1307 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1308 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1309 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1310 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1311 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1312 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1313 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1314 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1315 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1316 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1317 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1318 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1319 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1320 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1321 }
1322 if (be_verbose > 2) printf("Format: %s\n", out_format);
1323
1324 /* now lets actually do the scanning */
1325 if (scan_ldpath || (show_rpath && be_quiet))
1326 load_ld_so_conf();
550 if (scan_ldpath) scanelf_ldpath(); 1327 if (scan_ldpath) scanelf_ldpath();
551 if (scan_envpath) scanelf_envpath(); 1328 if (scan_envpath) scanelf_envpath();
1329 if (from_file) {
1330 scanelf_from_file(from_file);
1331 free(from_file);
1332 from_file = *argv;
1333 }
552 if (optind == argc && !scan_ldpath && !scan_envpath) 1334 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
553 err("Nothing to scan !?"); 1335 err("Nothing to scan !?");
554 while (optind < argc) 1336 while (optind < argc) {
555 scanelf_dir(argv[optind++]); 1337 search_path = argv[optind++];
1338 scanelf_dir(search_path);
1339 }
556 1340
557 if (find_sym) free(find_sym); 1341 /* clean up */
1342 if (versioned_symname) free(versioned_symname);
1343 for (i = 0; ldpaths[i]; ++i)
1344 free(ldpaths[i]);
1345
1346 if (ldcache != 0)
1347 munmap(ldcache, ldcache_size);
1348}
1349
1350
1351
1352/* utility funcs */
1353static char *xstrdup(const char *s)
1354{
1355 char *ret = strdup(s);
1356 if (!ret) err("Could not strdup(): %s", strerror(errno));
1357 return ret;
1358}
1359static void *xmalloc(size_t size)
1360{
1361 void *ret = malloc(size);
1362 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1363 return ret;
1364}
1365static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1366{
1367 size_t new_len;
1368
1369 new_len = strlen(*dst) + strlen(src);
1370 if (*curr_len <= new_len) {
1371 *curr_len = new_len + (*curr_len / 2);
1372 *dst = realloc(*dst, *curr_len);
1373 if (!*dst)
1374 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1375 }
1376
1377 if (n)
1378 strncat(*dst, src, n);
1379 else
1380 strcat(*dst, src);
1381}
1382static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1383{
1384 static char my_app[2];
1385 my_app[0] = append;
1386 my_app[1] = '\0';
1387 xstrcat(dst, my_app, curr_len);
558} 1388}
559 1389
560 1390
561 1391
562int main(int argc, char *argv[]) 1392int main(int argc, char *argv[])
563{ 1393{
564 if (argc < 2) 1394 if (argc < 2)
565 usage(EXIT_FAILURE); 1395 usage(EXIT_FAILURE);
566 parseargs(argc, argv); 1396 parseargs(argc, argv);
567 fclose(stdout); 1397 fclose(stdout);
1398#ifdef __BOUNDS_CHECKING_ON
1399 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1400#endif
568 return EXIT_SUCCESS; 1401 return EXIT_SUCCESS;
569} 1402}

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

  ViewVC Help
Powered by ViewVC 1.1.20