/[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.54
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.54 2005/05/18 21:16:32 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.54 2005/05/18 21:16:32 vapier Exp $";
39#define argv0 "scanelf" 39#define argv0 "scanelf"
40 40
41 41
42 42
43/* prototypes */ 43/* prototypes */
49static void parseargs(int argc, char *argv[]); 49static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 50static char *xstrdup(char *s);
51static void *xmalloc(size_t size); 51static void *xmalloc(size_t size);
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);
55 54
56/* variables to control behavior */ 55/* variables to control behavior */
56static char *ldpaths[256];
57static char scan_ldpath = 0; 57static char scan_ldpath = 0;
58static char scan_envpath = 0; 58static char scan_envpath = 0;
59static char scan_symlink = 1; 59static char scan_symlink = 1;
60static char dir_recurse = 0; 60static char dir_recurse = 0;
61static char dir_crossmount = 1; 61static char dir_crossmount = 1;
63static char show_stack = 0; 63static char show_stack = 0;
64static char show_textrel = 0; 64static char show_textrel = 0;
65static char show_rpath = 0; 65static char show_rpath = 0;
66static char show_needed = 0; 66static char show_needed = 0;
67static char show_interp = 0; 67static char show_interp = 0;
68static char show_bind = 0;
68static char show_banner = 1; 69static char show_banner = 1;
69static char be_quiet = 0; 70static char be_quiet = 0;
70static char be_verbose = 0; 71static char be_verbose = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 72static char *find_sym = NULL, *versioned_symname = NULL;
72static char *out_format = NULL; 73static char *out_format = NULL;
90} 91}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro) 92static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{ 93{
93 static char ret[8]; 94 static char ret[8];
94 char *found; 95 char *found;
95 int i, off, shown; 96 unsigned long i, off, shown;
96 97
97 if (!show_stack) return NULL; 98 if (!show_stack) return NULL;
98 99
99 shown = 0; 100 shown = 0;
100 strcpy(ret, "--- ---"); 101 strcpy(ret, "--- ---");
102
103 if (elf->phdr) {
101#define SHOW_STACK(B) \ 104#define SHOW_STACK(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 105 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 106 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 107 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 108 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 109 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
107 found = found_stack; \ 110 found = found_stack; \
108 off = 0; \ 111 off = 0; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 112 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
110 found = found_relro; \ 113 found = found_relro; \
111 off = 3; \ 114 off = 4; \
112 } else \ 115 } else \
113 continue; \ 116 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 117 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
115 continue; \ 118 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 119 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
118 ++shown; \ 121 ++shown; \
119 } \ 122 } \
120 } 123 }
121 SHOW_STACK(32) 124 SHOW_STACK(32)
122 SHOW_STACK(64) 125 SHOW_STACK(64)
126 }
127
123 if (be_quiet && !shown) 128 if (be_quiet && !shown)
124 return NULL; 129 return NULL;
125 else 130 else
126 return ret; 131 return ret;
127} 132}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 133static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 134{
130 static char *ret = "TEXTREL"; 135 static char *ret = "TEXTREL";
131 int i; 136 unsigned long i;
132 137
133 if (!show_textrel) return NULL; 138 if (!show_textrel) return NULL;
134 139
140 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 141#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 142 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 143 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 144 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 145 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
146 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 147 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 148 if (phdr[i].p_type != PT_DYNAMIC) continue; \
149 offset = EGET(phdr[i].p_offset); \
150 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 151 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 152 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 153 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 154 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 155 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 156 return ret; \
149 ++dyn; \ 158 ++dyn; \
150 } \ 159 } \
151 } } 160 } }
152 SHOW_TEXTREL(32) 161 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 162 SHOW_TEXTREL(64)
163 }
164
154 if (be_quiet) 165 if (be_quiet)
155 return NULL; 166 return NULL;
156 else 167 else
157 return " - "; 168 return " - ";
158} 169}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 170static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 171{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 172 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
162 int i; 173 unsigned long i, s;
163 char *rpath, *runpath; 174 char *rpath, *runpath, **r;
164 void *strtbl_void; 175 void *strtbl_void;
165 176
166 if (!show_rpath) return; 177 if (!show_rpath) return;
167 178
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 179 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 180 rpath = runpath = NULL;
170 181
171 if (strtbl_void) { 182 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 183#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 184 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 185 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 186 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 187 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 188 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
189 Elf ## B ## _Off offset; \
190 Elf ## B ## _Sxword word; \
191 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 192 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
193 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 194 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
195 offset = EGET(phdr[i].p_offset); \
196 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
197 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 198 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 199 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 200 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 201 r = &rpath; \
202 } else if (word == DT_RUNPATH) { \
203 r = &runpath; \
204 } else { \
205 ++dyn; \
206 continue; \
207 } \
208 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 209 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
210 if (offset < elf->len) { \
211 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
212 *r = (char*)(elf->data + offset); \
213 /* If quiet, don't output paths in ld.so.conf */ \
214 if (be_quiet) \
215 for (s = 0; ldpaths[s]; ++s) \
216 if (!strcmp(ldpaths[s], *r)) { \
217 *r = NULL; \
218 break; \
219 } \
185 *found_rpath = 1; \ 220 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 } \ 221 } \
191 ++dyn; \ 222 ++dyn; \
192 } \ 223 } \
193 } } 224 } }
194 SHOW_RPATH(32) 225 SHOW_RPATH(32)
211 else if (!be_quiet) 242 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 243 xstrcat(ret, " - ", ret_len);
213} 244}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 245static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
215{ 246{
216 int i; 247 unsigned long i;
217 char *needed; 248 char *needed;
218 void *strtbl_void; 249 void *strtbl_void;
219 250
220 if (!show_needed) return; 251 if (!show_needed) return;
221 252
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 253 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 254
224 if (strtbl_void) { 255 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 256#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 257 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 258 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 259 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 260 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 261 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
262 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 263 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 264 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
265 offset = EGET(phdr[i].p_offset); \
266 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 267 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 268 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 269 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 270 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
271 if (offset >= elf->len) { \
272 ++dyn; \
273 continue; \
274 } \
275 needed = (char*)(elf->data + offset); \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 276 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 277 xstrcat(ret, needed, ret_len); \
239 *found_needed = 1; \ 278 *found_needed = 1; \
240 } \ 279 } \
241 ++dyn; \ 280 ++dyn; \
263 SHOW_INTERP(32) 302 SHOW_INTERP(32)
264 SHOW_INTERP(64) 303 SHOW_INTERP(64)
265 } 304 }
266 return NULL; 305 return NULL;
267} 306}
307static char *scanelf_file_bind(elfobj *elf, char *found_bind)
308{
309 unsigned long i;
310 struct stat s;
311
312 if (!show_bind) return NULL;
313 if (!elf->phdr) 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#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 498 (found_pax || found_stack || found_textrel || found_rpath || \
414 found_rpath || found_needed || found_interp || found_sym) 499 found_needed || found_interp || found_bind || found_sym)
500
501 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
502 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 503 xstrcat(&out_buffer, filename, &out_len);
416 } 504 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 505 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
418 puts(out_buffer); 506 puts(out_buffer);
419 507
420 unreadelf(elf); 508 unreadelf(elf);
421} 509}
422 510
468 } 556 }
469 } 557 }
470 closedir(dir); 558 closedir(dir);
471} 559}
472 560
561static int scanelf_from_file(char *filename)
562{
563 FILE *fp = NULL;
564 char *p;
565 char path[_POSIX_PATH_MAX];
566
567 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
568 fp = stdin;
569 else if ((fp = fopen(filename, "r")) == NULL)
570 return 1;
571
572 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
573 if ((p = strchr(path, '\n')) != NULL)
574 *p = 0;
575 scanelf_dir(path);
576 }
577 if (fp != stdin)
578 fclose(fp);
579 return 0;
580}
581
582static void load_ld_so_conf()
583{
584 FILE *fp = NULL;
585 char *p;
586 char path[_POSIX_PATH_MAX];
587 int i = 0;
588
589 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
590 return;
591
592 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
593 if (*path != '/')
594 continue;
595
596 if ((p = strrchr(path, '\r')) != NULL)
597 *p = 0;
598 if ((p = strchr(path, '\n')) != NULL)
599 *p = 0;
600
601 ldpaths[i++] = xstrdup(path);
602
603 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
604 break;
605 }
606 ldpaths[i] = NULL;
607
608 fclose(fp);
609}
610
473/* scan /etc/ld.so.conf for paths */ 611/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 612static void scanelf_ldpath()
475{ 613{
476 char scan_l, scan_ul, scan_ull; 614 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 615 int i = 0;
478 FILE *fp;
479 616
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 617 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 618 err("Unable to load any paths from ld.so.conf");
482 619
483 scan_l = scan_ul = scan_ull = 0; 620 scan_l = scan_ul = scan_ull = 0;
484 621
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 622 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; 623 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 624 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 625 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 626 scanelf_dir(ldpaths[i]);
627 ++i;
496 } 628 }
497 free(path);
498 fclose(fp);
499 629
500 if (!scan_l) scanelf_dir("/lib"); 630 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 631 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 632 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 633}
521} 651}
522 652
523 653
524 654
525/* usage / invocation handling functions */ 655/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 656#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
527#define a_argument required_argument 657#define a_argument required_argument
528static struct option const long_opts[] = { 658static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 659 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 660 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 661 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 665 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 666 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 667 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 668 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 669 {"interp", no_argument, NULL, 'i'},
670 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 671 {"symbol", a_argument, NULL, 's'},
541 {"all", no_argument, NULL, 'a'}, 672 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 673 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 674 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 675 {"format", a_argument, NULL, 'F'},
676 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 677 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 678 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 679 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 680 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 681 {NULL, no_argument, NULL, 0x0}
558 "Print GNU_STACK markings", 690 "Print GNU_STACK markings",
559 "Print TEXTREL information", 691 "Print TEXTREL information",
560 "Print RPATH information", 692 "Print RPATH information",
561 "Print NEEDED information", 693 "Print NEEDED information",
562 "Print INTERP information", 694 "Print INTERP information",
695 "Print BIND information",
563 "Find a specified symbol", 696 "Find a specified symbol",
564 "Print all scanned info (-x -e -t -r)\n", 697 "Print all scanned info (-x -e -t -r -n -i)\n",
565 "Only output 'bad' things", 698 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 699 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 700 "Use specified format for output",
701 "Read input stream from a filename",
568 "Write output stream to a filename", 702 "Write output stream to a filename",
569 "Don't display the header", 703 "Don't display the header",
570 "Print this help and exit", 704 "Print this help and exit",
571 "Print version and exit", 705 "Print version and exit",
572 NULL 706 NULL
573}; 707};
574 708
575/* display usage and exit */ 709/* display usage and exit */
576static void usage(int status) 710static void usage(int status)
577{ 711{
578 int i; 712 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 713 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 714 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 715 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 716 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 717 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 718 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 719 long_opts[i].name, opts_help[i]);
586 else 720 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 721 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 722 long_opts[i].name, opts_help[i]);
723
724 if (status != EXIT_SUCCESS)
725 exit(status);
726
727 puts("\nThe format modifiers for the -F option are:");
728 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
729 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
730 puts(" %i INTERP \t%b BIND \t%s symbol");
731
589 exit(status); 732 exit(status);
590} 733}
591 734
592/* parse command line arguments and preform needed actions */ 735/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 736static void parseargs(int argc, char *argv[])
594{ 737{
595 int flag; 738 int i;
739 char *from_file = NULL;
596 740
597 opterr = 0; 741 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 742 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 743 switch (i) {
600 744
601 case 'V': 745 case 'V':
602 printf("%s compiled %s\n%s\n" 746 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 747 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 748 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 749 exit(EXIT_SUCCESS);
606 break; 750 break;
607 case 'h': usage(EXIT_SUCCESS); break; 751 case 'h': usage(EXIT_SUCCESS); break;
608 752 case 'f':
753 if (from_file == NULL)
754 from_file = xstrdup(optarg);
755 break;
609 case 'o': { 756 case 'o': {
610 FILE *fp = NULL; 757 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 758 fp = freopen(optarg, "w", stdout);
612 if (fp == NULL) 759 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 760 err("Could not open output stream '%s': %s", optarg, strerror(errno));
623 sprintf(versioned_symname, "%s@", find_sym); 770 sprintf(versioned_symname, "%s@", find_sym);
624 break; 771 break;
625 } 772 }
626 773
627 case 'F': { 774 case 'F': {
628 out_format = strdup(optarg); 775 out_format = xstrdup(optarg);
629 break; 776 break;
630 } 777 }
631 778
632 case 'y': scan_symlink = 0; break; 779 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 780 case 'B': show_banner = 0; break;
639 case 'e': show_stack = 1; break; 786 case 'e': show_stack = 1; break;
640 case 't': show_textrel = 1; break; 787 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 788 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 789 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 790 case 'i': show_interp = 1; break;
791 case 'b': show_bind = 1; break;
644 case 'q': be_quiet = 1; break; 792 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 793 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; 794 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
795 show_needed = show_interp = show_bind = 1; break;
647 796
648 case ':': 797 case ':':
649 warn("Option missing parameter\n"); 798 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 799 case '?':
653 warn("Unknown option\n"); 800 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 801 default:
657 err("Unhandled option '%c'", flag); 802 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 803 }
661 804 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 805
665 /* let the format option override all other options */ 806 /* let the format option override all other options */
666 if (out_format) { 807 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 808 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
668 for (flag=0; out_format[flag]; ++flag) { 809 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 810 if (out_format[i] != '%') continue;
670 811
671 switch (out_format[++flag]) { 812 switch (out_format[++i]) {
672 case '%': break; 813 case '%': break;
673 case 'F': break; 814 case 'F': break;
674 case 's': break; 815 case 's': break;
675 case 'o': break; 816 case 'o': break;
676 case 'x': show_pax = 1; break; 817 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 818 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break; 819 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 820 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 821 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 822 case 'i': show_interp = 1; break;
823 case 'b': show_bind = 1; break;
682 default: 824 default:
683 err("Invalid format specifier '%c' (byte %i)", 825 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 826 out_format[i], i+1);
685 } 827 }
686 } 828 }
687 829
688 /* construct our default format */ 830 /* construct our default format */
689 } else { 831 } else {
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 836 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 837 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 838 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 839 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 840 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
841 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 842 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 843 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 844 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 845 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 846
704 /* now lets actually do the scanning */ 847 /* now lets actually do the scanning */
848 if (scan_ldpath || (show_rpath && be_quiet))
849 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 850 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 851 if (scan_envpath) scanelf_envpath();
852 if (from_file) {
853 scanelf_from_file(from_file);
854 free(from_file);
855 from_file = *argv;
856 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 857 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 858 err("Nothing to scan !?");
709 while (optind < argc) 859 while (optind < argc)
710 scanelf_dir(argv[optind++]); 860 scanelf_dir(argv[optind++]);
711 861
712 /* clean up */ 862 /* clean up */
713 if (find_sym) { 863 if (find_sym) {
714 free(find_sym); 864 free(find_sym);
715 free(versioned_symname); 865 free(versioned_symname);
716 } 866 }
717 if (out_format) free(out_format); 867 if (out_format) free(out_format);
868 for (i = 0; ldpaths[i]; ++i)
869 free(ldpaths[i]);
718} 870}
719 871
720 872
721 873
722/* utility funcs */ 874/* utility funcs */
751 static char my_app[2]; 903 static char my_app[2];
752 my_app[0] = append; 904 my_app[0] = append;
753 my_app[1] = '\0'; 905 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 906 xstrcat(dst, my_app, curr_len);
755} 907}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764 908
765 909
766 910
767int main(int argc, char *argv[]) 911int main(int argc, char *argv[])
768{ 912{

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

  ViewVC Help
Powered by ViewVC 1.1.20