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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.45 - (hide annotations) (download) (as text)
Sat May 14 00:18:56 2005 UTC (9 years, 4 months ago) by solar
Branch: MAIN
Changes since 1.44: +51 -6 lines
File MIME type: text/x-csrc
- add option to read from streams

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 solar 1.45 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.44 2005/05/10 22:54:25 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 solar 1.45 static const char *rcsid = "$Id: scanelf.c,v 1.44 2005/05/10 22:54:25 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 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 solar 1.16 "Print all scanned info (-x -e -t -r)\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     puts("\nThe format modifiers for the -F option are");
638     puts(" %F Filename");
639     puts(" %x PaX Flags");
640     puts(" %e STACK/RELRO");
641     puts(" %t TEXTREL");
642     puts(" %r RPATH");
643     puts(" %n NEEDED");
644     puts(" %i INTERP");
645     puts(" %s symbol");
646    
647 vapier 1.10 exit(status);
648 solar 1.1 }
649    
650     /* parse command line arguments and preform needed actions */
651 vapier 1.10 static void parseargs(int argc, char *argv[])
652     {
653     int flag;
654 solar 1.45 char *from_file = NULL;
655 vapier 1.10
656     opterr = 0;
657     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
658     switch (flag) {
659    
660 vapier 1.39 case 'V':
661 solar 1.19 printf("%s compiled %s\n%s\n"
662     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
663     __FILE__, __DATE__, rcsid, argv0);
664 vapier 1.10 exit(EXIT_SUCCESS);
665     break;
666     case 'h': usage(EXIT_SUCCESS); break;
667 solar 1.45 case 'f':
668     if (from_file == NULL)
669     from_file = xstrdup(optarg);
670     break;
671 vapier 1.24 case 'o': {
672 solar 1.21 FILE *fp = NULL;
673     fp = freopen(optarg, "w", stdout);
674 vapier 1.24 if (fp == NULL)
675     err("Could not open output stream '%s': %s", optarg, strerror(errno));
676     stdout = fp;
677 solar 1.21 break;
678     }
679 vapier 1.24
680 vapier 1.39 case 's': {
681     size_t len;
682 vapier 1.41 find_sym = xstrdup(optarg);
683 vapier 1.39 len = strlen(find_sym) + 1;
684 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
685 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
686     break;
687     }
688    
689     case 'F': {
690 solar 1.45 out_format = xstrdup(optarg);
691 vapier 1.39 break;
692     }
693 vapier 1.27
694 vapier 1.37 case 'y': scan_symlink = 0; break;
695 solar 1.16 case 'B': show_banner = 0; break;
696 vapier 1.10 case 'l': scan_ldpath = 1; break;
697     case 'p': scan_envpath = 1; break;
698     case 'R': dir_recurse = 1; break;
699 vapier 1.14 case 'm': dir_crossmount = 0; break;
700 vapier 1.10 case 'x': show_pax = 1; break;
701 solar 1.16 case 'e': show_stack = 1; break;
702 vapier 1.10 case 't': show_textrel = 1; break;
703     case 'r': show_rpath = 1; break;
704 vapier 1.32 case 'n': show_needed = 1; break;
705 vapier 1.38 case 'i': show_interp = 1; break;
706 vapier 1.10 case 'q': be_quiet = 1; break;
707 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
708 vapier 1.38 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
709 vapier 1.10
710     case ':':
711 vapier 1.39 warn("Option missing parameter\n");
712 vapier 1.10 usage(EXIT_FAILURE);
713     break;
714     case '?':
715 vapier 1.39 warn("Unknown option\n");
716 vapier 1.10 usage(EXIT_FAILURE);
717     break;
718     default:
719     err("Unhandled option '%c'", flag);
720     break;
721     }
722     }
723    
724 vapier 1.14 if (be_quiet && be_verbose)
725     err("You can be quiet or you can be verbose, not both, stupid");
726    
727 vapier 1.39 /* let the format option override all other options */
728     if (out_format) {
729     show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
730     for (flag=0; out_format[flag]; ++flag) {
731     if (out_format[flag] != '%') continue;
732    
733     switch (out_format[++flag]) {
734     case '%': break;
735     case 'F': break;
736     case 's': break;
737 vapier 1.41 case 'o': break;
738 vapier 1.39 case 'x': show_pax = 1; break;
739     case 'e': show_stack = 1; break;
740     case 't': show_textrel = 1; break;
741     case 'r': show_rpath = 1; break;
742     case 'n': show_needed = 1; break;
743     case 'i': show_interp = 1; break;
744     default:
745     err("Invalid format specifier '%c' (byte %i)",
746     out_format[flag], flag+1);
747     }
748     }
749 vapier 1.41
750     /* construct our default format */
751     } else {
752     size_t fmt_len = 30;
753     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
754     if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
755     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
756     if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
757     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
758     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
759     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
760     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
761     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
762     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
763 vapier 1.39 }
764 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
765 vapier 1.39
766     /* now lets actually do the scanning */
767 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
768     if (scan_envpath) scanelf_envpath();
769 solar 1.45 if (from_file) {
770     scanelf_from_file(from_file);
771     free(from_file);
772     from_file = *argv;
773     }
774     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
775 vapier 1.25 err("Nothing to scan !?");
776 vapier 1.10 while (optind < argc)
777     scanelf_dir(argv[optind++]);
778 vapier 1.27
779 vapier 1.39 /* clean up */
780     if (find_sym) {
781     free(find_sym);
782     free(versioned_symname);
783     }
784     if (out_format) free(out_format);
785 vapier 1.10 }
786    
787    
788    
789 vapier 1.41 /* utility funcs */
790     static char *xstrdup(char *s)
791     {
792     char *ret = strdup(s);
793     if (!ret) err("Could not strdup(): %s", strerror(errno));
794     return ret;
795     }
796     static void *xmalloc(size_t size)
797     {
798     void *ret = malloc(size);
799     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
800     return ret;
801     }
802     static void xstrcat(char **dst, const char *src, size_t *curr_len)
803     {
804     long new_len;
805    
806     new_len = strlen(*dst) + strlen(src);
807     if (*curr_len <= new_len) {
808     *curr_len = new_len + (*curr_len / 2);
809     *dst = realloc(*dst, *curr_len);
810     if (!*dst)
811     err("could not realloc %li bytes", (unsigned long)*curr_len);
812     }
813    
814     strcat(*dst, src);
815     }
816     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
817     {
818     static char my_app[2];
819     my_app[0] = append;
820     my_app[1] = '\0';
821     xstrcat(dst, my_app, curr_len);
822     }
823     static int xemptybuffer(const char *buff)
824     {
825     long i;
826     for (i=0; buff[i]; ++i)
827     if (buff[i] != ' ')
828     return 0;
829     return 1;
830     }
831    
832    
833    
834 vapier 1.10 int main(int argc, char *argv[])
835 solar 1.1 {
836 vapier 1.10 if (argc < 2)
837     usage(EXIT_FAILURE);
838     parseargs(argc, argv);
839 solar 1.21 fclose(stdout);
840 vapier 1.10 return EXIT_SUCCESS;
841 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20