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

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

  ViewVC Help
Powered by ViewVC 1.1.20