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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.54 - (hide annotations) (download) (as text)
Wed May 18 21:16:32 2005 UTC (9 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.53: +10 -20 lines
File MIME type: text/x-csrc
be quieter

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

  ViewVC Help
Powered by ViewVC 1.1.20