/[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.43 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.43 2005/05/06 02:55:27 vapier 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.43 2005/05/06 02:55:27 vapier Exp $"; 12static const char *rcsid = "$Id: scanelf.c,v 1.99 2006/01/10 01:35:06 vapier Exp $";
39#define argv0 "scanelf" 13#define argv0 "scanelf"
14
15#define IS_MODIFIER(c) (c == '%' || c == '#')
40 16
41 17
42 18
43/* prototypes */ 19/* prototypes */
44static void scanelf_file(const char *filename); 20static void scanelf_file(const char *filename);
45static void scanelf_dir(const char *path); 21static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 22static void scanelf_ldpath();
47static void scanelf_envpath(); 23static void scanelf_envpath();
48static void usage(int status); 24static void usage(int status);
49static void parseargs(int argc, char *argv[]); 25static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 26static char *xstrdup(const char *s);
51static void *xmalloc(size_t size); 27static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 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)
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 30static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
55 31
56/* variables to control behavior */ 32/* variables to control behavior */
33static char *ldpaths[256];
57static char scan_ldpath = 0; 34static char scan_ldpath = 0;
58static char scan_envpath = 0; 35static char scan_envpath = 0;
59static char scan_symlink = 1; 36static char scan_symlink = 1;
60static char dir_recurse = 0; 37static char dir_recurse = 0;
61static char dir_crossmount = 1; 38static char dir_crossmount = 1;
62static char show_pax = 0; 39static char show_pax = 0;
63static char show_stack = 0; 40static char show_phdr = 0;
64static char show_textrel = 0; 41static char show_textrel = 0;
65static char show_rpath = 0; 42static char show_rpath = 0;
66static char show_needed = 0; 43static char show_needed = 0;
67static char show_interp = 0; 44static char show_interp = 0;
45static char show_bind = 0;
46static char show_soname = 0;
47static char show_textrels = 0;
68static char show_banner = 1; 48static char show_banner = 1;
69static char be_quiet = 0; 49static char be_quiet = 0;
70static char be_verbose = 0; 50static char be_verbose = 0;
51static char be_wewy_wewy_quiet = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 52static char *find_sym = NULL, *versioned_symname = NULL;
53static char *find_lib = NULL;
72static char *out_format = NULL; 54static char *out_format = NULL;
55static char *search_path = NULL;
56static char gmatch = 0;
57static char printcache = 0;
73 58
74 59
60caddr_t ldcache = 0;
61size_t ldcache_size = 0;
75 62
76/* sub-funcs for scanelf_file() */ 63/* sub-funcs for scanelf_file() */
64static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
65{
66 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
67#define GET_SYMTABS(B) \
68 if (elf->elf_class == ELFCLASS ## B) { \
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}
77static char *scanelf_file_pax(elfobj *elf, char *found_pax) 90static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{ 91{
79 static char *paxflags; 92 static char ret[7];
93 unsigned long i, shown;
80 94
81 if (!show_pax) return NULL; 95 if (!show_pax) return NULL;
82 96
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85 *found_pax = 1;
86 return paxflags;
87 }
88
89 return NULL;
90}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{
93 static char ret[8];
94 char *found;
95 int i, off, shown;
96
97 if (!show_stack) return NULL;
98
99 shown = 0; 97 shown = 0;
100 strcpy(ret, "--- ---"); 98 memset(&ret, 0, sizeof(ret));
99
100 if (elf->phdr) {
101#define SHOW_STACK(B) \ 101#define SHOW_PAX(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 102 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 106 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
107 found = found_stack; \
108 off = 0; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
110 found = found_relro; \
111 off = 3; \
112 } else \
113 continue; \ 107 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 108 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
115 continue; \ 109 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 110 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
117 *found = 1; \ 111 *found_pax = 1; \
118 ++shown; \ 112 ++shown; \
113 break; \
119 } \ 114 } \
120 } 115 }
121 SHOW_STACK(32) 116 SHOW_PAX(32)
122 SHOW_STACK(64) 117 SHOW_PAX(64)
123 if (be_quiet && !shown) 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))
124 return NULL; 132 return NULL;
125 else 133 else
126 return ret; 134 return ret;
127} 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}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 221static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 222{
130 static char *ret = "TEXTREL"; 223 static const char *ret = "TEXTREL";
131 int i; 224 unsigned long i;
132 225
133 if (!show_textrel) return NULL; 226 if (!show_textrel && !show_textrels) return NULL;
134 227
228 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 229#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 230 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 231 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 232 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 233 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
234 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 235 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 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; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 239 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 240 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 241 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 242 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 243 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 244 return (be_wewy_wewy_quiet ? NULL : ret); \
148 } \ 245 } \
149 ++dyn; \ 246 ++dyn; \
150 } \ 247 } \
151 } } 248 } }
152 SHOW_TEXTREL(32) 249 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 250 SHOW_TEXTREL(64)
154 if (be_quiet) 251 }
252
253 if (be_quiet || be_wewy_wewy_quiet)
155 return NULL; 254 return NULL;
156 else 255 else
157 return " - "; 256 return " - ";
158} 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) {
362 struct stat st;
363 switch (*item) {
364 case '/': break;
365 case '.':
366 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename);
367 break;
368 case '\0':
369 warnf("Security problem NULL RPATH in %s", elf->filename);
370 break;
371 case '$':
372 if (fstat(elf->fd, &st) != -1)
373 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
374 warnf("Security problem with RPATH='%s' in %s with mode set of %o",
375 item, elf->filename, st.st_mode & 07777);
376 break;
377 default:
378 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename);
379 break;
380 }
381}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 382static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 383{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 384 unsigned long i, s;
162 int i;
163 char *rpath, *runpath; 385 char *rpath, *runpath, **r;
164 void *strtbl_void; 386 void *strtbl_void;
165 387
166 if (!show_rpath) return; 388 if (!show_rpath) return;
167 389
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 390 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 391 rpath = runpath = NULL;
170 392
171 if (strtbl_void) { 393 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 394#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 395 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 396 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 397 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 398 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 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 */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 403 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
404 /* Just scan dynamic headers */ \
179 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 */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 409 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 410 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 411 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 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 */ \
184 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 } \
185 *found_rpath = 1; \ 448 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 449 } \
191 ++dyn; \ 450 ++dyn; \
192 } \ 451 } \
193 } } 452 } }
194 SHOW_RPATH(32) 453 SHOW_RPATH(32)
195 SHOW_RPATH(64) 454 SHOW_RPATH(64)
196 } 455 }
456
457 if (be_wewy_wewy_quiet) return;
197 458
198 if (rpath && runpath) { 459 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) { 460 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len); 461 xstrcat(ret, runpath, ret_len);
201 } else { 462 } else {
209 } else if (rpath || runpath) 470 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 471 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet) 472 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 473 xstrcat(ret, " - ", ret_len);
213} 474}
475
476#define LDSO_CACHE_MAGIC "ld.so-"
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
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 561static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
215{ 562{
216 int i; 563 unsigned long i;
217 char *needed; 564 char *needed;
218 void *strtbl_void; 565 void *strtbl_void;
566 char *p;
219 567
220 if (!show_needed) return; 568 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
221 569
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 570 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 571
224 if (strtbl_void) { 572 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 573#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 574 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 575 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 576 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 577 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 578 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
579 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 580 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 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; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 584 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 585 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 586 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 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); \
588 if (offset >= (Elf ## B ## _Off)elf->len) { \
589 ++dyn; \
590 continue; \
591 } \
592 needed = (char*)(elf->data + offset); \
593 if (op == 0) { \
594 if (!be_wewy_wewy_quiet) { \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 595 if (*found_needed) xchrcat(ret, ',', ret_len); \
596 if (printcache) \
597 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
598 needed = p; \
238 xstrcat(ret, needed, ret_len); \ 599 xstrcat(ret, needed, ret_len); \
600 } \
239 *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 } \
240 } \ 608 } \
241 ++dyn; \ 609 ++dyn; \
242 } \ 610 } \
243 } } 611 } }
244 SHOW_NEEDED(32) 612 SHOW_NEEDED(32)
245 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);
246 } 616 }
617
618 return NULL;
247} 619}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp) 620static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{ 621{
250 void *strtbl_void; 622 void *strtbl_void;
251 623
256 if (strtbl_void) { 628 if (strtbl_void) {
257#define SHOW_INTERP(B) \ 629#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \ 630 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 631 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \ 632 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \ 633 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 634 }
263 SHOW_INTERP(32) 635 SHOW_INTERP(32)
264 SHOW_INTERP(64) 636 SHOW_INTERP(64)
265 } 637 }
266 return NULL; 638 return NULL;
267} 639}
640static char *scanelf_file_bind(elfobj *elf, char *found_bind)
641{
642 unsigned long i;
643 struct stat s;
644
645 if (!show_bind) return NULL;
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}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 729static char *scanelf_file_sym(elfobj *elf, char *found_sym)
269{ 730{
270 int i; 731 unsigned long i;
732 char *ret;
271 void *symtab_void, *strtab_void; 733 void *symtab_void, *strtab_void;
272 734
273 if (!find_sym) return NULL; 735 if (!find_sym) return NULL;
736 ret = find_sym;
274 737
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 738 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 strtab_void = elf_findsecbyname(elf, ".strtab");
277 739
278 if (symtab_void && strtab_void) { 740 if (symtab_void && strtab_void) {
279#define FIND_SYM(B) \ 741#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 742 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 743 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 744 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 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)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 746 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 747 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 748 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 749 if (sym->st_name) { \
288 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)); \
289 if (*find_sym == '*') { \ 751 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 752 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 753 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 754 elf->base_filename, \
293 (long)sym->st_size, \ 755 (unsigned long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 756 get_elfstttype(sym->st_info), \
295 symname); \ 757 symname); \
296 *found_sym = 1; \ 758 *found_sym = 1; \
297 } 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') || \
298 (strcmp(symname, versioned_symname) == 0)) \ 767 (strcmp(symname, versioned_symname) == 0)) { \
768 ret = this_sym; \
299 (*found_sym)++; \ 769 (*found_sym)++; \
770 goto break_out; \
771 } \
772 this_sym = next_sym + 1; \
773 } while (*next_sym != '\0'); \
774 } \
300 } \ 775 } \
301 ++sym; \ 776 ++sym; \
302 } } 777 } }
303 FIND_SYM(32) 778 FIND_SYM(32)
304 FIND_SYM(64) 779 FIND_SYM(64)
305 } 780 }
781
782break_out:
783 if (be_wewy_wewy_quiet) return NULL;
784
306 if (*find_sym != '*' && *found_sym) 785 if (*find_sym != '*' && *found_sym)
307 return find_sym; 786 return ret;
308 if (be_quiet) 787 if (be_quiet)
309 return NULL; 788 return NULL;
310 else 789 else
311 return " - "; 790 return (char *)" - ";
312} 791}
313/* scan an elf file and show all the fun stuff */ 792/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 793#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 794static void scanelf_file(const char *filename)
316{ 795{
317 int i; 796 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 797 char found_pax, found_phdr, found_relro, found_load, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 798 found_rpath, found_needed, found_interp, found_bind, found_soname,
320 found_file; 799 found_sym, found_lib, found_file, found_textrels;
321 elfobj *elf; 800 elfobj *elf;
322 struct stat st; 801 struct stat st;
323 static char *out_buffer = NULL; 802 static char *out_buffer = NULL;
324 static size_t out_len; 803 static size_t out_len;
325 804
327 if (lstat(filename, &st) == -1) { 806 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 807 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 808 return;
330 } 809 }
331 /* always handle regular files and handle symlinked files if no -y */ 810 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 811 if (S_ISLNK(st.st_mode)) {
812 if (!scan_symlink) return;
813 stat(filename, &st);
814 }
815 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 816 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 817 return;
335 } 818 }
336 819
337 found_pax = found_stack = found_relro = found_textrel = \ 820 found_pax = found_phdr = found_relro = found_load = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 821 found_rpath = found_needed = found_interp = found_bind = found_soname = \
339 found_file = 0; 822 found_sym = found_lib = found_file = found_textrels = 0;
340 823
341 /* verify this is real ELF */ 824 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 825 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 826 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 827 return;
345 } 828 }
346 829
347 if (be_verbose > 1) 830 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename, 831 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class), 832 get_elfeitype(EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 833 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose) 834 else if (be_verbose)
352 printf("%s: scanning file\n", filename); 835 printf("%s: scanning file\n", filename);
353 836
354 /* init output buffer */ 837 /* init output buffer */
355 if (!out_buffer) { 838 if (!out_buffer) {
358 } 841 }
359 *out_buffer = '\0'; 842 *out_buffer = '\0';
360 843
361 /* show the header */ 844 /* show the header */
362 if (!be_quiet && show_banner) { 845 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 846 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 847 if (!IS_MODIFIER(out_format[i])) continue;
365 848
366 switch (out_format[++i]) { 849 switch (out_format[++i]) {
367 case '%': break; 850 case '%': break;
851 case '#': break;
852 case 'F':
853 case 'p':
368 case 'F': prints("FILE "); break; 854 case 'f': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 855 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 856 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 857 case 'e': prints("STK/REL/PTL "); break;
372 case 't': prints("TEXTREL "); break; 858 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 859 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 860 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 861 case 'i': prints("INTERP "); break;
862 case 'b': prints("BIND "); break;
863 case 'S': prints("SONAME "); break;
376 case 's': prints("SYM "); 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]);
377 } 868 }
378 } 869 }
870 if (!found_file) prints("FILE ");
379 prints("\n"); 871 prints("\n");
872 found_file = 0;
380 show_banner = 0; 873 show_banner = 0;
381 } 874 }
382 875
383 /* dump all the good stuff */ 876 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 877 for (i = 0; out_format[i]; ++i) {
385 const char *out; 878 const char *out;
879 const char *tmp;
386 880
387 /* make sure we trim leading spaces in quiet mode */ 881 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 882 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 883 *out_buffer = '\0';
390 884
391 if (out_format[i] != '%') { 885 if (!IS_MODIFIER(out_format[i])) {
392 xchrcat(&out_buffer, out_format[i], &out_len); 886 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue; 887 continue;
394 } 888 }
395 889
396 out = NULL; 890 out = NULL;
891 be_wewy_wewy_quiet = (out_format[i] == '#');
397 switch (out_format[++i]) { 892 switch (out_format[++i]) {
893 case '%':
894 case '#':
398 case '%': xchrcat(&out_buffer, '%', &out_len); break; 895 xchrcat(&out_buffer, out_format[i], &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &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;
400 case 'o': out = get_elfetype(elf); break; 922 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 923 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 924 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); 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;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 927 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
928 case 'n':
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 929 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); 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;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 933 case 's': out = scanelf_file_sym(elf, &found_sym); break;
934 default: warnf("'%c' has no scan code?", out_format[i]);
408 } 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
409 if (out) xstrcat(&out_buffer, out, &out_len); 941 xstrcat(&out_buffer, out, &out_len);
410 } 942 }
943 }
411 944
412 if (!found_file) { 945#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 946 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 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);
415 xstrcat(&out_buffer, filename, &out_len); 952 xstrcat(&out_buffer, filename, &out_len);
416 } 953 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 954 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
418 puts(out_buffer); 955 puts(out_buffer);
956 fflush(stdout);
957 }
419 958
420 unreadelf(elf); 959 unreadelf(elf);
421} 960}
422 961
423/* 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 */
452 while ((dentry = readdir(dir))) { 991 while ((dentry = readdir(dir))) {
453 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 992 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
454 continue; 993 continue;
455 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 994 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
456 if (len >= sizeof(buf)) { 995 if (len >= sizeof(buf)) {
457 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));
458 continue; 998 continue;
459 } 999 }
460 sprintf(buf, "%s/%s", path, dentry->d_name); 1000 sprintf(buf, "%s/%s", path, dentry->d_name);
461 if (lstat(buf, &st) != -1) { 1001 if (lstat(buf, &st) != -1) {
462 if (S_ISREG(st.st_mode)) 1002 if (S_ISREG(st.st_mode))
468 } 1008 }
469 } 1009 }
470 closedir(dir); 1010 closedir(dir);
471} 1011}
472 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
473/* scan /etc/ld.so.conf for paths */ 1064/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 1065static void scanelf_ldpath()
475{ 1066{
476 char scan_l, scan_ul, scan_ull; 1067 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 1068 int i = 0;
478 FILE *fp;
479 1069
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1070 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 1071 err("Unable to load any paths from ld.so.conf");
482 1072
483 scan_l = scan_ul = scan_ull = 0; 1073 scan_l = scan_ul = scan_ull = 0;
484 1074
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 1075 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 1076 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 1077 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 1078 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 1079 scanelf_dir(ldpaths[i]);
1080 ++i;
496 } 1081 }
497 free(path);
498 fclose(fp);
499 1082
500 if (!scan_l) scanelf_dir("/lib"); 1083 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 1084 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1085 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 1086}
519 1102
520 free(path); 1103 free(path);
521} 1104}
522 1105
523 1106
524
525/* usage / invocation handling functions */ 1107/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 1108#define PARSE_FLAGS "plRmyxetrnLibSs:gN:TaqvF:f:o:BhV"
527#define a_argument required_argument 1109#define a_argument required_argument
528static struct option const long_opts[] = { 1110static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 1111 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 1112 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 1113 {"recursive", no_argument, NULL, 'R'},
534 {"pax", no_argument, NULL, 'x'}, 1116 {"pax", no_argument, NULL, 'x'},
535 {"header", no_argument, NULL, 'e'}, 1117 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 1118 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 1119 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 1120 {"needed", no_argument, NULL, 'n'},
1121 {"ldcache", no_argument, NULL, 'L'},
539 {"interp", no_argument, NULL, 'i'}, 1122 {"interp", no_argument, NULL, 'i'},
1123 {"bind", no_argument, NULL, 'b'},
1124 {"soname", no_argument, NULL, 'S'},
540 {"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'},
541 {"all", no_argument, NULL, 'a'}, 1129 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 1130 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 1131 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 1132 {"format", a_argument, NULL, 'F'},
1133 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 1134 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 1135 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 1136 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 1137 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 1138 {NULL, no_argument, NULL, 0x0}
550}; 1139};
1140
551static char *opts_help[] = { 1141static const char *opts_help[] = {
552 "Scan all directories in PATH environment", 1142 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 1143 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 1144 "Scan directories recursively",
555 "Don't recursively cross mount points", 1145 "Don't recursively cross mount points",
556 "Don't scan symlinks\n", 1146 "Don't scan symlinks\n",
557 "Print PaX markings", 1147 "Print PaX markings",
558 "Print GNU_STACK markings", 1148 "Print GNU_STACK/PT_LOAD markings",
559 "Print TEXTREL information", 1149 "Print TEXTREL information",
560 "Print RPATH information", 1150 "Print RPATH information",
561 "Print NEEDED information", 1151 "Print NEEDED information",
1152 "Resolve NEEDED information (use with -n)",
562 "Print INTERP information", 1153 "Print INTERP information",
1154 "Print BIND information",
1155 "Print SONAME information",
563 "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",
564 "Print all scanned info (-x -e -t -r)\n", 1160 "Print all scanned info (-x -e -t -r -b)\n",
565 "Only output 'bad' things", 1161 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 1162 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 1163 "Use specified format for output",
1164 "Read input stream from a filename",
568 "Write output stream to a filename", 1165 "Write output stream to a filename",
569 "Don't display the header", 1166 "Don't display the header",
570 "Print this help and exit", 1167 "Print this help and exit",
571 "Print version and exit", 1168 "Print version and exit",
572 NULL 1169 NULL
573}; 1170};
574 1171
575/* display usage and exit */ 1172/* display usage and exit */
576static void usage(int status) 1173static void usage(int status)
577{ 1174{
578 int i; 1175 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 1176 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1177 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 1178 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 1179 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 1180 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1181 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 1182 long_opts[i].name, opts_help[i]);
586 else 1183 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1184 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 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
589 exit(status); 1200 exit(status);
590} 1201}
591 1202
592/* parse command line arguments and preform needed actions */ 1203/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 1204static void parseargs(int argc, char *argv[])
594{ 1205{
595 int flag; 1206 int i;
1207 char *from_file = NULL;
596 1208
597 opterr = 0; 1209 opterr = 0;
598 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) {
599 switch (flag) { 1211 switch (i) {
600 1212
601 case 'V': 1213 case 'V':
602 printf("%s compiled %s\n%s\n" 1214 printf("pax-utils-%s: %s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1215 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 1216 VERSION, __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 1217 exit(EXIT_SUCCESS);
606 break; 1218 break;
607 case 'h': usage(EXIT_SUCCESS); break; 1219 case 'h': usage(EXIT_SUCCESS); break;
608 1220 case 'f':
1221 if (from_file) err("Don't specify -f twice");
1222 from_file = xstrdup(optarg);
1223 break;
609 case 'o': { 1224 case 'o': {
610 FILE *fp = NULL; 1225 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 1226 if ((fp = freopen(optarg, "w", stdout)) == NULL)
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1227 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp; 1228 SET_STDOUT(fp);
615 break; 1229 break;
616 } 1230 }
617 1231
618 case 's': { 1232 case 's': {
619 size_t len; 1233 if (find_sym) warn("You prob don't want to specify -s twice");
620 find_sym = xstrdup(optarg); 1234 find_sym = optarg;
621 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1235 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
623 sprintf(versioned_symname, "%s@", find_sym); 1236 sprintf(versioned_symname, "%s@", find_sym);
624 break; 1237 break;
625 } 1238 }
626
627 case 'F': { 1239 case 'N': {
628 out_format = strdup(optarg); 1240 if (find_lib) warn("You prob don't want to specify -N twice");
1241 find_lib = optarg;
629 break; 1242 break;
630 } 1243 }
631 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;
632 case 'y': scan_symlink = 0; break; 1253 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 1254 case 'B': show_banner = 0; break;
634 case 'l': scan_ldpath = 1; break; 1255 case 'l': scan_ldpath = 1; break;
635 case 'p': scan_envpath = 1; break; 1256 case 'p': scan_envpath = 1; break;
636 case 'R': dir_recurse = 1; break; 1257 case 'R': dir_recurse = 1; break;
637 case 'm': dir_crossmount = 0; break; 1258 case 'm': dir_crossmount = 0; break;
638 case 'x': show_pax = 1; break; 1259 case 'x': show_pax = 1; break;
639 case 'e': show_stack = 1; break; 1260 case 'e': show_phdr = 1; break;
640 case 't': show_textrel = 1; break; 1261 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 1262 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 1263 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 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;
644 case 'q': be_quiet = 1; break; 1268 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1269 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 1270 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
647 1271
648 case ':': 1272 case ':':
649 warn("Option missing parameter\n"); 1273 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 1274 case '?':
653 warn("Unknown option\n"); 1275 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 1276 default:
657 err("Unhandled option '%c'", flag); 1277 err("Unhandled option '%c'", i);
658 break;
659 } 1278 }
660 } 1279 }
661
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 1280
665 /* let the format option override all other options */ 1281 /* let the format option override all other options */
666 if (out_format) { 1282 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 1283 show_pax = show_phdr = show_textrel = show_rpath = \
1284 show_needed = show_interp = show_bind = show_soname = \
1285 show_textrels = 0;
668 for (flag=0; out_format[flag]; ++flag) { 1286 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 1287 if (!IS_MODIFIER(out_format[i])) continue;
670 1288
671 switch (out_format[++flag]) { 1289 switch (out_format[++i]) {
672 case '%': break; 1290 case '%': break;
1291 case '#': break;
673 case 'F': break; 1292 case 'F': break;
1293 case 'p': break;
1294 case 'f': break;
674 case 's': break; 1295 case 's': break;
1296 case 'N': break;
675 case 'o': break; 1297 case 'o': break;
676 case 'x': show_pax = 1; break; 1298 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 1299 case 'e': show_phdr = 1; break;
678 case 't': show_textrel = 1; break; 1300 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 1301 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 1302 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 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;
682 default: 1307 default:
683 err("Invalid format specifier '%c' (byte %i)", 1308 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 1309 out_format[i], i+1);
685 } 1310 }
686 } 1311 }
687 1312
688 /* construct our default format */ 1313 /* construct our default format */
689 } else { 1314 } else {
690 size_t fmt_len = 30; 1315 size_t fmt_len = 30;
691 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1316 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
692 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1317 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
693 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1318 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1319 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1320 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1321 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1322 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &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);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1327 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1328 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1329 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 1330 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 1331 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 1332
704 /* now lets actually do the scanning */ 1333 /* now lets actually do the scanning */
1334 if (scan_ldpath || (show_rpath && be_quiet))
1335 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 1336 if (scan_ldpath) scanelf_ldpath();
706 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 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 1343 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 1344 err("Nothing to scan !?");
709 while (optind < argc) 1345 while (optind < argc) {
710 scanelf_dir(argv[optind++]); 1346 search_path = argv[optind++];
1347 scanelf_dir(search_path);
1348 }
711 1349
712 /* clean up */ 1350 /* clean up */
713 if (find_sym) { 1351 if (versioned_symname) free(versioned_symname);
714 free(find_sym); 1352 for (i = 0; ldpaths[i]; ++i)
715 free(versioned_symname); 1353 free(ldpaths[i]);
716 } 1354
717 if (out_format) free(out_format); 1355 if (ldcache != 0)
1356 munmap(ldcache, ldcache_size);
718} 1357}
719 1358
720 1359
721 1360
722/* utility funcs */ 1361/* utility funcs */
723static char *xstrdup(char *s) 1362static char *xstrdup(const char *s)
724{ 1363{
725 char *ret = strdup(s); 1364 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1365 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 1366 return ret;
728} 1367}
730{ 1369{
731 void *ret = malloc(size); 1370 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1371 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 1372 return ret;
734} 1373}
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 1374static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
736{ 1375{
737 long new_len; 1376 size_t new_len;
738 1377
739 new_len = strlen(*dst) + strlen(src); 1378 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) { 1379 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2); 1380 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len); 1381 *dst = realloc(*dst, *curr_len);
743 if (!*dst) 1382 if (!*dst)
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 1383 err("could not realloc() %li bytes", (unsigned long)*curr_len);
745 } 1384 }
746 1385
1386 if (n)
1387 strncat(*dst, src, n);
1388 else
747 strcat(*dst, src); 1389 strcat(*dst, src);
748} 1390}
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1391static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 1392{
751 static char my_app[2]; 1393 static char my_app[2];
752 my_app[0] = append; 1394 my_app[0] = append;
753 my_app[1] = '\0'; 1395 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 1396 xstrcat(dst, my_app, curr_len);
755} 1397}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764 1398
765 1399
766 1400
767int main(int argc, char *argv[]) 1401int main(int argc, char *argv[])
768{ 1402{
769 if (argc < 2) 1403 if (argc < 2)
770 usage(EXIT_FAILURE); 1404 usage(EXIT_FAILURE);
771 parseargs(argc, argv); 1405 parseargs(argc, argv);
772 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
773 return EXIT_SUCCESS; 1410 return EXIT_SUCCESS;
774} 1411}

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

  ViewVC Help
Powered by ViewVC 1.1.20