/[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.59
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.59 2005/05/25 21:58:03 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.59 2005/05/25 21:58:03 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;
88 89
89 return NULL; 90 return 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
102 if (elf->phdr) {
101#define SHOW_STACK(B) \ 103#define SHOW_STACK(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 104 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 105 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 106 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 107 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 108 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
107 found = found_stack; \ 109 found = found_stack; \
108 off = 0; \ 110 off = 0; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 111 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
110 found = found_relro; \ 112 found = found_relro; \
111 off = 3; \ 113 off = 4; \
112 } else \ 114 } else \
113 continue; \ 115 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 116 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
115 continue; \ 117 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 118 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
118 ++shown; \ 120 ++shown; \
119 } \ 121 } \
120 } 122 }
121 SHOW_STACK(32) 123 SHOW_STACK(32)
122 SHOW_STACK(64) 124 SHOW_STACK(64)
125 }
126
123 if (be_quiet && !shown) 127 if (be_quiet && !shown)
124 return NULL; 128 return NULL;
125 else 129 else
126 return ret; 130 return ret;
127} 131}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 132static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 133{
130 static char *ret = "TEXTREL"; 134 static char *ret = "TEXTREL";
131 int i; 135 unsigned long i;
132 136
133 if (!show_textrel) return NULL; 137 if (!show_textrel) return NULL;
134 138
139 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 140#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 141 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 142 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 143 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 144 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
145 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 146 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 147 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
148 offset = EGET(phdr[i].p_offset); \
149 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 150 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 151 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 152 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 153 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 154 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 155 return ret; \
149 ++dyn; \ 157 ++dyn; \
150 } \ 158 } \
151 } } 159 } }
152 SHOW_TEXTREL(32) 160 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 161 SHOW_TEXTREL(64)
162 }
163
154 if (be_quiet) 164 if (be_quiet)
155 return NULL; 165 return NULL;
156 else 166 else
157 return " - "; 167 return " - ";
158} 168}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 169static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 170{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 171 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
162 int i; 172 unsigned long i, s;
163 char *rpath, *runpath; 173 char *rpath, *runpath, **r;
164 void *strtbl_void; 174 void *strtbl_void;
165 175
166 if (!show_rpath) return; 176 if (!show_rpath) return;
167 177
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 178 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 179 rpath = runpath = NULL;
170 180
171 if (strtbl_void) { 181 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 182#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 183 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 184 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 185 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 186 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 187 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
188 Elf ## B ## _Off offset; \
189 Elf ## B ## _Sxword word; \
190 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 191 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
192 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 193 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
194 offset = EGET(phdr[i].p_offset); \
195 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
196 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 197 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 198 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 199 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 200 r = &rpath; \
201 } else if (word == DT_RUNPATH) { \
202 r = &runpath; \
203 } else { \
204 ++dyn; \
205 continue; \
206 } \
207 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 208 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
209 if (offset < elf->len) { \
210 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
211 *r = (char*)(elf->data + offset); \
212 /* If quiet, don't output paths in ld.so.conf */ \
213 if (be_quiet) \
214 for (s = 0; ldpaths[s]; ++s) \
215 if (!strcmp(ldpaths[s], *r)) { \
216 *r = NULL; \
217 break; \
218 } \
185 *found_rpath = 1; \ 219 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 } \ 220 } \
191 ++dyn; \ 221 ++dyn; \
192 } \ 222 } \
193 } } 223 } }
194 SHOW_RPATH(32) 224 SHOW_RPATH(32)
211 else if (!be_quiet) 241 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 242 xstrcat(ret, " - ", ret_len);
213} 243}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 244static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
215{ 245{
216 int i; 246 unsigned long i;
217 char *needed; 247 char *needed;
218 void *strtbl_void; 248 void *strtbl_void;
219 249
220 if (!show_needed) return; 250 if (!show_needed) return;
221 251
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 252 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 253
224 if (strtbl_void) { 254 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 255#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 256 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 257 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 258 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 259 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 260 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
261 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 262 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 263 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
264 offset = EGET(phdr[i].p_offset); \
265 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 266 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 267 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 268 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 269 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
270 if (offset >= elf->len) { \
271 ++dyn; \
272 continue; \
273 } \
274 needed = (char*)(elf->data + offset); \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 275 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 276 xstrcat(ret, needed, ret_len); \
239 *found_needed = 1; \ 277 *found_needed = 1; \
240 } \ 278 } \
241 ++dyn; \ 279 ++dyn; \
263 SHOW_INTERP(32) 301 SHOW_INTERP(32)
264 SHOW_INTERP(64) 302 SHOW_INTERP(64)
265 } 303 }
266 return NULL; 304 return NULL;
267} 305}
306static char *scanelf_file_bind(elfobj *elf, char *found_bind)
307{
308 unsigned long i;
309 struct stat s;
310
311 if (!show_bind) return NULL;
312 if (!elf->phdr) return NULL;
313
314#define SHOW_BIND(B) \
315 if (elf->elf_class == ELFCLASS ## B) { \
316 Elf ## B ## _Dyn *dyn; \
317 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
318 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
319 Elf ## B ## _Off offset; \
320 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
321 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
322 offset = EGET(phdr[i].p_offset); \
323 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
324 dyn = DYN ## B (elf->data + offset); \
325 while (EGET(dyn->d_tag) != DT_NULL) { \
326 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
327 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
328 { \
329 if (be_quiet) return NULL; \
330 *found_bind = 1; \
331 return "NOW"; \
332 } \
333 ++dyn; \
334 } \
335 } \
336 }
337 SHOW_BIND(32)
338 SHOW_BIND(64)
339
340 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
341 return NULL;
342 } else {
343 *found_bind = 1;
344 return "LAZY";
345 }
346}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 347static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
269{ 348{
270 int i; 349 unsigned long i;
271 void *symtab_void, *strtab_void; 350 void *symtab_void, *strtab_void;
272 351
273 if (!find_sym) return NULL; 352 if (!find_sym) return NULL;
274 353
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 354 symtab_void = elf_findsecbyname(elf, ".symtab");
279#define FIND_SYM(B) \ 358#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 359 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 360 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 361 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 362 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 363 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 364 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 365 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 366 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 367 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 368 if (*find_sym == '*') { \
309 return NULL; 388 return NULL;
310 else 389 else
311 return " - "; 390 return " - ";
312} 391}
313/* scan an elf file and show all the fun stuff */ 392/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 393// #define prints(str) fputs(str, stdout)
394#define prints(str) write(fileno(stdout), str, strlen(str))
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}
550}; 685};
686
551static char *opts_help[] = { 687static char *opts_help[] = {
552 "Scan all directories in PATH environment", 688 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 689 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 690 "Scan directories recursively",
555 "Don't recursively cross mount points", 691 "Don't recursively cross mount points",
558 "Print GNU_STACK markings", 694 "Print GNU_STACK markings",
559 "Print TEXTREL information", 695 "Print TEXTREL information",
560 "Print RPATH information", 696 "Print RPATH information",
561 "Print NEEDED information", 697 "Print NEEDED information",
562 "Print INTERP information", 698 "Print INTERP information",
699 "Print BIND information",
563 "Find a specified symbol", 700 "Find a specified symbol",
564 "Print all scanned info (-x -e -t -r)\n", 701 "Print all scanned info (-x -e -t -r -n -i -b)\n",
565 "Only output 'bad' things", 702 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 703 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 704 "Use specified format for output",
705 "Read input stream from a filename",
568 "Write output stream to a filename", 706 "Write output stream to a filename",
569 "Don't display the header", 707 "Don't display the header",
570 "Print this help and exit", 708 "Print this help and exit",
571 "Print version and exit", 709 "Print version and exit",
572 NULL 710 NULL
573}; 711};
574 712
575/* display usage and exit */ 713/* display usage and exit */
576static void usage(int status) 714static void usage(int status)
577{ 715{
578 int i; 716 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 717 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 718 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 719 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 720 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 721 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 722 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 723 long_opts[i].name, opts_help[i]);
586 else 724 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 725 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 726 long_opts[i].name, opts_help[i]);
727
728 if (status != EXIT_SUCCESS)
729 exit(status);
730
731 puts("\nThe format modifiers for the -F option are:");
732 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
733 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
734 puts(" %i INTERP \t%b BIND \t%s symbol");
735
589 exit(status); 736 exit(status);
590} 737}
591 738
592/* parse command line arguments and preform needed actions */ 739/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 740static void parseargs(int argc, char *argv[])
594{ 741{
595 int flag; 742 int i;
743 char *from_file = NULL;
596 744
597 opterr = 0; 745 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 746 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 747 switch (i) {
600 748
601 case 'V': 749 case 'V':
602 printf("%s compiled %s\n%s\n" 750 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 751 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 752 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 753 exit(EXIT_SUCCESS);
606 break; 754 break;
607 case 'h': usage(EXIT_SUCCESS); break; 755 case 'h': usage(EXIT_SUCCESS); break;
608 756 case 'f':
757 if (from_file == NULL)
758 from_file = xstrdup(optarg);
759 break;
609 case 'o': { 760 case 'o': {
610 FILE *fp = NULL; 761 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 762 fp = freopen(optarg, "w", stdout);
612 if (fp == NULL) 763 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 764 err("Could not open output stream '%s': %s", optarg, strerror(errno));
623 sprintf(versioned_symname, "%s@", find_sym); 774 sprintf(versioned_symname, "%s@", find_sym);
624 break; 775 break;
625 } 776 }
626 777
627 case 'F': { 778 case 'F': {
628 out_format = strdup(optarg); 779 out_format = xstrdup(optarg);
629 break; 780 break;
630 } 781 }
631 782
632 case 'y': scan_symlink = 0; break; 783 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 784 case 'B': show_banner = 0; break;
639 case 'e': show_stack = 1; break; 790 case 'e': show_stack = 1; break;
640 case 't': show_textrel = 1; break; 791 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 792 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 793 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 794 case 'i': show_interp = 1; break;
795 case 'b': show_bind = 1; break;
644 case 'q': be_quiet = 1; break; 796 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 797 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; 798 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
799 show_needed = show_interp = show_bind = 1; break;
647 800
648 case ':': 801 case ':':
649 warn("Option missing parameter\n"); 802 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 803 case '?':
653 warn("Unknown option\n"); 804 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 805 default:
657 err("Unhandled option '%c'", flag); 806 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 807 }
661 808 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 809
665 /* let the format option override all other options */ 810 /* let the format option override all other options */
666 if (out_format) { 811 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 812 show_pax = show_stack = show_textrel = show_rpath = \
813 show_needed = show_interp = show_bind = 0;
668 for (flag=0; out_format[flag]; ++flag) { 814 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 815 if (out_format[i] != '%') continue;
670 816
671 switch (out_format[++flag]) { 817 switch (out_format[++i]) {
672 case '%': break; 818 case '%': break;
673 case 'F': break; 819 case 'F': break;
674 case 's': break; 820 case 's': break;
675 case 'o': break; 821 case 'o': break;
676 case 'x': show_pax = 1; break; 822 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 823 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break; 824 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 825 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 826 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 827 case 'i': show_interp = 1; break;
828 case 'b': show_bind = 1; break;
682 default: 829 default:
683 err("Invalid format specifier '%c' (byte %i)", 830 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 831 out_format[i], i+1);
685 } 832 }
686 } 833 }
687 834
688 /* construct our default format */ 835 /* construct our default format */
689 } else { 836 } else {
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 841 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 842 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 843 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 844 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 845 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
846 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 847 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 848 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 849 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 850 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 851
704 /* now lets actually do the scanning */ 852 /* now lets actually do the scanning */
853 if (scan_ldpath || (show_rpath && be_quiet))
854 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 855 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 856 if (scan_envpath) scanelf_envpath();
857 if (from_file) {
858 scanelf_from_file(from_file);
859 free(from_file);
860 from_file = *argv;
861 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 862 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 863 err("Nothing to scan !?");
709 while (optind < argc) 864 while (optind < argc)
710 scanelf_dir(argv[optind++]); 865 scanelf_dir(argv[optind++]);
711 866
712 /* clean up */ 867 /* clean up */
713 if (find_sym) { 868 if (find_sym) {
714 free(find_sym); 869 free(find_sym);
715 free(versioned_symname); 870 free(versioned_symname);
716 } 871 }
717 if (out_format) free(out_format); 872 if (out_format) free(out_format);
873 for (i = 0; ldpaths[i]; ++i)
874 free(ldpaths[i]);
718} 875}
719 876
720 877
721 878
722/* utility funcs */ 879/* utility funcs */
724{ 881{
725 char *ret = strdup(s); 882 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 883 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 884 return ret;
728} 885}
886
729static void *xmalloc(size_t size) 887static void *xmalloc(size_t size)
730{ 888{
731 void *ret = malloc(size); 889 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 890 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 891 return ret;
734} 892}
893
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 894static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 895{
737 long new_len; 896 long new_len;
738 897
739 new_len = strlen(*dst) + strlen(src); 898 new_len = strlen(*dst) + strlen(src);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 903 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 904 }
746 905
747 strcat(*dst, src); 906 strcat(*dst, src);
748} 907}
908
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 909static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 910{
751 static char my_app[2]; 911 static char my_app[2];
752 my_app[0] = append; 912 my_app[0] = append;
753 my_app[1] = '\0'; 913 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 914 xstrcat(dst, my_app, curr_len);
755} 915}
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
765 916
766 917
767int main(int argc, char *argv[]) 918int main(int argc, char *argv[])
768{ 919{
769 if (argc < 2) 920 if (argc < 2)

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

  ViewVC Help
Powered by ViewVC 1.1.20