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

Diff of /pax-utils/scanelf.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.20