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

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

  ViewVC Help
Powered by ViewVC 1.1.20