/[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.50
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.50 2005/05/18 04:10:14 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.50 2005/05/18 04:10:14 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
315#define SHOW_BIND(B) \
316 if (elf->elf_class == ELFCLASS ## B) { \
317 Elf ## B ## _Dyn *dyn; \
318 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
319 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
320 Elf ## B ## _Off offset; \
321 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
322 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
323 offset = EGET(phdr[i].p_offset); \
324 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
325 dyn = DYN ## B (elf->data + offset); \
326 while (EGET(dyn->d_tag) != DT_NULL) { \
327 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
328 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
329 { \
330 if (be_quiet) return NULL; \
331 *found_bind = 1; \
332 return "NOW"; \
333 } \
334 ++dyn; \
335 } \
336 } \
337 }
338 SHOW_BIND(32)
339 SHOW_BIND(64)
340
341 fstat(elf->fd, &s);
342 if (be_quiet && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
343 return NULL;
344 } else {
345 *found_bind = 1;
346 return "LAZY";
347 }
348}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 349static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
269{ 350{
270 int i; 351 unsigned long i;
271 void *symtab_void, *strtab_void; 352 void *symtab_void, *strtab_void;
272 353
273 if (!find_sym) return NULL; 354 if (!find_sym) return NULL;
274 355
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 356 symtab_void = elf_findsecbyname(elf, ".symtab");
279#define FIND_SYM(B) \ 360#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 361 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 362 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 363 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 364 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 365 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 366 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 367 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 368 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 369 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 370 if (*find_sym == '*') { \
312} 393}
313/* scan an elf file and show all the fun stuff */ 394/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 395#define prints(str) fputs(str, stdout)
315static void scanelf_file(const char *filename) 396static void scanelf_file(const char *filename)
316{ 397{
317 int i; 398 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 399 char found_pax, found_stack, found_relro, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 400 found_rpath, found_needed, found_interp, found_bind,
320 found_file; 401 found_sym, found_file;
321 elfobj *elf; 402 elfobj *elf;
322 struct stat st; 403 struct stat st;
323 static char *out_buffer = NULL; 404 static char *out_buffer = NULL;
324 static size_t out_len; 405 static size_t out_len;
325 406
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 414 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 415 return;
335 } 416 }
336 417
337 found_pax = found_stack = found_relro = found_textrel = \ 418 found_pax = found_stack = found_relro = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 419 found_rpath = found_needed = found_interp = found_bind = \
339 found_file = 0; 420 found_sym = found_file = 0;
340 421
341 /* verify this is real ELF */ 422 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 423 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 424 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 425 return;
358 } 439 }
359 *out_buffer = '\0'; 440 *out_buffer = '\0';
360 441
361 /* show the header */ 442 /* show the header */
362 if (!be_quiet && show_banner) { 443 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 444 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 445 if (out_format[i] != '%') continue;
365 446
366 switch (out_format[++i]) { 447 switch (out_format[++i]) {
367 case '%': break; 448 case '%': break;
368 case 'F': prints("FILE "); break; 449 case 'F': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 450 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 451 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 452 case 'e': prints("STK/REL "); break;
372 case 't': prints("TEXTREL "); break; 453 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 454 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 455 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 456 case 'i': prints("INTERP "); break;
457 case 'b': prints("BIND "); break;
376 case 's': prints("SYM "); break; 458 case 's': prints("SYM "); break;
377 } 459 }
378 } 460 }
461 if (!found_file) prints("FILE ");
379 prints("\n"); 462 prints("\n");
463 found_file = 0;
380 show_banner = 0; 464 show_banner = 0;
381 } 465 }
382 466
383 /* dump all the good stuff */ 467 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 468 for (i = 0; out_format[i]; ++i) {
385 const char *out; 469 const char *out;
386 470
387 /* make sure we trim leading spaces in quiet mode */ 471 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 472 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 473 *out_buffer = '\0';
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 486 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 487 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 488 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; 489 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 490 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
491 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 492 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
408 } 493 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 494 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 495 }
411 496
412 if (!found_file) { 497 if (!found_file) {
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 498 if (!be_quiet || found_pax || found_stack || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 499 found_rpath || found_needed || found_interp || found_bind || \
500 found_sym)
501 {
502 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 503 xstrcat(&out_buffer, filename, &out_len);
504 }
416 } 505 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 506 if (!(be_quiet && xemptybuffer(out_buffer)))
418 puts(out_buffer); 507 puts(out_buffer);
419 508
420 unreadelf(elf); 509 unreadelf(elf);
468 } 557 }
469 } 558 }
470 closedir(dir); 559 closedir(dir);
471} 560}
472 561
562static int scanelf_from_file(char *filename)
563{
564 FILE *fp = NULL;
565 char *p;
566 char path[_POSIX_PATH_MAX];
567
568 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
569 fp = stdin;
570 else if ((fp = fopen(filename, "r")) == NULL)
571 return 1;
572
573 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
574 if ((p = strchr(path, '\n')) != NULL)
575 *p = 0;
576 scanelf_dir(path);
577 }
578 if (fp != stdin)
579 fclose(fp);
580 return 0;
581}
582
583static void load_ld_so_conf()
584{
585 FILE *fp = NULL;
586 char *p;
587 char path[_POSIX_PATH_MAX];
588 int i = 0;
589
590 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
591 return;
592
593 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
594 if (*path != '/')
595 continue;
596
597 if ((p = strrchr(path, '\r')) != NULL)
598 *p = 0;
599 if ((p = strchr(path, '\n')) != NULL)
600 *p = 0;
601
602 ldpaths[i++] = xstrdup(path);
603
604 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
605 break;
606 }
607 ldpaths[i] = NULL;
608
609 fclose(fp);
610}
611
473/* scan /etc/ld.so.conf for paths */ 612/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 613static void scanelf_ldpath()
475{ 614{
476 char scan_l, scan_ul, scan_ull; 615 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 616 int i = 0;
478 FILE *fp;
479 617
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 618 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 619 err("Unable to load any paths from ld.so.conf");
482 620
483 scan_l = scan_ul = scan_ull = 0; 621 scan_l = scan_ul = scan_ull = 0;
484 622
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 623 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; 624 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 625 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 626 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 627 scanelf_dir(ldpaths[i]);
628 ++i;
496 } 629 }
497 free(path);
498 fclose(fp);
499 630
500 if (!scan_l) scanelf_dir("/lib"); 631 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 632 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 633 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 634}
521} 652}
522 653
523 654
524 655
525/* usage / invocation handling functions */ 656/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 657#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
527#define a_argument required_argument 658#define a_argument required_argument
528static struct option const long_opts[] = { 659static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 660 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 661 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 662 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 666 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 667 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 668 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 669 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 670 {"interp", no_argument, NULL, 'i'},
671 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 672 {"symbol", a_argument, NULL, 's'},
541 {"all", no_argument, NULL, 'a'}, 673 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 674 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 675 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 676 {"format", a_argument, NULL, 'F'},
677 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 678 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 679 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 680 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 681 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 682 {NULL, no_argument, NULL, 0x0}
558 "Print GNU_STACK markings", 691 "Print GNU_STACK markings",
559 "Print TEXTREL information", 692 "Print TEXTREL information",
560 "Print RPATH information", 693 "Print RPATH information",
561 "Print NEEDED information", 694 "Print NEEDED information",
562 "Print INTERP information", 695 "Print INTERP information",
696 "Print BIND information",
563 "Find a specified symbol", 697 "Find a specified symbol",
564 "Print all scanned info (-x -e -t -r)\n", 698 "Print all scanned info (-x -e -t -r -n -i)\n",
565 "Only output 'bad' things", 699 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 700 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 701 "Use specified format for output",
702 "Read input stream from a filename",
568 "Write output stream to a filename", 703 "Write output stream to a filename",
569 "Don't display the header", 704 "Don't display the header",
570 "Print this help and exit", 705 "Print this help and exit",
571 "Print version and exit", 706 "Print version and exit",
572 NULL 707 NULL
573}; 708};
574 709
575/* display usage and exit */ 710/* display usage and exit */
576static void usage(int status) 711static void usage(int status)
577{ 712{
578 int i; 713 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 714 printf(" Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 715 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 716 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 717 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 718 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 719 printf(" -%c, --%-13s %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 720 long_opts[i].name, opts_help[i]);
586 else 721 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 722 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 723 long_opts[i].name, opts_help[i]);
724
725 if (status != EXIT_SUCCESS)
726 exit(status);
727
728 puts("\nThe format modifiers for the -F option are:");
729 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
730 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
731 puts(" %i INTERP \t%b BIND \t%s symbol");
732
589 exit(status); 733 exit(status);
590} 734}
591 735
592/* parse command line arguments and preform needed actions */ 736/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 737static void parseargs(int argc, char *argv[])
594{ 738{
595 int flag; 739 int i;
740 char *from_file = NULL;
596 741
597 opterr = 0; 742 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 743 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 744 switch (i) {
600 745
601 case 'V': 746 case 'V':
602 printf("%s compiled %s\n%s\n" 747 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 748 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 749 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 750 exit(EXIT_SUCCESS);
606 break; 751 break;
607 case 'h': usage(EXIT_SUCCESS); break; 752 case 'h': usage(EXIT_SUCCESS); break;
608 753 case 'f':
754 if (from_file == NULL)
755 from_file = xstrdup(optarg);
756 break;
609 case 'o': { 757 case 'o': {
610 FILE *fp = NULL; 758 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 759 fp = freopen(optarg, "w", stdout);
612 if (fp == NULL) 760 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 761 err("Could not open output stream '%s': %s", optarg, strerror(errno));
623 sprintf(versioned_symname, "%s@", find_sym); 771 sprintf(versioned_symname, "%s@", find_sym);
624 break; 772 break;
625 } 773 }
626 774
627 case 'F': { 775 case 'F': {
628 out_format = strdup(optarg); 776 out_format = xstrdup(optarg);
629 break; 777 break;
630 } 778 }
631 779
632 case 'y': scan_symlink = 0; break; 780 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 781 case 'B': show_banner = 0; break;
639 case 'e': show_stack = 1; break; 787 case 'e': show_stack = 1; break;
640 case 't': show_textrel = 1; break; 788 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 789 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 790 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 791 case 'i': show_interp = 1; break;
792 case 'b': show_bind = 1; break;
644 case 'q': be_quiet = 1; break; 793 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 794 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; 795 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
796 show_needed = show_interp = show_bind = 1; break;
647 797
648 case ':': 798 case ':':
649 warn("Option missing parameter\n"); 799 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 800 case '?':
653 warn("Unknown option\n"); 801 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 802 default:
657 err("Unhandled option '%c'", flag); 803 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 804 }
661 805 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 806
665 /* let the format option override all other options */ 807 /* let the format option override all other options */
666 if (out_format) { 808 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 809 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
668 for (flag=0; out_format[flag]; ++flag) { 810 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 811 if (out_format[i] != '%') continue;
670 812
671 switch (out_format[++flag]) { 813 switch (out_format[++i]) {
672 case '%': break; 814 case '%': break;
673 case 'F': break; 815 case 'F': break;
674 case 's': break; 816 case 's': break;
675 case 'o': break; 817 case 'o': break;
676 case 'x': show_pax = 1; break; 818 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 819 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break; 820 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 821 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 822 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 823 case 'i': show_interp = 1; break;
824 case 'b': show_bind = 1; break;
682 default: 825 default:
683 err("Invalid format specifier '%c' (byte %i)", 826 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 827 out_format[i], i+1);
685 } 828 }
686 } 829 }
687 830
688 /* construct our default format */ 831 /* construct our default format */
689 } else { 832 } else {
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 837 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 838 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 839 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 840 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 841 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
842 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 843 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 844 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 845 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 846 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 847
704 /* now lets actually do the scanning */ 848 /* now lets actually do the scanning */
849 if (scan_ldpath || (show_rpath && be_quiet))
850 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 851 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 852 if (scan_envpath) scanelf_envpath();
853 if (from_file) {
854 scanelf_from_file(from_file);
855 free(from_file);
856 from_file = *argv;
857 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 858 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 859 err("Nothing to scan !?");
709 while (optind < argc) 860 while (optind < argc)
710 scanelf_dir(argv[optind++]); 861 scanelf_dir(argv[optind++]);
711 862
712 /* clean up */ 863 /* clean up */
713 if (find_sym) { 864 if (find_sym) {
714 free(find_sym); 865 free(find_sym);
715 free(versioned_symname); 866 free(versioned_symname);
716 } 867 }
717 if (out_format) free(out_format); 868 if (out_format) free(out_format);
869 for (i = 0; ldpaths[i]; ++i)
870 free(ldpaths[i]);
718} 871}
719 872
720 873
721 874
722/* utility funcs */ 875/* utility funcs */
754 xstrcat(dst, my_app, curr_len); 907 xstrcat(dst, my_app, curr_len);
755} 908}
756static int xemptybuffer(const char *buff) 909static int xemptybuffer(const char *buff)
757{ 910{
758 long i; 911 long i;
759 for (i=0; buff[i]; ++i) 912 for (i = 0; buff[i]; ++i)
760 if (buff[i] != ' ') 913 if (buff[i] != ' ')
761 return 0; 914 return 0;
762 return 1; 915 return 1;
763} 916}
764 917

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

  ViewVC Help
Powered by ViewVC 1.1.20