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

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

  ViewVC Help
Powered by ViewVC 1.1.20