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

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

  ViewVC Help
Powered by ViewVC 1.1.20