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

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.98

  ViewVC Help
Powered by ViewVC 1.1.20