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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.46 - (hide annotations) (download) (as text)
Mon May 16 21:59:06 2005 UTC (9 years, 3 months ago) by vapier
Branch: MAIN
Changes since 1.45: +7 -12 lines
File MIME type: text/x-csrc
update the help output

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.46 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.45 2005/05/14 00:18:56 solar 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.46 static const char *rcsid = "$Id: scanelf.c,v 1.45 2005/05/14 00:18:56 solar 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 solar 1.45 int scanelf_from_file(char *filename) {
496     FILE *fp = NULL;
497     char *p;
498     char path[_POSIX_PATH_MAX];
499    
500     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
501     fp = stdin;
502     else if ((fp = fopen(filename, "r")) == NULL)
503     return 1;
504    
505     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
506     if ((p = strchr(path, '\n')) != NULL)
507     *p = 0;
508     scanelf_dir(path);
509     }
510     if (fp != stdin)
511     fclose(fp);
512     return 0;
513     }
514    
515 vapier 1.10 /* scan /etc/ld.so.conf for paths */
516     static void scanelf_ldpath()
517     {
518 vapier 1.17 char scan_l, scan_ul, scan_ull;
519 vapier 1.10 char *path, *p;
520     FILE *fp;
521    
522     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
523     err("Unable to open ld.so.conf: %s", strerror(errno));
524    
525 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
526    
527 vapier 1.41 path = (char*)xmalloc(_POSIX_PATH_MAX);
528 vapier 1.10 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
529     if (*path == '/') {
530     if ((p = strrchr(path, '\r')) != NULL)
531     *p = 0;
532     if ((p = strrchr(path, '\n')) != NULL)
533     *p = 0;
534 vapier 1.17 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
535     if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
536     if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
537 vapier 1.10 scanelf_dir(path);
538     }
539     free(path);
540 vapier 1.32 fclose(fp);
541 vapier 1.10
542 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
543     if (!scan_ul) scanelf_dir("/usr/lib");
544     if (!scan_ull) scanelf_dir("/usr/local/lib");
545 vapier 1.10 }
546 solar 1.1
547 vapier 1.10 /* scan env PATH for paths */
548     static void scanelf_envpath()
549 solar 1.1 {
550 solar 1.34 char *path, *p;
551 vapier 1.10
552     path = getenv("PATH");
553     if (!path)
554     err("PATH is not set in your env !");
555 vapier 1.41 path = xstrdup(path);
556 vapier 1.10
557     while ((p = strrchr(path, ':')) != NULL) {
558     scanelf_dir(p + 1);
559     *p = 0;
560     }
561 vapier 1.17
562 solar 1.34 free(path);
563 solar 1.1 }
564    
565    
566 vapier 1.10
567     /* usage / invocation handling functions */
568 solar 1.45 #define PARSE_FLAGS "plRmyxetrnis:aqvF:f:o:BhV"
569 vapier 1.27 #define a_argument required_argument
570 vapier 1.10 static struct option const long_opts[] = {
571     {"path", no_argument, NULL, 'p'},
572     {"ldpath", no_argument, NULL, 'l'},
573     {"recursive", no_argument, NULL, 'R'},
574 vapier 1.14 {"mount", no_argument, NULL, 'm'},
575 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
576 vapier 1.10 {"pax", no_argument, NULL, 'x'},
577 solar 1.16 {"header", no_argument, NULL, 'e'},
578 vapier 1.10 {"textrel", no_argument, NULL, 't'},
579     {"rpath", no_argument, NULL, 'r'},
580 vapier 1.32 {"needed", no_argument, NULL, 'n'},
581 vapier 1.38 {"interp", no_argument, NULL, 'i'},
582 vapier 1.27 {"symbol", a_argument, NULL, 's'},
583 vapier 1.10 {"all", no_argument, NULL, 'a'},
584     {"quiet", no_argument, NULL, 'q'},
585 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
586 vapier 1.39 {"format", a_argument, NULL, 'F'},
587 solar 1.45 {"from", a_argument, NULL, 'f'},
588 vapier 1.27 {"file", a_argument, NULL, 'o'},
589 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
590 vapier 1.10 {"help", no_argument, NULL, 'h'},
591     {"version", no_argument, NULL, 'V'},
592     {NULL, no_argument, NULL, 0x0}
593     };
594     static char *opts_help[] = {
595     "Scan all directories in PATH environment",
596     "Scan all directories in /etc/ld.so.conf",
597 vapier 1.14 "Scan directories recursively",
598 vapier 1.37 "Don't recursively cross mount points",
599     "Don't scan symlinks\n",
600 vapier 1.10 "Print PaX markings",
601     "Print GNU_STACK markings",
602     "Print TEXTREL information",
603     "Print RPATH information",
604 vapier 1.32 "Print NEEDED information",
605 vapier 1.38 "Print INTERP information",
606 vapier 1.27 "Find a specified symbol",
607 vapier 1.46 "Print all scanned info (-x -e -t -r -n -i)\n",
608 vapier 1.14 "Only output 'bad' things",
609     "Be verbose (can be specified more than once)",
610 vapier 1.39 "Use specified format for output",
611 solar 1.45 "Read input stream from a filename",
612 vapier 1.24 "Write output stream to a filename",
613 vapier 1.14 "Don't display the header",
614 vapier 1.10 "Print this help and exit",
615     "Print version and exit",
616     NULL
617     };
618    
619     /* display usage and exit */
620     static void usage(int status)
621 solar 1.1 {
622 vapier 1.44 unsigned long i;
623 vapier 1.37 printf(" Scan ELF binaries for stuff\n\n"
624 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
625     printf("Options: -[%s]\n", PARSE_FLAGS);
626 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
627 vapier 1.27 if (long_opts[i].has_arg == no_argument)
628     printf(" -%c, --%-13s %s\n", long_opts[i].val,
629     long_opts[i].name, opts_help[i]);
630     else
631     printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
632     long_opts[i].name, opts_help[i]);
633 solar 1.45
634     if (status != EXIT_SUCCESS)
635     exit(status);
636    
637 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
638     puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
639     puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
640     puts(" %i INTERP \t%s symbol");
641 solar 1.45
642 vapier 1.10 exit(status);
643 solar 1.1 }
644    
645     /* parse command line arguments and preform needed actions */
646 vapier 1.10 static void parseargs(int argc, char *argv[])
647     {
648     int flag;
649 solar 1.45 char *from_file = NULL;
650 vapier 1.10
651     opterr = 0;
652     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
653     switch (flag) {
654    
655 vapier 1.39 case 'V':
656 solar 1.19 printf("%s compiled %s\n%s\n"
657     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
658     __FILE__, __DATE__, rcsid, argv0);
659 vapier 1.10 exit(EXIT_SUCCESS);
660     break;
661     case 'h': usage(EXIT_SUCCESS); break;
662 solar 1.45 case 'f':
663     if (from_file == NULL)
664     from_file = xstrdup(optarg);
665     break;
666 vapier 1.24 case 'o': {
667 solar 1.21 FILE *fp = NULL;
668     fp = freopen(optarg, "w", stdout);
669 vapier 1.24 if (fp == NULL)
670     err("Could not open output stream '%s': %s", optarg, strerror(errno));
671     stdout = fp;
672 solar 1.21 break;
673     }
674 vapier 1.24
675 vapier 1.39 case 's': {
676     size_t len;
677 vapier 1.41 find_sym = xstrdup(optarg);
678 vapier 1.39 len = strlen(find_sym) + 1;
679 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
680 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
681     break;
682     }
683    
684     case 'F': {
685 solar 1.45 out_format = xstrdup(optarg);
686 vapier 1.39 break;
687     }
688 vapier 1.27
689 vapier 1.37 case 'y': scan_symlink = 0; break;
690 solar 1.16 case 'B': show_banner = 0; break;
691 vapier 1.10 case 'l': scan_ldpath = 1; break;
692     case 'p': scan_envpath = 1; break;
693     case 'R': dir_recurse = 1; break;
694 vapier 1.14 case 'm': dir_crossmount = 0; break;
695 vapier 1.10 case 'x': show_pax = 1; break;
696 solar 1.16 case 'e': show_stack = 1; break;
697 vapier 1.10 case 't': show_textrel = 1; break;
698     case 'r': show_rpath = 1; break;
699 vapier 1.32 case 'n': show_needed = 1; break;
700 vapier 1.38 case 'i': show_interp = 1; break;
701 vapier 1.10 case 'q': be_quiet = 1; break;
702 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
703 vapier 1.38 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
704 vapier 1.10
705     case ':':
706 vapier 1.39 warn("Option missing parameter\n");
707 vapier 1.10 usage(EXIT_FAILURE);
708     break;
709     case '?':
710 vapier 1.39 warn("Unknown option\n");
711 vapier 1.10 usage(EXIT_FAILURE);
712     break;
713     default:
714     err("Unhandled option '%c'", flag);
715     break;
716     }
717     }
718    
719 vapier 1.14 if (be_quiet && be_verbose)
720     err("You can be quiet or you can be verbose, not both, stupid");
721    
722 vapier 1.39 /* let the format option override all other options */
723     if (out_format) {
724     show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
725     for (flag=0; out_format[flag]; ++flag) {
726     if (out_format[flag] != '%') continue;
727    
728     switch (out_format[++flag]) {
729     case '%': break;
730     case 'F': break;
731     case 's': break;
732 vapier 1.41 case 'o': break;
733 vapier 1.39 case 'x': show_pax = 1; break;
734     case 'e': show_stack = 1; break;
735     case 't': show_textrel = 1; break;
736     case 'r': show_rpath = 1; break;
737     case 'n': show_needed = 1; break;
738     case 'i': show_interp = 1; break;
739     default:
740     err("Invalid format specifier '%c' (byte %i)",
741     out_format[flag], flag+1);
742     }
743     }
744 vapier 1.41
745     /* construct our default format */
746     } else {
747     size_t fmt_len = 30;
748     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
749     if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
750     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
751     if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
752     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
753     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
754     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
755     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
756     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
757     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
758 vapier 1.39 }
759 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
760 vapier 1.39
761     /* now lets actually do the scanning */
762 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
763     if (scan_envpath) scanelf_envpath();
764 solar 1.45 if (from_file) {
765     scanelf_from_file(from_file);
766     free(from_file);
767     from_file = *argv;
768     }
769     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
770 vapier 1.25 err("Nothing to scan !?");
771 vapier 1.10 while (optind < argc)
772     scanelf_dir(argv[optind++]);
773 vapier 1.27
774 vapier 1.39 /* clean up */
775     if (find_sym) {
776     free(find_sym);
777     free(versioned_symname);
778     }
779     if (out_format) free(out_format);
780 vapier 1.10 }
781    
782    
783    
784 vapier 1.41 /* utility funcs */
785     static char *xstrdup(char *s)
786     {
787     char *ret = strdup(s);
788     if (!ret) err("Could not strdup(): %s", strerror(errno));
789     return ret;
790     }
791     static void *xmalloc(size_t size)
792     {
793     void *ret = malloc(size);
794     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
795     return ret;
796     }
797     static void xstrcat(char **dst, const char *src, size_t *curr_len)
798     {
799     long new_len;
800    
801     new_len = strlen(*dst) + strlen(src);
802     if (*curr_len <= new_len) {
803     *curr_len = new_len + (*curr_len / 2);
804     *dst = realloc(*dst, *curr_len);
805     if (!*dst)
806     err("could not realloc %li bytes", (unsigned long)*curr_len);
807     }
808    
809     strcat(*dst, src);
810     }
811     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
812     {
813     static char my_app[2];
814     my_app[0] = append;
815     my_app[1] = '\0';
816     xstrcat(dst, my_app, curr_len);
817     }
818     static int xemptybuffer(const char *buff)
819     {
820     long i;
821     for (i=0; buff[i]; ++i)
822     if (buff[i] != ' ')
823     return 0;
824     return 1;
825     }
826    
827    
828    
829 vapier 1.10 int main(int argc, char *argv[])
830 solar 1.1 {
831 vapier 1.10 if (argc < 2)
832     usage(EXIT_FAILURE);
833     parseargs(argc, argv);
834 solar 1.21 fclose(stdout);
835 vapier 1.10 return EXIT_SUCCESS;
836 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20