/[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.61 Revision 1.74
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.61 2005/05/28 22:09:36 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.74 2005/06/05 09:42:06 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
34#include <dirent.h> 33#include <dirent.h>
35#include <getopt.h> 34#include <getopt.h>
36#include <assert.h> 35#include <assert.h>
37#include "paxelf.h" 36#include "paxelf.h"
38 37
39static const char *rcsid = "$Id: scanelf.c,v 1.61 2005/05/28 22:09:36 solar Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.74 2005/06/05 09:42:06 vapier Exp $";
40#define argv0 "scanelf" 39#define argv0 "scanelf"
40
41#define IS_MODIFIER(c) (c == '%' || c == '#')
41 42
42 43
43 44
44/* prototypes */ 45/* prototypes */
45static void scanelf_file(const char *filename); 46static void scanelf_file(const char *filename);
59static char scan_envpath = 0; 60static char scan_envpath = 0;
60static char scan_symlink = 1; 61static char scan_symlink = 1;
61static char dir_recurse = 0; 62static char dir_recurse = 0;
62static char dir_crossmount = 1; 63static char dir_crossmount = 1;
63static char show_pax = 0; 64static char show_pax = 0;
64static char show_stack = 0; 65static char show_phdr = 0;
65static char show_textrel = 0; 66static char show_textrel = 0;
66static char show_rpath = 0; 67static char show_rpath = 0;
67static char show_needed = 0; 68static char show_needed = 0;
68static char show_interp = 0; 69static char show_interp = 0;
69static char show_bind = 0; 70static char show_bind = 0;
70static char show_banner = 1; 71static char show_banner = 1;
71static char be_quiet = 0; 72static char be_quiet = 0;
72static char be_verbose = 0; 73static char be_verbose = 0;
74static char be_wewy_wewy_quiet = 0;
73static char *find_sym = NULL, *versioned_symname = NULL; 75static char *find_sym = NULL, *versioned_symname = NULL;
76static char *find_lib = NULL;
74static char *out_format = NULL; 77static char *out_format = NULL;
78static char *search_path = NULL;
79
75 80
76 81
77/* sub-funcs for scanelf_file() */ 82/* sub-funcs for scanelf_file() */
78static char *scanelf_file_pax(elfobj *elf, char *found_pax) 83static char *scanelf_file_pax(elfobj *elf, char *found_pax)
79{ 84{
121 if (be_quiet && !shown) 126 if (be_quiet && !shown)
122 return NULL; 127 return NULL;
123 return ret; 128 return ret;
124 129
125} 130}
126static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro) 131static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
127{ 132{
128 static char ret[8] = "--- ---"; 133 static char ret[12];
129 char *found; 134 char *found;
130 unsigned long i, off, shown; 135 unsigned long i, off, shown, check_flags;
136 unsigned char multi_stack, multi_relro, multi_load;
131 137
132 if (!show_stack) return NULL; 138 if (!show_phdr) return NULL;
139
140 memcpy(ret, "--- --- ---\0", 12);
133 141
134 shown = 0; 142 shown = 0;
143 multi_stack = multi_relro = multi_load = 0;
135 144
136 if (elf->phdr) { 145 if (elf->phdr) {
137#define SHOW_STACK(B) \ 146#define SHOW_PHDR(B) \
138 if (elf->elf_class == ELFCLASS ## B) { \ 147 if (elf->elf_class == ELFCLASS ## B) { \
139 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 148 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
140 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 149 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
150 uint32_t flags; \
141 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 151 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
142 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 152 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
153 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
143 found = found_stack; \ 154 found = found_phdr; \
144 off = 0; \ 155 off = 0; \
156 check_flags = PF_X; \
145 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 157 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
158 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
146 found = found_relro; \ 159 found = found_relro; \
147 off = 4; \ 160 off = 4; \
161 check_flags = PF_X; \
162 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
163 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
164 found = found_load; \
165 off = 8; \
166 check_flags = PF_W|PF_X; \
148 } else \ 167 } else \
149 continue; \ 168 continue; \
150 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 169 flags = EGET(phdr[i].p_flags); \
170 if (be_quiet && ((flags & check_flags) != check_flags)) \
151 continue; \ 171 continue; \
152 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 172 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
153 *found = 1; \ 173 *found = 1; \
154 ++shown; \ 174 ++shown; \
155 } \ 175 } \
156 } 176 }
157 SHOW_STACK(32) 177 SHOW_PHDR(32)
158 SHOW_STACK(64) 178 SHOW_PHDR(64)
159 } 179 }
160 180
161 if (be_quiet && !shown) 181 if (be_quiet && !shown)
162 return NULL; 182 return NULL;
163 else 183 else
164 return ret; 184 return ret;
165} 185}
166static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 186static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
167{ 187{
168 static char *ret = "TEXTREL"; 188 static char ret[] = "TEXTREL";
169 unsigned long i; 189 unsigned long i;
170 190
171 if (!show_textrel) return NULL; 191 if (!show_textrel) return NULL;
172 192
173 if (elf->phdr) { 193 if (elf->phdr) {
184 dyn = DYN ## B (elf->data + offset); \ 204 dyn = DYN ## B (elf->data + offset); \
185 while (EGET(dyn->d_tag) != DT_NULL) { \ 205 while (EGET(dyn->d_tag) != DT_NULL) { \
186 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 206 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
187 *found_textrel = 1; \ 207 *found_textrel = 1; \
188 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 208 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
189 return ret; \ 209 return (be_wewy_wewy_quiet ? NULL : ret); \
190 } \ 210 } \
191 ++dyn; \ 211 ++dyn; \
192 } \ 212 } \
193 } } 213 } }
194 SHOW_TEXTREL(32) 214 SHOW_TEXTREL(32)
195 SHOW_TEXTREL(64) 215 SHOW_TEXTREL(64)
196 } 216 }
197 217
198 if (be_quiet) 218 if (be_quiet || be_wewy_wewy_quiet)
199 return NULL; 219 return NULL;
200 else 220 else
201 return " - "; 221 return (char *)" - ";
202} 222}
203static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 223static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
204{ 224{
205 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
206 unsigned long i, s; 225 unsigned long i, s;
207 char *rpath, *runpath, **r; 226 char *rpath, *runpath, **r;
208 void *strtbl_void; 227 void *strtbl_void;
209 228
210 if (!show_rpath) return; 229 if (!show_rpath) return;
238 ++dyn; \ 257 ++dyn; \
239 continue; \ 258 continue; \
240 } \ 259 } \
241 /* Verify the memory is somewhat sane */ \ 260 /* Verify the memory is somewhat sane */ \
242 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 261 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
243 if (offset < elf->len) { \ 262 if (offset < (Elf ## B ## _Off)elf->len) { \
244 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 263 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
245 *r = (char*)(elf->data + offset); \ 264 *r = (char*)(elf->data + offset); \
246 /* If quiet, don't output paths in ld.so.conf */ \ 265 /* If quiet, don't output paths in ld.so.conf */ \
247 if (be_quiet) \ 266 if (be_quiet) { \
267 size_t len; \
268 char *start, *end; \
248 for (s = 0; ldpaths[s]; ++s) \ 269 for (s = 0; *r && ldpaths[s]; ++s) { \
249 if (!strcmp(ldpaths[s], *r)) { \ 270 /* scan each path in : delimited list */ \
250 *r = NULL; \ 271 start = *r; \
272 end = strchr(start, ':'); \
273 while ((start && ((end = strchr(start, ':')) != NULL)) || start) { \
274 len = (end ? abs(end - start) : strlen(start)); \
275 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
276 *r = (end ? end + 1 : NULL); \
251 break; \ 277 break; \
278 } \
279 start = (end ? start + len + 1 : NULL); \
252 } \ 280 } \
281 } \
282 } \
253 if (*r) *found_rpath = 1; \ 283 if (*r) *found_rpath = 1; \
254 } \ 284 } \
255 ++dyn; \ 285 ++dyn; \
256 } \ 286 } \
257 } } 287 } }
258 SHOW_RPATH(32) 288 SHOW_RPATH(32)
259 SHOW_RPATH(64) 289 SHOW_RPATH(64)
260 } 290 }
291
292 if (be_wewy_wewy_quiet) return;
261 293
262 if (rpath && runpath) { 294 if (rpath && runpath) {
263 if (!strcmp(rpath, runpath)) { 295 if (!strcmp(rpath, runpath)) {
264 xstrcat(ret, runpath, ret_len); 296 xstrcat(ret, runpath, ret_len);
265 } else { 297 } else {
273 } else if (rpath || runpath) 305 } else if (rpath || runpath)
274 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 306 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
275 else if (!be_quiet) 307 else if (!be_quiet)
276 xstrcat(ret, " - ", ret_len); 308 xstrcat(ret, " - ", ret_len);
277} 309}
278static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 310static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
279{ 311{
280 unsigned long i; 312 unsigned long i;
281 char *needed; 313 char *needed;
282 void *strtbl_void; 314 void *strtbl_void;
283 315
284 if (!show_needed) return; 316 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
285 317
286 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 318 strtbl_void = elf_findsecbyname(elf, ".dynstr");
287 319
288 if (elf->phdr && strtbl_void) { 320 if (elf->phdr && strtbl_void) {
289#define SHOW_NEEDED(B) \ 321#define SHOW_NEEDED(B) \
299 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 331 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
300 dyn = DYN ## B (elf->data + offset); \ 332 dyn = DYN ## B (elf->data + offset); \
301 while (EGET(dyn->d_tag) != DT_NULL) { \ 333 while (EGET(dyn->d_tag) != DT_NULL) { \
302 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 334 if (EGET(dyn->d_tag) == DT_NEEDED) { \
303 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 335 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
304 if (offset >= elf->len) { \ 336 if (offset >= (Elf ## B ## _Off)elf->len) { \
305 ++dyn; \ 337 ++dyn; \
306 continue; \ 338 continue; \
307 } \ 339 } \
308 needed = (char*)(elf->data + offset); \ 340 needed = (char*)(elf->data + offset); \
341 if (op == 0) { \
342 if (!be_wewy_wewy_quiet) { \
309 if (*found_needed) xchrcat(ret, ',', ret_len); \ 343 if (*found_needed) xchrcat(ret, ',', ret_len); \
310 xstrcat(ret, needed, ret_len); \ 344 xstrcat(ret, needed, ret_len); \
345 } \
311 *found_needed = 1; \ 346 *found_needed = 1; \
347 } else { \
348 if (strcmp(find_lib, needed)) return NULL; \
349 *found_lib = 1; \
350 return (be_wewy_wewy_quiet ? NULL : find_lib); \
351 } \
312 } \ 352 } \
313 ++dyn; \ 353 ++dyn; \
314 } \ 354 } \
315 } } 355 } }
316 SHOW_NEEDED(32) 356 SHOW_NEEDED(32)
317 SHOW_NEEDED(64) 357 SHOW_NEEDED(64)
318 } 358 }
359
360 return NULL;
319} 361}
320static char *scanelf_file_interp(elfobj *elf, char *found_interp) 362static char *scanelf_file_interp(elfobj *elf, char *found_interp)
321{ 363{
322 void *strtbl_void; 364 void *strtbl_void;
323 365
328 if (strtbl_void) { 370 if (strtbl_void) {
329#define SHOW_INTERP(B) \ 371#define SHOW_INTERP(B) \
330 if (elf->elf_class == ELFCLASS ## B) { \ 372 if (elf->elf_class == ELFCLASS ## B) { \
331 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 373 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
332 *found_interp = 1; \ 374 *found_interp = 1; \
333 return elf->data + EGET(strtbl->sh_offset); \ 375 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
334 } 376 }
335 SHOW_INTERP(32) 377 SHOW_INTERP(32)
336 SHOW_INTERP(64) 378 SHOW_INTERP(64)
337 } 379 }
338 return NULL; 380 return NULL;
360 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 402 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
361 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \ 403 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
362 { \ 404 { \
363 if (be_quiet) return NULL; \ 405 if (be_quiet) return NULL; \
364 *found_bind = 1; \ 406 *found_bind = 1; \
365 return "NOW"; \ 407 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
366 } \ 408 } \
367 ++dyn; \ 409 ++dyn; \
368 } \ 410 } \
369 } \ 411 } \
370 } 412 }
371 SHOW_BIND(32) 413 SHOW_BIND(32)
372 SHOW_BIND(64) 414 SHOW_BIND(64)
373 415
416 if (be_wewy_wewy_quiet) return NULL;
417
374 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 418 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
375 return NULL; 419 return NULL;
376 } else { 420 } else {
377 *found_bind = 1; 421 *found_bind = 1;
378 return "LAZY"; 422 return (char *) "LAZY";
379 } 423 }
380} 424}
381static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 425static char *scanelf_file_sym(elfobj *elf, char *found_sym)
382{ 426{
383 unsigned long i; 427 unsigned long i;
384 void *symtab_void, *strtab_void; 428 void *symtab_void, *strtab_void;
385 429
386 if (!find_sym) return NULL; 430 if (!find_sym) return NULL;
387 431
432 /* debug sections */
388 symtab_void = elf_findsecbyname(elf, ".symtab"); 433 symtab_void = elf_findsecbyname(elf, ".symtab");
389 strtab_void = elf_findsecbyname(elf, ".strtab"); 434 strtab_void = elf_findsecbyname(elf, ".strtab");
435 /* fall back to runtime sections */
436 if (!symtab_void || !strtab_void) {
437 symtab_void = elf_findsecbyname(elf, ".dynsym");
438 strtab_void = elf_findsecbyname(elf, ".dynstr");
439 }
390 440
391 if (symtab_void && strtab_void) { 441 if (symtab_void && strtab_void) {
392 char *base, *basemem; 442 char *base, *basemem;
393 basemem = xstrdup(filename); 443 basemem = xstrdup(elf->filename);
394 base = basename(basemem); 444 base = basename(basemem);
395#define FIND_SYM(B) \ 445#define FIND_SYM(B) \
396 if (elf->elf_class == ELFCLASS ## B) { \ 446 if (elf->elf_class == ELFCLASS ## B) { \
397 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 447 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
398 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 448 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
418 } } 468 } }
419 FIND_SYM(32) 469 FIND_SYM(32)
420 FIND_SYM(64) 470 FIND_SYM(64)
421 free(basemem); 471 free(basemem);
422 } 472 }
473
474 if (be_wewy_wewy_quiet) return NULL;
475
423 if (*find_sym != '*' && *found_sym) 476 if (*find_sym != '*' && *found_sym)
424 return find_sym; 477 return find_sym;
425 if (be_quiet) 478 if (be_quiet)
426 return NULL; 479 return NULL;
427 else 480 else
428 return " - "; 481 return (char *)" - ";
429} 482}
430/* scan an elf file and show all the fun stuff */ 483/* scan an elf file and show all the fun stuff */
431// #define prints(str) fputs(str, stdout)
432#define prints(str) write(fileno(stdout), str, strlen(str)) 484#define prints(str) write(fileno(stdout), str, strlen(str))
433static void scanelf_file(const char *filename) 485static void scanelf_file(const char *filename)
434{ 486{
435 unsigned long i; 487 unsigned long i;
436 char found_pax, found_stack, found_relro, found_textrel, 488 char found_pax, found_phdr, found_relro, found_load, found_textrel,
437 found_rpath, found_needed, found_interp, found_bind, 489 found_rpath, found_needed, found_interp, found_bind,
438 found_sym, found_file; 490 found_sym, found_lib, found_file;
439 elfobj *elf; 491 elfobj *elf;
440 struct stat st; 492 struct stat st;
441 static char *out_buffer = NULL; 493 static char *out_buffer = NULL;
442 static size_t out_len; 494 static size_t out_len;
443 495
454 if (!S_ISREG(st.st_mode)) { 506 if (!S_ISREG(st.st_mode)) {
455 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 507 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
456 return; 508 return;
457 } 509 }
458 510
459 found_pax = found_stack = found_relro = found_textrel = \ 511 found_pax = found_phdr = found_relro = found_load = \
460 found_rpath = found_needed = found_interp = found_bind = \ 512 found_textrel = found_rpath = found_needed = found_interp = \
461 found_sym = found_file = 0; 513 found_bind = found_sym = found_lib = found_file = 0;
462 514
463 /* verify this is real ELF */ 515 /* verify this is real ELF */
464 if ((elf = readelf(filename)) == NULL) { 516 if ((elf = readelf(filename)) == NULL) {
465 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 517 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
466 return; 518 return;
467 } 519 }
468 520
469 if (be_verbose > 1) 521 if (be_verbose > 1)
470 printf("%s: scanning file {%s,%s}\n", filename, 522 printf("%s: scanning file {%s,%s}\n", filename,
471 get_elfeitype(elf, EI_CLASS, elf->elf_class), 523 get_elfeitype(EI_CLASS, elf->elf_class),
472 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 524 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
473 else if (be_verbose) 525 else if (be_verbose)
474 printf("%s: scanning file\n", filename); 526 printf("%s: scanning file\n", filename);
475 527
476 /* init output buffer */ 528 /* init output buffer */
477 if (!out_buffer) { 529 if (!out_buffer) {
481 *out_buffer = '\0'; 533 *out_buffer = '\0';
482 534
483 /* show the header */ 535 /* show the header */
484 if (!be_quiet && show_banner) { 536 if (!be_quiet && show_banner) {
485 for (i = 0; out_format[i]; ++i) { 537 for (i = 0; out_format[i]; ++i) {
486 if (out_format[i] != '%') continue; 538 if (!IS_MODIFIER(out_format[i])) continue;
487 539
488 switch (out_format[++i]) { 540 switch (out_format[++i]) {
489 case '%': break; 541 case '%': break;
542 case '#': break;
543 case 'F':
544 case 'p':
490 case 'F': prints("FILE "); found_file = 1; break; 545 case 'f': prints("FILE "); found_file = 1; break;
491 case 'o': prints(" TYPE "); break; 546 case 'o': prints(" TYPE "); break;
492 case 'x': prints(" PAX "); break; 547 case 'x': prints(" PAX "); break;
493 case 'e': prints("STK/REL "); break; 548 case 'e': prints("STK/REL/PTL "); break;
494 case 't': prints("TEXTREL "); break; 549 case 't': prints("TEXTREL "); break;
495 case 'r': prints("RPATH "); break; 550 case 'r': prints("RPATH "); break;
496 case 'n': prints("NEEDED "); break; 551 case 'n': prints("NEEDED "); break;
497 case 'i': prints("INTERP "); break; 552 case 'i': prints("INTERP "); break;
498 case 'b': prints("BIND "); break; 553 case 'b': prints("BIND "); break;
499 case 's': prints("SYM "); break; 554 case 's': prints("SYM "); break;
555 case 'N': prints("LIB "); break;
500 } 556 }
501 } 557 }
502 if (!found_file) prints("FILE "); 558 if (!found_file) prints("FILE ");
503 prints("\n"); 559 prints("\n");
504 found_file = 0; 560 found_file = 0;
506 } 562 }
507 563
508 /* dump all the good stuff */ 564 /* dump all the good stuff */
509 for (i = 0; out_format[i]; ++i) { 565 for (i = 0; out_format[i]; ++i) {
510 const char *out; 566 const char *out;
567 const char *tmp;
511 568
512 /* make sure we trim leading spaces in quiet mode */ 569 /* make sure we trim leading spaces in quiet mode */
513 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 570 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
514 *out_buffer = '\0'; 571 *out_buffer = '\0';
515 572
516 if (out_format[i] != '%') { 573 if (!IS_MODIFIER(out_format[i])) {
517 xchrcat(&out_buffer, out_format[i], &out_len); 574 xchrcat(&out_buffer, out_format[i], &out_len);
518 continue; 575 continue;
519 } 576 }
520 577
521 out = NULL; 578 out = NULL;
579 be_wewy_wewy_quiet = (out_format[i] == '#');
522 switch (out_format[++i]) { 580 switch (out_format[++i]) {
581 case '%':
582 case '#':
523 case '%': xchrcat(&out_buffer, '%', &out_len); break; 583 xchrcat(&out_buffer, out_format[i], &out_len); break;
524 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 584 case 'F':
585 if (be_wewy_wewy_quiet) break;
586 found_file = 1;
587 xstrcat(&out_buffer, filename, &out_len);
588 break;
589 case 'p':
590 if (be_wewy_wewy_quiet) break;
591 found_file = 1;
592 tmp = filename;
593 if (search_path) {
594 ssize_t len_search = strlen(search_path);
595 ssize_t len_file = strlen(filename);
596 if (!strncmp(filename, search_path, len_search) && \
597 len_file > len_search)
598 tmp += len_search;
599 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
600 }
601 xstrcat(&out_buffer, tmp, &out_len);
602 break;
603 case 'f':
604 if (be_wewy_wewy_quiet) break;
605 found_file = 1;
606 tmp = strrchr(filename, '/');
607 tmp = (tmp == NULL ? filename : tmp+1);
608 xstrcat(&out_buffer, tmp, &out_len);
609 break;
525 case 'o': out = get_elfetype(elf); break; 610 case 'o': out = get_elfetype(elf); break;
526 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 611 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
527 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 612 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
528 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 613 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
529 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 614 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
615 case 'n':
530 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 616 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
531 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 617 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
532 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 618 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
533 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 619 case 's': out = scanelf_file_sym(elf, &found_sym); break;
534 } 620 }
535 if (out) xstrcat(&out_buffer, out, &out_len); 621 if (out) xstrcat(&out_buffer, out, &out_len);
536 } 622 }
537 623
538#define FOUND_SOMETHING() \ 624#define FOUND_SOMETHING() \
539 (found_pax || found_stack || found_textrel || found_rpath || \ 625 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
540 found_needed || found_interp || found_bind || found_sym) 626 found_rpath || found_needed || found_interp || found_bind || found_sym || found_lib)
541 627
542 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 628 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
543 xchrcat(&out_buffer, ' ', &out_len); 629 xchrcat(&out_buffer, ' ', &out_len);
544 xstrcat(&out_buffer, filename, &out_len); 630 xstrcat(&out_buffer, filename, &out_len);
545 } 631 }
581 while ((dentry = readdir(dir))) { 667 while ((dentry = readdir(dir))) {
582 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 668 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
583 continue; 669 continue;
584 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 670 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
585 if (len >= sizeof(buf)) { 671 if (len >= sizeof(buf)) {
586 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 672 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, len, sizeof(buf));
587 continue; 673 continue;
588 } 674 }
589 sprintf(buf, "%s/%s", path, dentry->d_name); 675 sprintf(buf, "%s/%s", path, dentry->d_name);
590 if (lstat(buf, &st) != -1) { 676 if (lstat(buf, &st) != -1) {
591 if (S_ISREG(st.st_mode)) 677 if (S_ISREG(st.st_mode))
611 return 1; 697 return 1;
612 698
613 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 699 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
614 if ((p = strchr(path, '\n')) != NULL) 700 if ((p = strchr(path, '\n')) != NULL)
615 *p = 0; 701 *p = 0;
702 search_path = path;
616 scanelf_dir(path); 703 scanelf_dir(path);
617 } 704 }
618 if (fp != stdin) 705 if (fp != stdin)
619 fclose(fp); 706 fclose(fp);
620 return 0; 707 return 0;
692} 779}
693 780
694 781
695 782
696/* usage / invocation handling functions */ 783/* usage / invocation handling functions */
697#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV" 784#define PARSE_FLAGS "plRmyxetrnibs:N:aqvF:f:o:BhV"
698#define a_argument required_argument 785#define a_argument required_argument
699static struct option const long_opts[] = { 786static struct option const long_opts[] = {
700 {"path", no_argument, NULL, 'p'}, 787 {"path", no_argument, NULL, 'p'},
701 {"ldpath", no_argument, NULL, 'l'}, 788 {"ldpath", no_argument, NULL, 'l'},
702 {"recursive", no_argument, NULL, 'R'}, 789 {"recursive", no_argument, NULL, 'R'},
708 {"rpath", no_argument, NULL, 'r'}, 795 {"rpath", no_argument, NULL, 'r'},
709 {"needed", no_argument, NULL, 'n'}, 796 {"needed", no_argument, NULL, 'n'},
710 {"interp", no_argument, NULL, 'i'}, 797 {"interp", no_argument, NULL, 'i'},
711 {"bind", no_argument, NULL, 'b'}, 798 {"bind", no_argument, NULL, 'b'},
712 {"symbol", a_argument, NULL, 's'}, 799 {"symbol", a_argument, NULL, 's'},
800 {"lib", a_argument, NULL, 'N'},
713 {"all", no_argument, NULL, 'a'}, 801 {"all", no_argument, NULL, 'a'},
714 {"quiet", no_argument, NULL, 'q'}, 802 {"quiet", no_argument, NULL, 'q'},
715 {"verbose", no_argument, NULL, 'v'}, 803 {"verbose", no_argument, NULL, 'v'},
716 {"format", a_argument, NULL, 'F'}, 804 {"format", a_argument, NULL, 'F'},
717 {"from", a_argument, NULL, 'f'}, 805 {"from", a_argument, NULL, 'f'},
720 {"help", no_argument, NULL, 'h'}, 808 {"help", no_argument, NULL, 'h'},
721 {"version", no_argument, NULL, 'V'}, 809 {"version", no_argument, NULL, 'V'},
722 {NULL, no_argument, NULL, 0x0} 810 {NULL, no_argument, NULL, 0x0}
723}; 811};
724 812
725static char *opts_help[] = { 813static const char *opts_help[] = {
726 "Scan all directories in PATH environment", 814 "Scan all directories in PATH environment",
727 "Scan all directories in /etc/ld.so.conf", 815 "Scan all directories in /etc/ld.so.conf",
728 "Scan directories recursively", 816 "Scan directories recursively",
729 "Don't recursively cross mount points", 817 "Don't recursively cross mount points",
730 "Don't scan symlinks\n", 818 "Don't scan symlinks\n",
731 "Print PaX markings", 819 "Print PaX markings",
732 "Print GNU_STACK markings", 820 "Print GNU_STACK/PT_LOAD markings",
733 "Print TEXTREL information", 821 "Print TEXTREL information",
734 "Print RPATH information", 822 "Print RPATH information",
735 "Print NEEDED information", 823 "Print NEEDED information",
736 "Print INTERP information", 824 "Print INTERP information",
737 "Print BIND information", 825 "Print BIND information",
738 "Find a specified symbol", 826 "Find a specified symbol",
827 "Find a specified library",
739 "Print all scanned info (-x -e -t -r -n -i -b)\n", 828 "Print all scanned info (-x -e -t -r -n -i -b)\n",
740 "Only output 'bad' things", 829 "Only output 'bad' things",
741 "Be verbose (can be specified more than once)", 830 "Be verbose (can be specified more than once)",
742 "Use specified format for output", 831 "Use specified format for output",
743 "Read input stream from a filename", 832 "Read input stream from a filename",
765 854
766 if (status != EXIT_SUCCESS) 855 if (status != EXIT_SUCCESS)
767 exit(status); 856 exit(status);
768 857
769 puts("\nThe format modifiers for the -F option are:"); 858 puts("\nThe format modifiers for the -F option are:");
770 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO"); 859 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
771 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED"); 860 puts(" t TEXTREL \tr RPATH \tn NEEDED");
772 puts(" %i INTERP \t%b BIND \t%s symbol"); 861 puts(" i INTERP \tb BIND \ts symbol");
862 puts(" N library \to Type");
863 puts(" p filename (with search path removed)");
864 puts(" f base filename");
865 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
773 866
774 exit(status); 867 exit(status);
775} 868}
776 869
777/* parse command line arguments and preform needed actions */ 870/* parse command line arguments and preform needed actions */
790 __FILE__, __DATE__, rcsid, argv0); 883 __FILE__, __DATE__, rcsid, argv0);
791 exit(EXIT_SUCCESS); 884 exit(EXIT_SUCCESS);
792 break; 885 break;
793 case 'h': usage(EXIT_SUCCESS); break; 886 case 'h': usage(EXIT_SUCCESS); break;
794 case 'f': 887 case 'f':
795 if (from_file == NULL) 888 if (from_file) err("Don't specify -f twice");
796 from_file = xstrdup(optarg); 889 from_file = xstrdup(optarg);
797 break; 890 break;
798 case 'o': { 891 case 'o': {
799 FILE *fp = NULL; 892 FILE *fp = NULL;
800 fp = freopen(optarg, "w", stdout); 893 if ((fp = freopen(optarg, "w", stdout)) == NULL)
801 if (fp == NULL)
802 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 894 err("Could not open output stream '%s': %s", optarg, strerror(errno));
803 stdout = fp; 895 SET_STDOUT(fp);
804 break; 896 break;
805 } 897 }
806 898
807 case 's': { 899 case 's': {
808 size_t len; 900 size_t len;
901 if (find_sym) err("Don't specify -s twice");
809 find_sym = xstrdup(optarg); 902 find_sym = xstrdup(optarg);
810 len = strlen(find_sym) + 1; 903 len = strlen(find_sym) + 1;
811 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 904 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
812 sprintf(versioned_symname, "%s@", find_sym); 905 sprintf(versioned_symname, "%s@", find_sym);
813 break; 906 break;
814 } 907 }
908 case 'N': {
909 if (find_lib) err("Don't specify -N twice");
910 find_lib = xstrdup(optarg);
911 break;
912 }
815 913
816 case 'F': { 914 case 'F': {
817 if (!out_format) 915 if (out_format) err("Don't specify -F twice");
818 out_format = xstrdup(optarg); 916 out_format = xstrdup(optarg);
819 break; 917 break;
820 } 918 }
821 919
822 case 'y': scan_symlink = 0; break; 920 case 'y': scan_symlink = 0; break;
823 case 'B': show_banner = 0; break; 921 case 'B': show_banner = 0; break;
824 case 'l': scan_ldpath = 1; break; 922 case 'l': scan_ldpath = 1; break;
825 case 'p': scan_envpath = 1; break; 923 case 'p': scan_envpath = 1; break;
826 case 'R': dir_recurse = 1; break; 924 case 'R': dir_recurse = 1; break;
827 case 'm': dir_crossmount = 0; break; 925 case 'm': dir_crossmount = 0; break;
828 case 'x': show_pax = 1; break; 926 case 'x': show_pax = 1; break;
829 case 'e': show_stack = 1; break; 927 case 'e': show_phdr = 1; break;
830 case 't': show_textrel = 1; break; 928 case 't': show_textrel = 1; break;
831 case 'r': show_rpath = 1; break; 929 case 'r': show_rpath = 1; break;
832 case 'n': show_needed = 1; break; 930 case 'n': show_needed = 1; break;
833 case 'i': show_interp = 1; break; 931 case 'i': show_interp = 1; break;
834 case 'b': show_bind = 1; break; 932 case 'b': show_bind = 1; break;
835 case 'q': be_quiet = 1; break; 933 case 'q': be_quiet = 1; break;
836 case 'v': be_verbose = (be_verbose % 20) + 1; break; 934 case 'v': be_verbose = (be_verbose % 20) + 1; break;
837 case 'a': show_pax = show_stack = show_textrel = show_rpath = \ 935 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \
838 show_needed = show_interp = show_bind = 1; break; 936 show_needed = show_interp = show_bind = 1; break;
839 937
840 case ':': 938 case ':':
841 err("Option missing parameter\n"); 939 err("Option missing parameter\n");
842 case '?': 940 case '?':
846 } 944 }
847 } 945 }
848 946
849 /* let the format option override all other options */ 947 /* let the format option override all other options */
850 if (out_format) { 948 if (out_format) {
851 show_pax = show_stack = show_textrel = show_rpath = \ 949 show_pax = show_phdr = show_textrel = show_rpath = \
852 show_needed = show_interp = show_bind = 0; 950 show_needed = show_interp = show_bind = 0;
853 for (i = 0; out_format[i]; ++i) { 951 for (i = 0; out_format[i]; ++i) {
854 if (out_format[i] != '%') continue; 952 if (!IS_MODIFIER(out_format[i])) continue;
855 953
856 switch (out_format[++i]) { 954 switch (out_format[++i]) {
857 case '%': break; 955 case '%': break;
956 case '#': break;
858 case 'F': break; 957 case 'F': break;
958 case 'p': break;
959 case 'f': break;
859 case 's': break; 960 case 's': break;
961 case 'N': break;
860 case 'o': break; 962 case 'o': break;
861 case 'x': show_pax = 1; break; 963 case 'x': show_pax = 1; break;
862 case 'e': show_stack = 1; break; 964 case 'e': show_phdr = 1; break;
863 case 't': show_textrel = 1; break; 965 case 't': show_textrel = 1; break;
864 case 'r': show_rpath = 1; break; 966 case 'r': show_rpath = 1; break;
865 case 'n': show_needed = 1; break; 967 case 'n': show_needed = 1; break;
866 case 'i': show_interp = 1; break; 968 case 'i': show_interp = 1; break;
867 case 'b': show_bind = 1; break; 969 case 'b': show_bind = 1; break;
875 } else { 977 } else {
876 size_t fmt_len = 30; 978 size_t fmt_len = 30;
877 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 979 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
878 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 980 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
879 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 981 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
880 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 982 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
881 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 983 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
882 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 984 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
883 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 985 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
884 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 986 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
885 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 987 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
886 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 988 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
989 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
887 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 990 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
888 } 991 }
889 if (be_verbose > 2) printf("Format: %s\n", out_format); 992 if (be_verbose > 2) printf("Format: %s\n", out_format);
890 993
891 /* now lets actually do the scanning */ 994 /* now lets actually do the scanning */
898 free(from_file); 1001 free(from_file);
899 from_file = *argv; 1002 from_file = *argv;
900 } 1003 }
901 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1004 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
902 err("Nothing to scan !?"); 1005 err("Nothing to scan !?");
903 while (optind < argc) 1006 while (optind < argc) {
904 scanelf_dir(argv[optind++]); 1007 search_path = argv[optind++];
1008 scanelf_dir(search_path);
1009 }
905 1010
906 /* clean up */ 1011 /* clean up */
907 if (find_sym) { 1012 if (find_sym) {
908 free(find_sym); 1013 free(find_sym);
909 free(versioned_symname); 1014 free(versioned_symname);
910 } 1015 }
1016 if (find_lib) free(find_lib);
911 if (out_format) free(out_format); 1017 if (out_format) free(out_format);
912 for (i = 0; ldpaths[i]; ++i) 1018 for (i = 0; ldpaths[i]; ++i)
913 free(ldpaths[i]); 1019 free(ldpaths[i]);
914} 1020}
915 1021
930 return ret; 1036 return ret;
931} 1037}
932 1038
933static void xstrcat(char **dst, const char *src, size_t *curr_len) 1039static void xstrcat(char **dst, const char *src, size_t *curr_len)
934{ 1040{
935 long new_len; 1041 size_t new_len;
936 1042
937 new_len = strlen(*dst) + strlen(src); 1043 new_len = strlen(*dst) + strlen(src);
938 if (*curr_len <= new_len) { 1044 if (*curr_len <= new_len) {
939 *curr_len = new_len + (*curr_len / 2); 1045 *curr_len = new_len + (*curr_len / 2);
940 *dst = realloc(*dst, *curr_len); 1046 *dst = realloc(*dst, *curr_len);
952 my_app[1] = '\0'; 1058 my_app[1] = '\0';
953 xstrcat(dst, my_app, curr_len); 1059 xstrcat(dst, my_app, curr_len);
954} 1060}
955 1061
956 1062
1063
957int main(int argc, char *argv[]) 1064int main(int argc, char *argv[])
958{ 1065{
959 if (argc < 2) 1066 if (argc < 2)
960 usage(EXIT_FAILURE); 1067 usage(EXIT_FAILURE);
961 parseargs(argc, argv); 1068 parseargs(argc, argv);
962 fclose(stdout); 1069 fclose(stdout);
963#ifdef __BOUNDS_CHECKING_ON 1070#ifdef __BOUNDS_CHECKING_ON
964 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 1071 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
965#endif 1072#endif
966 return EXIT_SUCCESS; 1073 return EXIT_SUCCESS;
967} 1074}

Legend:
Removed from v.1.61  
changed lines
  Added in v.1.74

  ViewVC Help
Powered by ViewVC 1.1.20