/[gentoo-projects]/pax-utils/scanelf.c
Gentoo

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

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

  ViewVC Help
Powered by ViewVC 1.1.20