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

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

  ViewVC Help
Powered by ViewVC 1.1.20