/[gentoo-projects]/pax-utils/scanelf.c
Gentoo

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.47 - (hide annotations) (download) (as text)
Wed May 18 01:08:46 2005 UTC (9 years, 11 months ago) by vapier
Branch: MAIN
Changes since 1.46: +4 -3 lines
File MIME type: text/x-csrc
style tweak

1 solar 1.1 /*
2     * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 vapier 1.8 * Copyright 1999-2005 Gentoo Foundation
4 solar 1.1 * Distributed under the terms of the GNU General Public License v2
5 vapier 1.47 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.46 2005/05/16 21:59:06 vapier Exp $
6 solar 1.1 *
7     ********************************************************************
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
10     * published by the Free Software Foundation; either version 2 of the
11     * License, or (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful, but
14     * WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16     * General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21     * MA 02111-1307, USA.
22     */
23    
24     #include <stdio.h>
25     #include <stdlib.h>
26     #include <sys/types.h>
27 solar 1.28 #define __USE_GNU
28 solar 1.1 #include <string.h>
29 vapier 1.10 #include <errno.h>
30 solar 1.1 #include <unistd.h>
31     #include <sys/stat.h>
32     #include <dirent.h>
33     #include <getopt.h>
34 solar 1.20 #include <assert.h>
35 solar 1.21
36 solar 1.1 #include "paxelf.h"
37    
38 vapier 1.47 static const char *rcsid = "$Id: scanelf.c,v 1.46 2005/05/16 21:59:06 vapier Exp $";
39 vapier 1.36 #define argv0 "scanelf"
40 vapier 1.10
41    
42    
43     /* prototypes */
44     static void scanelf_file(const char *filename);
45     static void scanelf_dir(const char *path);
46     static void scanelf_ldpath();
47     static void scanelf_envpath();
48     static void usage(int status);
49     static void parseargs(int argc, char *argv[]);
50 vapier 1.41 static char *xstrdup(char *s);
51     static void *xmalloc(size_t size);
52     static void xstrcat(char **dst, const char *src, size_t *curr_len);
53     static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54     static int xemptybuffer(const char *buff);
55 vapier 1.10
56     /* variables to control behavior */
57     static char scan_ldpath = 0;
58     static char scan_envpath = 0;
59 vapier 1.37 static char scan_symlink = 1;
60 vapier 1.10 static char dir_recurse = 0;
61 vapier 1.14 static char dir_crossmount = 1;
62 vapier 1.10 static char show_pax = 0;
63     static char show_stack = 0;
64     static char show_textrel = 0;
65     static char show_rpath = 0;
66 vapier 1.32 static char show_needed = 0;
67 vapier 1.38 static char show_interp = 0;
68 solar 1.16 static char show_banner = 1;
69 vapier 1.10 static char be_quiet = 0;
70 vapier 1.14 static char be_verbose = 0;
71 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
72     static char *out_format = NULL;
73 vapier 1.10
74 solar 1.1
75    
76 vapier 1.39 /* sub-funcs for scanelf_file() */
77 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78 solar 1.6 {
79 vapier 1.41 static char *paxflags;
80    
81     if (!show_pax) return NULL;
82 vapier 1.10
83 vapier 1.39 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84     if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85     *found_pax = 1;
86 vapier 1.41 return paxflags;
87 vapier 1.14 }
88 vapier 1.41
89     return NULL;
90 vapier 1.39 }
91 vapier 1.41 static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92 vapier 1.39 {
93 vapier 1.43 static char ret[8];
94 vapier 1.41 char *found;
95 vapier 1.44 unsigned long i, off, shown;
96 vapier 1.41
97     if (!show_stack) return NULL;
98    
99     shown = 0;
100 vapier 1.43 strcpy(ret, "--- ---");
101 vapier 1.44
102     if (elf->phdr) {
103 vapier 1.26 #define SHOW_STACK(B) \
104 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
105     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
106     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
107     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
108 vapier 1.41 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
109     found = found_stack; \
110     off = 0; \
111     } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
112     found = found_relro; \
113     off = 3; \
114     } else \
115     continue; \
116 vapier 1.39 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
117     continue; \
118 vapier 1.41 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
119     *found = 1; \
120     ++shown; \
121 vapier 1.39 } \
122     }
123     SHOW_STACK(32)
124     SHOW_STACK(64)
125 vapier 1.44 }
126    
127 vapier 1.41 if (be_quiet && !shown)
128     return NULL;
129     else
130     return ret;
131 vapier 1.39 }
132 vapier 1.41 static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
133 vapier 1.39 {
134 vapier 1.41 static char *ret = "TEXTREL";
135 vapier 1.44 unsigned long i;
136 vapier 1.41
137     if (!show_textrel) return NULL;
138    
139 vapier 1.44 if (elf->phdr) {
140 vapier 1.39 #define SHOW_TEXTREL(B) \
141     if (elf->elf_class == ELFCLASS ## B) { \
142     Elf ## B ## _Dyn *dyn; \
143     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
144     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
145 vapier 1.44 Elf ## B ## _Off offset; \
146 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
147     if (phdr[i].p_type != PT_DYNAMIC) continue; \
148 vapier 1.44 offset = EGET(phdr[i].p_offset); \
149     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
150     dyn = DYN ## B (elf->data + offset); \
151 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
152     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
153     *found_textrel = 1; \
154     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
155 vapier 1.41 return ret; \
156 vapier 1.39 } \
157     ++dyn; \
158 vapier 1.26 } \
159 vapier 1.39 } }
160     SHOW_TEXTREL(32)
161     SHOW_TEXTREL(64)
162 vapier 1.44 }
163    
164 vapier 1.41 if (be_quiet)
165     return NULL;
166     else
167     return " - ";
168 vapier 1.39 }
169 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
170 vapier 1.39 {
171     /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
172 vapier 1.44 unsigned long i;
173 vapier 1.39 char *rpath, *runpath;
174     void *strtbl_void;
175 vapier 1.10
176 vapier 1.39 if (!show_rpath) return;
177 vapier 1.10
178 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
179     rpath = runpath = NULL;
180 vapier 1.10
181 vapier 1.44 if (elf->phdr && strtbl_void) {
182 vapier 1.26 #define SHOW_RPATH(B) \
183     if (elf->elf_class == ELFCLASS ## B) { \
184     Elf ## B ## _Dyn *dyn; \
185     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
186     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
187     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
188 vapier 1.44 Elf ## B ## _Off offset; \
189 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
190     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
191 vapier 1.44 offset = EGET(phdr[i].p_offset); \
192     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
193     dyn = DYN ## B (elf->data + offset); \
194 vapier 1.26 while (EGET(dyn->d_tag) != DT_NULL) { \
195     if (EGET(dyn->d_tag) == DT_RPATH) { \
196 vapier 1.41 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \
197 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
198     if (offset >= elf->len) continue; \
199     rpath = (char*)(elf->data + offset); \
200 vapier 1.39 *found_rpath = 1; \
201 vapier 1.26 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
202 vapier 1.41 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
203 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204     if (offset >= elf->len) continue; \
205     runpath = (char*)(elf->data + offset); \
206 vapier 1.39 *found_rpath = 1; \
207 vapier 1.26 } \
208     ++dyn; \
209     } \
210     } }
211     SHOW_RPATH(32)
212     SHOW_RPATH(64)
213 vapier 1.10 }
214 vapier 1.41
215 vapier 1.39 if (rpath && runpath) {
216 vapier 1.41 if (!strcmp(rpath, runpath)) {
217     xstrcat(ret, runpath, ret_len);
218     } else {
219 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
220 vapier 1.41 xchrcat(ret, '{', ret_len);
221     xstrcat(ret, rpath, ret_len);
222     xchrcat(ret, ',', ret_len);
223     xstrcat(ret, runpath, ret_len);
224     xchrcat(ret, '}', ret_len);
225 vapier 1.39 }
226     } else if (rpath || runpath)
227 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
228     else if (!be_quiet)
229     xstrcat(ret, " - ", ret_len);
230 vapier 1.39 }
231 vapier 1.41 static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
232 vapier 1.39 {
233 vapier 1.44 unsigned long i;
234 vapier 1.39 char *needed;
235     void *strtbl_void;
236    
237     if (!show_needed) return;
238 vapier 1.10
239 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
240 vapier 1.32
241 vapier 1.44 if (elf->phdr && strtbl_void) {
242 vapier 1.32 #define SHOW_NEEDED(B) \
243     if (elf->elf_class == ELFCLASS ## B) { \
244     Elf ## B ## _Dyn *dyn; \
245     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
246     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
247     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
248 vapier 1.44 Elf ## B ## _Off offset; \
249 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
250     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
251 vapier 1.44 offset = EGET(phdr[i].p_offset); \
252     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
253     dyn = DYN ## B (elf->data + offset); \
254 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
255     if (EGET(dyn->d_tag) == DT_NEEDED) { \
256 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
257     if (offset >= elf->len) continue; \
258     needed = (char*)(elf->data + offset); \
259 vapier 1.41 if (*found_needed) xchrcat(ret, ',', ret_len); \
260     xstrcat(ret, needed, ret_len); \
261 vapier 1.39 *found_needed = 1; \
262 vapier 1.32 } \
263     ++dyn; \
264     } \
265     } }
266     SHOW_NEEDED(32)
267     SHOW_NEEDED(64)
268     }
269 vapier 1.39 }
270 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
271 vapier 1.39 {
272     void *strtbl_void;
273    
274 vapier 1.41 if (!show_interp) return NULL;
275 vapier 1.32
276 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
277 vapier 1.38
278 vapier 1.39 if (strtbl_void) {
279 vapier 1.38 #define SHOW_INTERP(B) \
280     if (elf->elf_class == ELFCLASS ## B) { \
281 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
282     *found_interp = 1; \
283 vapier 1.41 return elf->data + EGET(strtbl->sh_offset); \
284 vapier 1.38 }
285     SHOW_INTERP(32)
286     SHOW_INTERP(64)
287     }
288 vapier 1.41 return NULL;
289 vapier 1.39 }
290 vapier 1.41 static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
291 vapier 1.39 {
292 vapier 1.44 unsigned long i;
293 vapier 1.39 void *symtab_void, *strtab_void;
294 vapier 1.38
295 vapier 1.41 if (!find_sym) return NULL;
296 vapier 1.32
297 vapier 1.39 symtab_void = elf_findsecbyname(elf, ".symtab");
298     strtab_void = elf_findsecbyname(elf, ".strtab");
299 vapier 1.27
300 vapier 1.39 if (symtab_void && strtab_void) {
301 vapier 1.27 #define FIND_SYM(B) \
302     if (elf->elf_class == ELFCLASS ## B) { \
303     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
304     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
305     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
306 vapier 1.44 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
307 vapier 1.27 char *symname; \
308     for (i = 0; i < cnt; ++i) { \
309     if (sym->st_name) { \
310     symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
311 solar 1.28 if (*find_sym == '*') { \
312 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
313 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
314 vapier 1.32 (char *)basename(filename), \
315     (long)sym->st_size, \
316     (char *)get_elfstttype(sym->st_info), \
317     symname); \
318 vapier 1.39 *found_sym = 1; \
319 vapier 1.32 } else if ((strcmp(find_sym, symname) == 0) || \
320 vapier 1.39 (strcmp(symname, versioned_symname) == 0)) \
321     (*found_sym)++; \
322 vapier 1.27 } \
323     ++sym; \
324     } }
325     FIND_SYM(32)
326     FIND_SYM(64)
327 vapier 1.39 }
328 vapier 1.41 if (*find_sym != '*' && *found_sym)
329     return find_sym;
330     if (be_quiet)
331     return NULL;
332     else
333     return " - ";
334 vapier 1.39 }
335     /* scan an elf file and show all the fun stuff */
336 vapier 1.41 #define prints(str) fputs(str, stdout)
337 vapier 1.39 static void scanelf_file(const char *filename)
338     {
339 vapier 1.44 unsigned long i;
340 vapier 1.39 char found_pax, found_stack, found_relro, found_textrel,
341     found_rpath, found_needed, found_interp, found_sym,
342     found_file;
343     elfobj *elf;
344     struct stat st;
345 vapier 1.41 static char *out_buffer = NULL;
346     static size_t out_len;
347 vapier 1.39
348     /* make sure 'filename' exists */
349     if (lstat(filename, &st) == -1) {
350     if (be_verbose > 2) printf("%s: does not exist\n", filename);
351     return;
352     }
353     /* always handle regular files and handle symlinked files if no -y */
354     if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) {
355     if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
356     return;
357     }
358    
359     found_pax = found_stack = found_relro = found_textrel = \
360     found_rpath = found_needed = found_interp = found_sym = \
361     found_file = 0;
362    
363     /* verify this is real ELF */
364     if ((elf = readelf(filename)) == NULL) {
365     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
366     return;
367     }
368    
369     if (be_verbose > 1)
370 vapier 1.41 printf("%s: scanning file {%s,%s}\n", filename,
371 vapier 1.39 get_elfeitype(elf, EI_CLASS, elf->elf_class),
372     get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
373     else if (be_verbose)
374     printf("%s: scanning file\n", filename);
375    
376 vapier 1.41 /* init output buffer */
377     if (!out_buffer) {
378     out_len = sizeof(char) * 80;
379     out_buffer = (char*)xmalloc(out_len);
380     }
381     *out_buffer = '\0';
382    
383 vapier 1.39 /* show the header */
384     if (!be_quiet && show_banner) {
385 vapier 1.41 for (i=0; out_format[i]; ++i) {
386     if (out_format[i] != '%') continue;
387    
388     switch (out_format[++i]) {
389     case '%': break;
390     case 'F': prints("FILE "); break;
391     case 'o': prints(" TYPE "); break;
392     case 'x': prints(" PAX "); break;
393     case 'e': prints("STK/REL "); break;
394     case 't': prints("TEXTREL "); break;
395     case 'r': prints("RPATH "); break;
396     case 'n': prints("NEEDED "); break;
397     case 'i': prints("INTERP "); break;
398     case 's': prints("SYM "); break;
399 vapier 1.39 }
400 vapier 1.27 }
401 vapier 1.41 prints("\n");
402 vapier 1.39 show_banner = 0;
403     }
404    
405     /* dump all the good stuff */
406 vapier 1.41 for (i=0; out_format[i]; ++i) {
407     const char *out;
408    
409     /* make sure we trim leading spaces in quiet mode */
410     if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
411     *out_buffer = '\0';
412 vapier 1.39
413 vapier 1.41 if (out_format[i] != '%') {
414     xchrcat(&out_buffer, out_format[i], &out_len);
415     continue;
416     }
417 vapier 1.39
418 vapier 1.41 out = NULL;
419     switch (out_format[++i]) {
420     case '%': xchrcat(&out_buffer, '%', &out_len); break;
421     case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break;
422     case 'o': out = get_elfetype(elf); break;
423     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
424     case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
425     case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
426     case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
427     case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
428     case 'i': out = scanelf_file_interp(elf, &found_interp); break;
429     case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
430 vapier 1.29 }
431 vapier 1.41 if (out) xstrcat(&out_buffer, out, &out_len);
432 vapier 1.39 }
433    
434     if (!found_file) {
435     if (!be_quiet || found_pax || found_stack || found_textrel || \
436 vapier 1.41 found_rpath || found_needed || found_interp || found_sym)
437     xstrcat(&out_buffer, filename, &out_len);
438 vapier 1.27 }
439 vapier 1.41 if (!(be_quiet && xemptybuffer(out_buffer)))
440     puts(out_buffer);
441 vapier 1.10
442     unreadelf(elf);
443 solar 1.6 }
444    
445 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
446 vapier 1.10 static void scanelf_dir(const char *path)
447 solar 1.1 {
448 vapier 1.10 register DIR *dir;
449     register struct dirent *dentry;
450 vapier 1.14 struct stat st_top, st;
451 solar 1.21 char buf[_POSIX_PATH_MAX];
452 vapier 1.32 size_t pathlen = 0, len = 0;
453 vapier 1.10
454     /* make sure path exists */
455 vapier 1.39 if (lstat(path, &st_top) == -1) {
456     if (be_verbose > 2) printf("%s: does not exist\n", path);
457 vapier 1.10 return;
458 vapier 1.39 }
459 solar 1.11
460 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
461 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
462 vapier 1.10 scanelf_file(path);
463     return;
464     }
465    
466     /* now scan the dir looking for fun stuff */
467     if ((dir = opendir(path)) == NULL) {
468     warnf("could not opendir %s: %s", path, strerror(errno));
469     return;
470     }
471 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
472 solar 1.11
473 vapier 1.32 pathlen = strlen(path);
474 vapier 1.10 while ((dentry = readdir(dir))) {
475     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
476     continue;
477 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
478     if (len >= sizeof(buf)) {
479     warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
480     continue;
481     }
482 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
483 solar 1.20 if (lstat(buf, &st) != -1) {
484 vapier 1.10 if (S_ISREG(st.st_mode))
485 solar 1.20 scanelf_file(buf);
486 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
487 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
488 solar 1.20 scanelf_dir(buf);
489 vapier 1.10 }
490     }
491     }
492     closedir(dir);
493 solar 1.1 }
494    
495 vapier 1.47 static int scanelf_from_file(char *filename)
496     {
497 solar 1.45 FILE *fp = NULL;
498     char *p;
499     char path[_POSIX_PATH_MAX];
500    
501     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
502     fp = stdin;
503     else if ((fp = fopen(filename, "r")) == NULL)
504     return 1;
505    
506     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
507     if ((p = strchr(path, '\n')) != NULL)
508     *p = 0;
509     scanelf_dir(path);
510     }
511     if (fp != stdin)
512     fclose(fp);
513     return 0;
514     }
515    
516 vapier 1.10 /* scan /etc/ld.so.conf for paths */
517     static void scanelf_ldpath()
518     {
519 vapier 1.17 char scan_l, scan_ul, scan_ull;
520 vapier 1.10 char *path, *p;
521     FILE *fp;
522    
523     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
524     err("Unable to open ld.so.conf: %s", strerror(errno));
525    
526 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
527    
528 vapier 1.41 path = (char*)xmalloc(_POSIX_PATH_MAX);
529 vapier 1.10 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
530     if (*path == '/') {
531     if ((p = strrchr(path, '\r')) != NULL)
532     *p = 0;
533     if ((p = strrchr(path, '\n')) != NULL)
534     *p = 0;
535 vapier 1.17 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
536     if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
537     if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
538 vapier 1.10 scanelf_dir(path);
539     }
540     free(path);
541 vapier 1.32 fclose(fp);
542 vapier 1.10
543 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
544     if (!scan_ul) scanelf_dir("/usr/lib");
545     if (!scan_ull) scanelf_dir("/usr/local/lib");
546 vapier 1.10 }
547 solar 1.1
548 vapier 1.10 /* scan env PATH for paths */
549     static void scanelf_envpath()
550 solar 1.1 {
551 solar 1.34 char *path, *p;
552 vapier 1.10
553     path = getenv("PATH");
554     if (!path)
555     err("PATH is not set in your env !");
556 vapier 1.41 path = xstrdup(path);
557 vapier 1.10
558     while ((p = strrchr(path, ':')) != NULL) {
559     scanelf_dir(p + 1);
560     *p = 0;
561     }
562 vapier 1.17
563 solar 1.34 free(path);
564 solar 1.1 }
565    
566    
567 vapier 1.10
568     /* usage / invocation handling functions */
569 solar 1.45 #define PARSE_FLAGS "plRmyxetrnis:aqvF:f:o:BhV"
570 vapier 1.27 #define a_argument required_argument
571 vapier 1.10 static struct option const long_opts[] = {
572     {"path", no_argument, NULL, 'p'},
573     {"ldpath", no_argument, NULL, 'l'},
574     {"recursive", no_argument, NULL, 'R'},
575 vapier 1.14 {"mount", no_argument, NULL, 'm'},
576 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
577 vapier 1.10 {"pax", no_argument, NULL, 'x'},
578 solar 1.16 {"header", no_argument, NULL, 'e'},
579 vapier 1.10 {"textrel", no_argument, NULL, 't'},
580     {"rpath", no_argument, NULL, 'r'},
581 vapier 1.32 {"needed", no_argument, NULL, 'n'},
582 vapier 1.38 {"interp", no_argument, NULL, 'i'},
583 vapier 1.27 {"symbol", a_argument, NULL, 's'},
584 vapier 1.10 {"all", no_argument, NULL, 'a'},
585     {"quiet", no_argument, NULL, 'q'},
586 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
587 vapier 1.39 {"format", a_argument, NULL, 'F'},
588 solar 1.45 {"from", a_argument, NULL, 'f'},
589 vapier 1.27 {"file", a_argument, NULL, 'o'},
590 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
591 vapier 1.10 {"help", no_argument, NULL, 'h'},
592     {"version", no_argument, NULL, 'V'},
593     {NULL, no_argument, NULL, 0x0}
594     };
595     static char *opts_help[] = {
596     "Scan all directories in PATH environment",
597     "Scan all directories in /etc/ld.so.conf",
598 vapier 1.14 "Scan directories recursively",
599 vapier 1.37 "Don't recursively cross mount points",
600     "Don't scan symlinks\n",
601 vapier 1.10 "Print PaX markings",
602     "Print GNU_STACK markings",
603     "Print TEXTREL information",
604     "Print RPATH information",
605 vapier 1.32 "Print NEEDED information",
606 vapier 1.38 "Print INTERP information",
607 vapier 1.27 "Find a specified symbol",
608 vapier 1.46 "Print all scanned info (-x -e -t -r -n -i)\n",
609 vapier 1.14 "Only output 'bad' things",
610     "Be verbose (can be specified more than once)",
611 vapier 1.39 "Use specified format for output",
612 solar 1.45 "Read input stream from a filename",
613 vapier 1.24 "Write output stream to a filename",
614 vapier 1.14 "Don't display the header",
615 vapier 1.10 "Print this help and exit",
616     "Print version and exit",
617     NULL
618     };
619    
620     /* display usage and exit */
621     static void usage(int status)
622 solar 1.1 {
623 vapier 1.44 unsigned long i;
624 vapier 1.37 printf(" Scan ELF binaries for stuff\n\n"
625 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
626     printf("Options: -[%s]\n", PARSE_FLAGS);
627 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
628 vapier 1.27 if (long_opts[i].has_arg == no_argument)
629     printf(" -%c, --%-13s %s\n", long_opts[i].val,
630     long_opts[i].name, opts_help[i]);
631     else
632     printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
633     long_opts[i].name, opts_help[i]);
634 solar 1.45
635     if (status != EXIT_SUCCESS)
636     exit(status);
637    
638 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
639     puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
640     puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
641     puts(" %i INTERP \t%s symbol");
642 solar 1.45
643 vapier 1.10 exit(status);
644 solar 1.1 }
645    
646     /* parse command line arguments and preform needed actions */
647 vapier 1.10 static void parseargs(int argc, char *argv[])
648     {
649     int flag;
650 solar 1.45 char *from_file = NULL;
651 vapier 1.10
652     opterr = 0;
653     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
654     switch (flag) {
655    
656 vapier 1.39 case 'V':
657 solar 1.19 printf("%s compiled %s\n%s\n"
658     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
659     __FILE__, __DATE__, rcsid, argv0);
660 vapier 1.10 exit(EXIT_SUCCESS);
661     break;
662     case 'h': usage(EXIT_SUCCESS); break;
663 solar 1.45 case 'f':
664     if (from_file == NULL)
665     from_file = xstrdup(optarg);
666     break;
667 vapier 1.24 case 'o': {
668 solar 1.21 FILE *fp = NULL;
669     fp = freopen(optarg, "w", stdout);
670 vapier 1.24 if (fp == NULL)
671     err("Could not open output stream '%s': %s", optarg, strerror(errno));
672     stdout = fp;
673 solar 1.21 break;
674     }
675 vapier 1.24
676 vapier 1.39 case 's': {
677     size_t len;
678 vapier 1.41 find_sym = xstrdup(optarg);
679 vapier 1.39 len = strlen(find_sym) + 1;
680 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
681 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
682     break;
683     }
684    
685     case 'F': {
686 solar 1.45 out_format = xstrdup(optarg);
687 vapier 1.39 break;
688     }
689 vapier 1.27
690 vapier 1.37 case 'y': scan_symlink = 0; break;
691 solar 1.16 case 'B': show_banner = 0; break;
692 vapier 1.10 case 'l': scan_ldpath = 1; break;
693     case 'p': scan_envpath = 1; break;
694     case 'R': dir_recurse = 1; break;
695 vapier 1.14 case 'm': dir_crossmount = 0; break;
696 vapier 1.10 case 'x': show_pax = 1; break;
697 solar 1.16 case 'e': show_stack = 1; break;
698 vapier 1.10 case 't': show_textrel = 1; break;
699     case 'r': show_rpath = 1; break;
700 vapier 1.32 case 'n': show_needed = 1; break;
701 vapier 1.38 case 'i': show_interp = 1; break;
702 vapier 1.10 case 'q': be_quiet = 1; break;
703 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
704 vapier 1.38 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
705 vapier 1.10
706     case ':':
707 vapier 1.39 warn("Option missing parameter\n");
708 vapier 1.10 usage(EXIT_FAILURE);
709     break;
710     case '?':
711 vapier 1.39 warn("Unknown option\n");
712 vapier 1.10 usage(EXIT_FAILURE);
713     break;
714     default:
715     err("Unhandled option '%c'", flag);
716     break;
717     }
718     }
719    
720 vapier 1.14 if (be_quiet && be_verbose)
721     err("You can be quiet or you can be verbose, not both, stupid");
722    
723 vapier 1.39 /* let the format option override all other options */
724     if (out_format) {
725     show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
726     for (flag=0; out_format[flag]; ++flag) {
727     if (out_format[flag] != '%') continue;
728    
729     switch (out_format[++flag]) {
730     case '%': break;
731     case 'F': break;
732     case 's': break;
733 vapier 1.41 case 'o': break;
734 vapier 1.39 case 'x': show_pax = 1; break;
735     case 'e': show_stack = 1; break;
736     case 't': show_textrel = 1; break;
737     case 'r': show_rpath = 1; break;
738     case 'n': show_needed = 1; break;
739     case 'i': show_interp = 1; break;
740     default:
741     err("Invalid format specifier '%c' (byte %i)",
742     out_format[flag], flag+1);
743     }
744     }
745 vapier 1.41
746     /* construct our default format */
747     } else {
748     size_t fmt_len = 30;
749     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
750     if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
751     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
752     if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
753     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
754     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
755     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
756     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
757     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
758     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
759 vapier 1.39 }
760 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
761 vapier 1.39
762     /* now lets actually do the scanning */
763 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
764     if (scan_envpath) scanelf_envpath();
765 solar 1.45 if (from_file) {
766     scanelf_from_file(from_file);
767     free(from_file);
768     from_file = *argv;
769     }
770     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
771 vapier 1.25 err("Nothing to scan !?");
772 vapier 1.10 while (optind < argc)
773     scanelf_dir(argv[optind++]);
774 vapier 1.27
775 vapier 1.39 /* clean up */
776     if (find_sym) {
777     free(find_sym);
778     free(versioned_symname);
779     }
780     if (out_format) free(out_format);
781 vapier 1.10 }
782    
783    
784    
785 vapier 1.41 /* utility funcs */
786     static char *xstrdup(char *s)
787     {
788     char *ret = strdup(s);
789     if (!ret) err("Could not strdup(): %s", strerror(errno));
790     return ret;
791     }
792     static void *xmalloc(size_t size)
793     {
794     void *ret = malloc(size);
795     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
796     return ret;
797     }
798     static void xstrcat(char **dst, const char *src, size_t *curr_len)
799     {
800     long new_len;
801    
802     new_len = strlen(*dst) + strlen(src);
803     if (*curr_len <= new_len) {
804     *curr_len = new_len + (*curr_len / 2);
805     *dst = realloc(*dst, *curr_len);
806     if (!*dst)
807     err("could not realloc %li bytes", (unsigned long)*curr_len);
808     }
809    
810     strcat(*dst, src);
811     }
812     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
813     {
814     static char my_app[2];
815     my_app[0] = append;
816     my_app[1] = '\0';
817     xstrcat(dst, my_app, curr_len);
818     }
819     static int xemptybuffer(const char *buff)
820     {
821     long i;
822     for (i=0; buff[i]; ++i)
823     if (buff[i] != ' ')
824     return 0;
825     return 1;
826     }
827    
828    
829    
830 vapier 1.10 int main(int argc, char *argv[])
831 solar 1.1 {
832 vapier 1.10 if (argc < 2)
833     usage(EXIT_FAILURE);
834     parseargs(argc, argv);
835 solar 1.21 fclose(stdout);
836 vapier 1.10 return EXIT_SUCCESS;
837 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20