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

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.119

  ViewVC Help
Powered by ViewVC 1.1.20