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

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.79

  ViewVC Help
Powered by ViewVC 1.1.20