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

Diff of /pax-utils/scanelf.c

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

Revision 1.43 Revision 1.51
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org> 2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 3 * Copyright 1999-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 4 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $ 5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.51 2005/05/18 05:15:48 vapier Exp $
6 * 6 *
7 ******************************************************************** 7 ********************************************************************
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the 10 * published by the Free Software Foundation; either version 2 of the
33#include <getopt.h> 33#include <getopt.h>
34#include <assert.h> 34#include <assert.h>
35 35
36#include "paxelf.h" 36#include "paxelf.h"
37 37
38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.51 2005/05/18 05:15:48 vapier Exp $";
39#define argv0 "scanelf" 39#define argv0 "scanelf"
40 40
41 41
42 42
43/* prototypes */ 43/* prototypes */
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 52static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 53static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff); 54static int xemptybuffer(const char *buff);
55 55
56/* variables to control behavior */ 56/* variables to control behavior */
57static char *ldpaths[256];
57static char scan_ldpath = 0; 58static char scan_ldpath = 0;
58static char scan_envpath = 0; 59static char scan_envpath = 0;
59static char scan_symlink = 1; 60static char scan_symlink = 1;
60static char dir_recurse = 0; 61static char dir_recurse = 0;
61static char dir_crossmount = 1; 62static char dir_crossmount = 1;
63static char show_stack = 0; 64static char show_stack = 0;
64static char show_textrel = 0; 65static char show_textrel = 0;
65static char show_rpath = 0; 66static char show_rpath = 0;
66static char show_needed = 0; 67static char show_needed = 0;
67static char show_interp = 0; 68static char show_interp = 0;
69static char show_bind = 0;
68static char show_banner = 1; 70static char show_banner = 1;
69static char be_quiet = 0; 71static char be_quiet = 0;
70static char be_verbose = 0; 72static char be_verbose = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 73static char *find_sym = NULL, *versioned_symname = NULL;
72static char *out_format = NULL; 74static char *out_format = NULL;
90} 92}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro) 93static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{ 94{
93 static char ret[8]; 95 static char ret[8];
94 char *found; 96 char *found;
95 int i, off, shown; 97 unsigned long i, off, shown;
96 98
97 if (!show_stack) return NULL; 99 if (!show_stack) return NULL;
98 100
99 shown = 0; 101 shown = 0;
100 strcpy(ret, "--- ---"); 102 strcpy(ret, "--- ---");
103
104 if (elf->phdr) {
101#define SHOW_STACK(B) \ 105#define SHOW_STACK(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 106 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 107 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 108 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 109 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
118 ++shown; \ 122 ++shown; \
119 } \ 123 } \
120 } 124 }
121 SHOW_STACK(32) 125 SHOW_STACK(32)
122 SHOW_STACK(64) 126 SHOW_STACK(64)
127 }
128
123 if (be_quiet && !shown) 129 if (be_quiet && !shown)
124 return NULL; 130 return NULL;
125 else 131 else
126 return ret; 132 return ret;
127} 133}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 134static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 135{
130 static char *ret = "TEXTREL"; 136 static char *ret = "TEXTREL";
131 int i; 137 unsigned long i;
132 138
133 if (!show_textrel) return NULL; 139 if (!show_textrel) return NULL;
134 140
141 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 142#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 143 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 144 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 145 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 146 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
147 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 148 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 149 if (phdr[i].p_type != PT_DYNAMIC) continue; \
150 offset = EGET(phdr[i].p_offset); \
151 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 152 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 153 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 154 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 155 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 156 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 157 return ret; \
149 ++dyn; \ 159 ++dyn; \
150 } \ 160 } \
151 } } 161 } }
152 SHOW_TEXTREL(32) 162 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 163 SHOW_TEXTREL(64)
164 }
165
154 if (be_quiet) 166 if (be_quiet)
155 return NULL; 167 return NULL;
156 else 168 else
157 return " - "; 169 return " - ";
158} 170}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 171static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 172{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 173 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
162 int i; 174 unsigned long i, s;
163 char *rpath, *runpath; 175 char *rpath, *runpath, **r;
164 void *strtbl_void; 176 void *strtbl_void;
165 177
166 if (!show_rpath) return; 178 if (!show_rpath) return;
167 179
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 180 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 181 rpath = runpath = NULL;
170 182
171 if (strtbl_void) { 183 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 184#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 185 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 186 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 187 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 188 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 189 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
190 Elf ## B ## _Off offset; \
191 Elf ## B ## _Sxword word; \
192 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 193 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
194 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 195 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
196 offset = EGET(phdr[i].p_offset); \
197 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
198 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 199 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 200 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 201 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 202 r = &rpath; \
203 } else if (word == DT_RUNPATH) { \
204 r = &runpath; \
205 } else { \
206 ++dyn; \
207 continue; \
208 } \
209 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 210 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
211 if (offset < elf->len) { \
212 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
213 *r = (char*)(elf->data + offset); \
214 /* If quiet, don't output paths in ld.so.conf */ \
215 if (be_quiet) \
216 for (s = 0; ldpaths[s]; ++s) \
217 if (!strcmp(ldpaths[s], *r)) { \
218 *r = NULL; \
219 break; \
220 } \
185 *found_rpath = 1; \ 221 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 222 } \
191 ++dyn; \ 223 ++dyn; \
192 } \ 224 } \
193 } } 225 } }
194 SHOW_RPATH(32) 226 SHOW_RPATH(32)
211 else if (!be_quiet) 243 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 244 xstrcat(ret, " - ", ret_len);
213} 245}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 246static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
215{ 247{
216 int i; 248 unsigned long i;
217 char *needed; 249 char *needed;
218 void *strtbl_void; 250 void *strtbl_void;
219 251
220 if (!show_needed) return; 252 if (!show_needed) return;
221 253
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 254 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 255
224 if (strtbl_void) { 256 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 257#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 258 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 259 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 260 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 261 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 262 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
263 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 264 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 265 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
266 offset = EGET(phdr[i].p_offset); \
267 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 268 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 269 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 270 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 271 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
272 if (offset >= elf->len) { \
273 ++dyn; \
274 continue; \
275 } \
276 needed = (char*)(elf->data + offset); \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 277 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 278 xstrcat(ret, needed, ret_len); \
239 *found_needed = 1; \ 279 *found_needed = 1; \
240 } \ 280 } \
241 ++dyn; \ 281 ++dyn; \
263 SHOW_INTERP(32) 303 SHOW_INTERP(32)
264 SHOW_INTERP(64) 304 SHOW_INTERP(64)
265 } 305 }
266 return NULL; 306 return NULL;
267} 307}
308static char *scanelf_file_bind(elfobj *elf, char *found_bind)
309{
310 unsigned long i;
311 struct stat s;
312
313 if (!show_bind) return NULL;
314 if (!elf->phdr) return NULL;
315
316#define SHOW_BIND(B) \
317 if (elf->elf_class == ELFCLASS ## B) { \
318 Elf ## B ## _Dyn *dyn; \
319 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
320 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
321 Elf ## B ## _Off offset; \
322 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
323 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
324 offset = EGET(phdr[i].p_offset); \
325 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
326 dyn = DYN ## B (elf->data + offset); \
327 while (EGET(dyn->d_tag) != DT_NULL) { \
328 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
329 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
330 { \
331 if (be_quiet) return NULL; \
332 *found_bind = 1; \
333 return "NOW"; \
334 } \
335 ++dyn; \
336 } \
337 } \
338 }
339 SHOW_BIND(32)
340 SHOW_BIND(64)
341
342 fstat(elf->fd, &s);
343 if (be_quiet && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
344 return NULL;
345 } else {
346 *found_bind = 1;
347 return "LAZY";
348 }
349}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 350static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
269{ 351{
270 int i; 352 unsigned long i;
271 void *symtab_void, *strtab_void; 353 void *symtab_void, *strtab_void;
272 354
273 if (!find_sym) return NULL; 355 if (!find_sym) return NULL;
274 356
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 357 symtab_void = elf_findsecbyname(elf, ".symtab");
279#define FIND_SYM(B) \ 361#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 362 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 363 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 364 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 365 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 366 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 367 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 368 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 369 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 370 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 371 if (*find_sym == '*') { \
312} 394}
313/* scan an elf file and show all the fun stuff */ 395/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 396#define prints(str) fputs(str, stdout)
315static void scanelf_file(const char *filename) 397static void scanelf_file(const char *filename)
316{ 398{
317 int i; 399 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 400 char found_pax, found_stack, found_relro, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 401 found_rpath, found_needed, found_interp, found_bind,
320 found_file; 402 found_sym, found_file;
321 elfobj *elf; 403 elfobj *elf;
322 struct stat st; 404 struct stat st;
323 static char *out_buffer = NULL; 405 static char *out_buffer = NULL;
324 static size_t out_len; 406 static size_t out_len;
325 407
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 415 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 416 return;
335 } 417 }
336 418
337 found_pax = found_stack = found_relro = found_textrel = \ 419 found_pax = found_stack = found_relro = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 420 found_rpath = found_needed = found_interp = found_bind = \
339 found_file = 0; 421 found_sym = found_file = 0;
340 422
341 /* verify this is real ELF */ 423 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 424 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 425 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 426 return;
358 } 440 }
359 *out_buffer = '\0'; 441 *out_buffer = '\0';
360 442
361 /* show the header */ 443 /* show the header */
362 if (!be_quiet && show_banner) { 444 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 445 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 446 if (out_format[i] != '%') continue;
365 447
366 switch (out_format[++i]) { 448 switch (out_format[++i]) {
367 case '%': break; 449 case '%': break;
368 case 'F': prints("FILE "); break; 450 case 'F': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 451 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 452 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 453 case 'e': prints("STK/REL "); break;
372 case 't': prints("TEXTREL "); break; 454 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 455 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 456 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 457 case 'i': prints("INTERP "); break;
458 case 'b': prints("BIND "); break;
376 case 's': prints("SYM "); break; 459 case 's': prints("SYM "); break;
377 } 460 }
378 } 461 }
462 if (!found_file) prints("FILE ");
379 prints("\n"); 463 prints("\n");
464 found_file = 0;
380 show_banner = 0; 465 show_banner = 0;
381 } 466 }
382 467
383 /* dump all the good stuff */ 468 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 469 for (i = 0; out_format[i]; ++i) {
385 const char *out; 470 const char *out;
386 471
387 /* make sure we trim leading spaces in quiet mode */ 472 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 473 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 474 *out_buffer = '\0';
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 487 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 488 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 489 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 490 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 491 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
492 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 493 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
408 } 494 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 495 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 496 }
411 497
412 if (!found_file) { 498 if (!found_file) {
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 499 if (!be_quiet || found_pax || found_stack || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 500 found_rpath || found_needed || found_interp || found_bind || \
501 found_sym)
502 {
503 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 504 xstrcat(&out_buffer, filename, &out_len);
505 }
416 } 506 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 507 if (!(be_quiet && xemptybuffer(out_buffer)))
418 puts(out_buffer); 508 puts(out_buffer);
419 509
420 unreadelf(elf); 510 unreadelf(elf);
468 } 558 }
469 } 559 }
470 closedir(dir); 560 closedir(dir);
471} 561}
472 562
563static int scanelf_from_file(char *filename)
564{
565 FILE *fp = NULL;
566 char *p;
567 char path[_POSIX_PATH_MAX];
568
569 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
570 fp = stdin;
571 else if ((fp = fopen(filename, "r")) == NULL)
572 return 1;
573
574 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
575 if ((p = strchr(path, '\n')) != NULL)
576 *p = 0;
577 scanelf_dir(path);
578 }
579 if (fp != stdin)
580 fclose(fp);
581 return 0;
582}
583
584static void load_ld_so_conf()
585{
586 FILE *fp = NULL;
587 char *p;
588 char path[_POSIX_PATH_MAX];
589 int i = 0;
590
591 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
592 return;
593
594 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
595 if (*path != '/')
596 continue;
597
598 if ((p = strrchr(path, '\r')) != NULL)
599 *p = 0;
600 if ((p = strchr(path, '\n')) != NULL)
601 *p = 0;
602
603 ldpaths[i++] = xstrdup(path);
604
605 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
606 break;
607 }
608 ldpaths[i] = NULL;
609
610 fclose(fp);
611}
612
473/* scan /etc/ld.so.conf for paths */ 613/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 614static void scanelf_ldpath()
475{ 615{
476 char scan_l, scan_ul, scan_ull; 616 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 617 int i = 0;
478 FILE *fp;
479 618
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 619 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 620 err("Unable to load any paths from ld.so.conf");
482 621
483 scan_l = scan_ul = scan_ull = 0; 622 scan_l = scan_ul = scan_ull = 0;
484 623
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 624 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 625 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 626 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 627 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 628 scanelf_dir(ldpaths[i]);
629 ++i;
496 } 630 }
497 free(path);
498 fclose(fp);
499 631
500 if (!scan_l) scanelf_dir("/lib"); 632 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 633 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 634 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 635}
521} 653}
522 654
523 655
524 656
525/* usage / invocation handling functions */ 657/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 658#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
527#define a_argument required_argument 659#define a_argument required_argument
528static struct option const long_opts[] = { 660static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 661 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 662 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 663 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 667 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 668 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 669 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 670 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 671 {"interp", no_argument, NULL, 'i'},
672 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 673 {"symbol", a_argument, NULL, 's'},
541 {"all", no_argument, NULL, 'a'}, 674 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 675 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 676 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 677 {"format", a_argument, NULL, 'F'},
678 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 679 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 680 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 681 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 682 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 683 {NULL, no_argument, NULL, 0x0}
558 "Print GNU_STACK markings", 692 "Print GNU_STACK markings",
559 "Print TEXTREL information", 693 "Print TEXTREL information",
560 "Print RPATH information", 694 "Print RPATH information",
561 "Print NEEDED information", 695 "Print NEEDED information",
562 "Print INTERP information", 696 "Print INTERP information",
697 "Print BIND information",
563 "Find a specified symbol", 698 "Find a specified symbol",
564 "Print all scanned info (-x -e -t -r)\n", 699 "Print all scanned info (-x -e -t -r -n -i)\n",
565 "Only output 'bad' things", 700 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 701 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 702 "Use specified format for output",
703 "Read input stream from a filename",
568 "Write output stream to a filename", 704 "Write output stream to a filename",
569 "Don't display the header", 705 "Don't display the header",
570 "Print this help and exit", 706 "Print this help and exit",
571 "Print version and exit", 707 "Print version and exit",
572 NULL 708 NULL
573}; 709};
574 710
575/* display usage and exit */ 711/* display usage and exit */
576static void usage(int status) 712static void usage(int status)
577{ 713{
578 int i; 714 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 715 printf(" Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 716 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 717 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 718 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 719 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 720 printf(" -%c, --%-13s %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 721 long_opts[i].name, opts_help[i]);
586 else 722 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 723 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 724 long_opts[i].name, opts_help[i]);
725
726 if (status != EXIT_SUCCESS)
727 exit(status);
728
729 puts("\nThe format modifiers for the -F option are:");
730 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
731 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
732 puts(" %i INTERP \t%b BIND \t%s symbol");
733
589 exit(status); 734 exit(status);
590} 735}
591 736
592/* parse command line arguments and preform needed actions */ 737/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 738static void parseargs(int argc, char *argv[])
594{ 739{
595 int flag; 740 int i;
741 char *from_file = NULL;
596 742
597 opterr = 0; 743 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 744 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 745 switch (i) {
600 746
601 case 'V': 747 case 'V':
602 printf("%s compiled %s\n%s\n" 748 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 749 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 750 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 751 exit(EXIT_SUCCESS);
606 break; 752 break;
607 case 'h': usage(EXIT_SUCCESS); break; 753 case 'h': usage(EXIT_SUCCESS); break;
608 754 case 'f':
755 if (from_file == NULL)
756 from_file = xstrdup(optarg);
757 break;
609 case 'o': { 758 case 'o': {
610 FILE *fp = NULL; 759 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 760 fp = freopen(optarg, "w", stdout);
612 if (fp == NULL) 761 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 762 err("Could not open output stream '%s': %s", optarg, strerror(errno));
623 sprintf(versioned_symname, "%s@", find_sym); 772 sprintf(versioned_symname, "%s@", find_sym);
624 break; 773 break;
625 } 774 }
626 775
627 case 'F': { 776 case 'F': {
628 out_format = strdup(optarg); 777 out_format = xstrdup(optarg);
629 break; 778 break;
630 } 779 }
631 780
632 case 'y': scan_symlink = 0; break; 781 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 782 case 'B': show_banner = 0; break;
639 case 'e': show_stack = 1; break; 788 case 'e': show_stack = 1; break;
640 case 't': show_textrel = 1; break; 789 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 790 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 791 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 792 case 'i': show_interp = 1; break;
793 case 'b': show_bind = 1; break;
644 case 'q': be_quiet = 1; break; 794 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 795 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 796 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
797 show_needed = show_interp = show_bind = 1; break;
647 798
648 case ':': 799 case ':':
649 warn("Option missing parameter\n"); 800 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 801 case '?':
653 warn("Unknown option\n"); 802 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 803 default:
657 err("Unhandled option '%c'", flag); 804 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 805 }
661 806 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 807
665 /* let the format option override all other options */ 808 /* let the format option override all other options */
666 if (out_format) { 809 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 810 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
668 for (flag=0; out_format[flag]; ++flag) { 811 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 812 if (out_format[i] != '%') continue;
670 813
671 switch (out_format[++flag]) { 814 switch (out_format[++i]) {
672 case '%': break; 815 case '%': break;
673 case 'F': break; 816 case 'F': break;
674 case 's': break; 817 case 's': break;
675 case 'o': break; 818 case 'o': break;
676 case 'x': show_pax = 1; break; 819 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 820 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break; 821 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 822 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 823 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 824 case 'i': show_interp = 1; break;
825 case 'b': show_bind = 1; break;
682 default: 826 default:
683 err("Invalid format specifier '%c' (byte %i)", 827 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 828 out_format[i], i+1);
685 } 829 }
686 } 830 }
687 831
688 /* construct our default format */ 832 /* construct our default format */
689 } else { 833 } else {
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 838 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 839 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 840 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 841 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 842 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
843 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 844 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 845 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 846 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 847 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 848
704 /* now lets actually do the scanning */ 849 /* now lets actually do the scanning */
850 if (scan_ldpath || (show_rpath && be_quiet))
851 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 852 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 853 if (scan_envpath) scanelf_envpath();
854 if (from_file) {
855 scanelf_from_file(from_file);
856 free(from_file);
857 from_file = *argv;
858 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 859 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 860 err("Nothing to scan !?");
709 while (optind < argc) 861 while (optind < argc)
710 scanelf_dir(argv[optind++]); 862 scanelf_dir(argv[optind++]);
711 863
712 /* clean up */ 864 /* clean up */
713 if (find_sym) { 865 if (find_sym) {
714 free(find_sym); 866 free(find_sym);
715 free(versioned_symname); 867 free(versioned_symname);
716 } 868 }
717 if (out_format) free(out_format); 869 if (out_format) free(out_format);
870 for (i = 0; ldpaths[i]; ++i)
871 free(ldpaths[i]);
718} 872}
719 873
720 874
721 875
722/* utility funcs */ 876/* utility funcs */
754 xstrcat(dst, my_app, curr_len); 908 xstrcat(dst, my_app, curr_len);
755} 909}
756static int xemptybuffer(const char *buff) 910static int xemptybuffer(const char *buff)
757{ 911{
758 long i; 912 long i;
759 for (i=0; buff[i]; ++i) 913 for (i = 0; buff[i]; ++i)
760 if (buff[i] != ' ') 914 if (buff[i] != ' ')
761 return 0; 915 return 0;
762 return 1; 916 return 1;
763} 917}
764 918

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

  ViewVC Help
Powered by ViewVC 1.1.20