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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.50 - (hide annotations) (download) (as text)
Wed May 18 04:10:14 2005 UTC (9 years, 4 months ago) by vapier
Branch: MAIN
Changes since 1.49: +4 -3 lines
File MIME type: text/x-csrc
add BIND to all 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.50 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.49 2005/05/18 04:08:30 vapier Exp $
6 solar 1.1 *
7     ********************************************************************
8     * This program is free software; you can redistribute it and/or
9     * modify it under the terms of the GNU General Public License as
10     * published by the Free Software Foundation; either version 2 of the
11     * License, or (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful, but
14     * WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16     * General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21     * MA 02111-1307, USA.
22     */
23    
24     #include <stdio.h>
25     #include <stdlib.h>
26     #include <sys/types.h>
27 solar 1.28 #define __USE_GNU
28 solar 1.1 #include <string.h>
29 vapier 1.10 #include <errno.h>
30 solar 1.1 #include <unistd.h>
31     #include <sys/stat.h>
32     #include <dirent.h>
33     #include <getopt.h>
34 solar 1.20 #include <assert.h>
35 solar 1.21
36 solar 1.1 #include "paxelf.h"
37    
38 vapier 1.50 static const char *rcsid = "$Id: scanelf.c,v 1.49 2005/05/18 04:08:30 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 vapier 1.48 static char *ldpaths[256];
58 vapier 1.10 static char scan_ldpath = 0;
59     static char scan_envpath = 0;
60 vapier 1.37 static char scan_symlink = 1;
61 vapier 1.10 static char dir_recurse = 0;
62 vapier 1.14 static char dir_crossmount = 1;
63 vapier 1.10 static char show_pax = 0;
64     static char show_stack = 0;
65     static char show_textrel = 0;
66     static char show_rpath = 0;
67 vapier 1.32 static char show_needed = 0;
68 vapier 1.38 static char show_interp = 0;
69 vapier 1.49 static char show_bind = 0;
70 solar 1.16 static char show_banner = 1;
71 vapier 1.10 static char be_quiet = 0;
72 vapier 1.14 static char be_verbose = 0;
73 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
74     static char *out_format = NULL;
75 vapier 1.10
76 solar 1.1
77    
78 vapier 1.39 /* sub-funcs for scanelf_file() */
79 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
80 solar 1.6 {
81 vapier 1.41 static char *paxflags;
82    
83     if (!show_pax) return NULL;
84 vapier 1.10
85 vapier 1.39 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
86     if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
87     *found_pax = 1;
88 vapier 1.41 return paxflags;
89 vapier 1.14 }
90 vapier 1.41
91     return NULL;
92 vapier 1.39 }
93 vapier 1.41 static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
94 vapier 1.39 {
95 vapier 1.43 static char ret[8];
96 vapier 1.41 char *found;
97 vapier 1.44 unsigned long i, off, shown;
98 vapier 1.41
99     if (!show_stack) return NULL;
100    
101     shown = 0;
102 vapier 1.43 strcpy(ret, "--- ---");
103 vapier 1.44
104     if (elf->phdr) {
105 vapier 1.26 #define SHOW_STACK(B) \
106 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
107     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
108     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
109     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
110 vapier 1.41 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
111     found = found_stack; \
112     off = 0; \
113     } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
114     found = found_relro; \
115     off = 3; \
116     } else \
117     continue; \
118 vapier 1.39 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
119     continue; \
120 vapier 1.41 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
121     *found = 1; \
122     ++shown; \
123 vapier 1.39 } \
124     }
125     SHOW_STACK(32)
126     SHOW_STACK(64)
127 vapier 1.44 }
128    
129 vapier 1.41 if (be_quiet && !shown)
130     return NULL;
131     else
132     return ret;
133 vapier 1.39 }
134 vapier 1.41 static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
135 vapier 1.39 {
136 vapier 1.41 static char *ret = "TEXTREL";
137 vapier 1.44 unsigned long i;
138 vapier 1.41
139     if (!show_textrel) return NULL;
140    
141 vapier 1.44 if (elf->phdr) {
142 vapier 1.39 #define SHOW_TEXTREL(B) \
143     if (elf->elf_class == ELFCLASS ## B) { \
144     Elf ## B ## _Dyn *dyn; \
145     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
146     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
147 vapier 1.44 Elf ## B ## _Off offset; \
148 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
149     if (phdr[i].p_type != PT_DYNAMIC) continue; \
150 vapier 1.44 offset = EGET(phdr[i].p_offset); \
151     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
152     dyn = DYN ## B (elf->data + offset); \
153 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
154     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
155     *found_textrel = 1; \
156     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
157 vapier 1.41 return ret; \
158 vapier 1.39 } \
159     ++dyn; \
160 vapier 1.26 } \
161 vapier 1.39 } }
162     SHOW_TEXTREL(32)
163     SHOW_TEXTREL(64)
164 vapier 1.44 }
165    
166 vapier 1.41 if (be_quiet)
167     return NULL;
168     else
169     return " - ";
170 vapier 1.39 }
171 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
172 vapier 1.39 {
173 vapier 1.48 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
174     unsigned long i, s;
175     char *rpath, *runpath, **r;
176 vapier 1.39 void *strtbl_void;
177 vapier 1.10
178 vapier 1.39 if (!show_rpath) return;
179 vapier 1.10
180 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
181     rpath = runpath = NULL;
182 vapier 1.10
183 vapier 1.44 if (elf->phdr && strtbl_void) {
184 vapier 1.26 #define SHOW_RPATH(B) \
185     if (elf->elf_class == ELFCLASS ## B) { \
186     Elf ## B ## _Dyn *dyn; \
187     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
188     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
189     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
190 vapier 1.44 Elf ## B ## _Off offset; \
191 vapier 1.48 Elf ## B ## _Sxword word; \
192     /* Scan all the program headers */ \
193 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
194 vapier 1.48 /* Just scan dynamic headers */ \
195 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
196 vapier 1.44 offset = EGET(phdr[i].p_offset); \
197     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
198 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
199 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
200 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
201     if (word == DT_RPATH) { \
202     r = &rpath; \
203     } else if (word == DT_RUNPATH) { \
204     r = &runpath; \
205     } else { \
206     ++dyn; \
207     continue; \
208     } \
209     /* Verify the memory is somewhat sane */ \
210     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
211     if (offset < elf->len) { \
212     if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
213     *r = (char*)(elf->data + offset); \
214     /* If quiet, don't output paths in ld.so.conf */ \
215     if (be_quiet) \
216     for (s = 0; ldpaths[s]; ++s) \
217     if (!strcmp(ldpaths[s], *r)) { \
218     *r = NULL; \
219     break; \
220     } \
221     if (*r) *found_rpath = 1; \
222 vapier 1.26 } \
223     ++dyn; \
224     } \
225     } }
226     SHOW_RPATH(32)
227     SHOW_RPATH(64)
228 vapier 1.10 }
229 vapier 1.41
230 vapier 1.39 if (rpath && runpath) {
231 vapier 1.41 if (!strcmp(rpath, runpath)) {
232     xstrcat(ret, runpath, ret_len);
233     } else {
234 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
235 vapier 1.41 xchrcat(ret, '{', ret_len);
236     xstrcat(ret, rpath, ret_len);
237     xchrcat(ret, ',', ret_len);
238     xstrcat(ret, runpath, ret_len);
239     xchrcat(ret, '}', ret_len);
240 vapier 1.39 }
241     } else if (rpath || runpath)
242 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
243     else if (!be_quiet)
244     xstrcat(ret, " - ", ret_len);
245 vapier 1.39 }
246 vapier 1.41 static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
247 vapier 1.39 {
248 vapier 1.44 unsigned long i;
249 vapier 1.39 char *needed;
250     void *strtbl_void;
251    
252     if (!show_needed) return;
253 vapier 1.10
254 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
255 vapier 1.32
256 vapier 1.44 if (elf->phdr && strtbl_void) {
257 vapier 1.32 #define SHOW_NEEDED(B) \
258     if (elf->elf_class == ELFCLASS ## B) { \
259     Elf ## B ## _Dyn *dyn; \
260     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
261     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
262     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
263 vapier 1.44 Elf ## B ## _Off offset; \
264 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
265     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
266 vapier 1.44 offset = EGET(phdr[i].p_offset); \
267     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
268     dyn = DYN ## B (elf->data + offset); \
269 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
270     if (EGET(dyn->d_tag) == DT_NEEDED) { \
271 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
272 vapier 1.49 if (offset >= elf->len) { \
273     ++dyn; \
274     continue; \
275     } \
276 vapier 1.44 needed = (char*)(elf->data + offset); \
277 vapier 1.41 if (*found_needed) xchrcat(ret, ',', ret_len); \
278     xstrcat(ret, needed, ret_len); \
279 vapier 1.39 *found_needed = 1; \
280 vapier 1.32 } \
281     ++dyn; \
282     } \
283     } }
284     SHOW_NEEDED(32)
285     SHOW_NEEDED(64)
286     }
287 vapier 1.39 }
288 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
289 vapier 1.39 {
290     void *strtbl_void;
291    
292 vapier 1.41 if (!show_interp) return NULL;
293 vapier 1.32
294 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
295 vapier 1.38
296 vapier 1.39 if (strtbl_void) {
297 vapier 1.38 #define SHOW_INTERP(B) \
298     if (elf->elf_class == ELFCLASS ## B) { \
299 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
300     *found_interp = 1; \
301 vapier 1.41 return elf->data + EGET(strtbl->sh_offset); \
302 vapier 1.38 }
303     SHOW_INTERP(32)
304     SHOW_INTERP(64)
305     }
306 vapier 1.41 return NULL;
307 vapier 1.39 }
308 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
309     {
310     unsigned long i;
311     struct stat s;
312    
313     if (!show_bind) return NULL;
314    
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     if (!found_file) {
498     if (!be_quiet || found_pax || found_stack || found_textrel || \
499 vapier 1.49 found_rpath || found_needed || found_interp || found_bind || \
500     found_sym)
501     {
502     xchrcat(&out_buffer, ' ', &out_len);
503 vapier 1.41 xstrcat(&out_buffer, filename, &out_len);
504 vapier 1.49 }
505 vapier 1.27 }
506 vapier 1.41 if (!(be_quiet && xemptybuffer(out_buffer)))
507     puts(out_buffer);
508 vapier 1.10
509     unreadelf(elf);
510 solar 1.6 }
511    
512 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
513 vapier 1.10 static void scanelf_dir(const char *path)
514 solar 1.1 {
515 vapier 1.10 register DIR *dir;
516     register struct dirent *dentry;
517 vapier 1.14 struct stat st_top, st;
518 solar 1.21 char buf[_POSIX_PATH_MAX];
519 vapier 1.32 size_t pathlen = 0, len = 0;
520 vapier 1.10
521     /* make sure path exists */
522 vapier 1.39 if (lstat(path, &st_top) == -1) {
523     if (be_verbose > 2) printf("%s: does not exist\n", path);
524 vapier 1.10 return;
525 vapier 1.39 }
526 solar 1.11
527 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
528 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
529 vapier 1.10 scanelf_file(path);
530     return;
531     }
532    
533     /* now scan the dir looking for fun stuff */
534     if ((dir = opendir(path)) == NULL) {
535     warnf("could not opendir %s: %s", path, strerror(errno));
536     return;
537     }
538 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
539 solar 1.11
540 vapier 1.32 pathlen = strlen(path);
541 vapier 1.10 while ((dentry = readdir(dir))) {
542     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
543     continue;
544 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
545     if (len >= sizeof(buf)) {
546     warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
547     continue;
548     }
549 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
550 solar 1.20 if (lstat(buf, &st) != -1) {
551 vapier 1.10 if (S_ISREG(st.st_mode))
552 solar 1.20 scanelf_file(buf);
553 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
554 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
555 solar 1.20 scanelf_dir(buf);
556 vapier 1.10 }
557     }
558     }
559     closedir(dir);
560 solar 1.1 }
561    
562 vapier 1.47 static int scanelf_from_file(char *filename)
563     {
564 solar 1.45 FILE *fp = NULL;
565     char *p;
566     char path[_POSIX_PATH_MAX];
567    
568     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
569     fp = stdin;
570     else if ((fp = fopen(filename, "r")) == NULL)
571     return 1;
572    
573     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
574     if ((p = strchr(path, '\n')) != NULL)
575     *p = 0;
576     scanelf_dir(path);
577     }
578     if (fp != stdin)
579     fclose(fp);
580     return 0;
581     }
582    
583 vapier 1.48 static void load_ld_so_conf()
584     {
585     FILE *fp = NULL;
586     char *p;
587     char path[_POSIX_PATH_MAX];
588     int i = 0;
589    
590     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
591     return;
592    
593     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
594     if (*path != '/')
595     continue;
596    
597     if ((p = strrchr(path, '\r')) != NULL)
598     *p = 0;
599     if ((p = strchr(path, '\n')) != NULL)
600     *p = 0;
601    
602     ldpaths[i++] = xstrdup(path);
603    
604     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
605     break;
606     }
607     ldpaths[i] = NULL;
608    
609     fclose(fp);
610     }
611    
612 vapier 1.10 /* scan /etc/ld.so.conf for paths */
613     static void scanelf_ldpath()
614     {
615 vapier 1.17 char scan_l, scan_ul, scan_ull;
616 vapier 1.48 int i = 0;
617 vapier 1.10
618 vapier 1.48 if (!ldpaths[0])
619     err("Unable to load any paths from ld.so.conf");
620 vapier 1.10
621 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
622    
623 vapier 1.48 while (ldpaths[i]) {
624     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
625     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
626     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
627     scanelf_dir(ldpaths[i]);
628     ++i;
629     }
630 vapier 1.10
631 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
632     if (!scan_ul) scanelf_dir("/usr/lib");
633     if (!scan_ull) scanelf_dir("/usr/local/lib");
634 vapier 1.10 }
635 solar 1.1
636 vapier 1.10 /* scan env PATH for paths */
637     static void scanelf_envpath()
638 solar 1.1 {
639 solar 1.34 char *path, *p;
640 vapier 1.10
641     path = getenv("PATH");
642     if (!path)
643     err("PATH is not set in your env !");
644 vapier 1.41 path = xstrdup(path);
645 vapier 1.10
646     while ((p = strrchr(path, ':')) != NULL) {
647     scanelf_dir(p + 1);
648     *p = 0;
649     }
650 vapier 1.17
651 solar 1.34 free(path);
652 solar 1.1 }
653    
654    
655 vapier 1.10
656     /* usage / invocation handling functions */
657 vapier 1.49 #define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
658 vapier 1.27 #define a_argument required_argument
659 vapier 1.10 static struct option const long_opts[] = {
660     {"path", no_argument, NULL, 'p'},
661     {"ldpath", no_argument, NULL, 'l'},
662     {"recursive", no_argument, NULL, 'R'},
663 vapier 1.14 {"mount", no_argument, NULL, 'm'},
664 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
665 vapier 1.10 {"pax", no_argument, NULL, 'x'},
666 solar 1.16 {"header", no_argument, NULL, 'e'},
667 vapier 1.10 {"textrel", no_argument, NULL, 't'},
668     {"rpath", no_argument, NULL, 'r'},
669 vapier 1.32 {"needed", no_argument, NULL, 'n'},
670 vapier 1.38 {"interp", no_argument, NULL, 'i'},
671 vapier 1.49 {"bind", no_argument, NULL, 'b'},
672 vapier 1.27 {"symbol", a_argument, NULL, 's'},
673 vapier 1.10 {"all", no_argument, NULL, 'a'},
674     {"quiet", no_argument, NULL, 'q'},
675 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
676 vapier 1.39 {"format", a_argument, NULL, 'F'},
677 solar 1.45 {"from", a_argument, NULL, 'f'},
678 vapier 1.27 {"file", a_argument, NULL, 'o'},
679 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
680 vapier 1.10 {"help", no_argument, NULL, 'h'},
681     {"version", no_argument, NULL, 'V'},
682     {NULL, no_argument, NULL, 0x0}
683     };
684     static char *opts_help[] = {
685     "Scan all directories in PATH environment",
686     "Scan all directories in /etc/ld.so.conf",
687 vapier 1.14 "Scan directories recursively",
688 vapier 1.37 "Don't recursively cross mount points",
689     "Don't scan symlinks\n",
690 vapier 1.10 "Print PaX markings",
691     "Print GNU_STACK markings",
692     "Print TEXTREL information",
693     "Print RPATH information",
694 vapier 1.32 "Print NEEDED information",
695 vapier 1.38 "Print INTERP information",
696 vapier 1.49 "Print BIND information",
697 vapier 1.27 "Find a specified symbol",
698 vapier 1.46 "Print all scanned info (-x -e -t -r -n -i)\n",
699 vapier 1.14 "Only output 'bad' things",
700     "Be verbose (can be specified more than once)",
701 vapier 1.39 "Use specified format for output",
702 solar 1.45 "Read input stream from a filename",
703 vapier 1.24 "Write output stream to a filename",
704 vapier 1.14 "Don't display the header",
705 vapier 1.10 "Print this help and exit",
706     "Print version and exit",
707     NULL
708     };
709    
710     /* display usage and exit */
711     static void usage(int status)
712 solar 1.1 {
713 vapier 1.44 unsigned long i;
714 vapier 1.37 printf(" Scan ELF binaries for stuff\n\n"
715 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
716     printf("Options: -[%s]\n", PARSE_FLAGS);
717 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
718 vapier 1.27 if (long_opts[i].has_arg == no_argument)
719     printf(" -%c, --%-13s %s\n", long_opts[i].val,
720     long_opts[i].name, opts_help[i]);
721     else
722     printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
723     long_opts[i].name, opts_help[i]);
724 solar 1.45
725     if (status != EXIT_SUCCESS)
726     exit(status);
727    
728 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
729     puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
730     puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
731 vapier 1.49 puts(" %i INTERP \t%b BIND \t%s symbol");
732 solar 1.45
733 vapier 1.10 exit(status);
734 solar 1.1 }
735    
736     /* parse command line arguments and preform needed actions */
737 vapier 1.10 static void parseargs(int argc, char *argv[])
738     {
739 vapier 1.48 int i;
740 solar 1.45 char *from_file = NULL;
741 vapier 1.10
742     opterr = 0;
743 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
744     switch (i) {
745 vapier 1.10
746 vapier 1.39 case 'V':
747 solar 1.19 printf("%s compiled %s\n%s\n"
748     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
749     __FILE__, __DATE__, rcsid, argv0);
750 vapier 1.10 exit(EXIT_SUCCESS);
751     break;
752     case 'h': usage(EXIT_SUCCESS); break;
753 solar 1.45 case 'f':
754     if (from_file == NULL)
755     from_file = xstrdup(optarg);
756     break;
757 vapier 1.24 case 'o': {
758 solar 1.21 FILE *fp = NULL;
759     fp = freopen(optarg, "w", stdout);
760 vapier 1.24 if (fp == NULL)
761     err("Could not open output stream '%s': %s", optarg, strerror(errno));
762     stdout = fp;
763 solar 1.21 break;
764     }
765 vapier 1.24
766 vapier 1.39 case 's': {
767     size_t len;
768 vapier 1.41 find_sym = xstrdup(optarg);
769 vapier 1.39 len = strlen(find_sym) + 1;
770 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
771 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
772     break;
773     }
774    
775     case 'F': {
776 solar 1.45 out_format = xstrdup(optarg);
777 vapier 1.39 break;
778     }
779 vapier 1.27
780 vapier 1.37 case 'y': scan_symlink = 0; break;
781 solar 1.16 case 'B': show_banner = 0; break;
782 vapier 1.10 case 'l': scan_ldpath = 1; break;
783     case 'p': scan_envpath = 1; break;
784     case 'R': dir_recurse = 1; break;
785 vapier 1.14 case 'm': dir_crossmount = 0; break;
786 vapier 1.10 case 'x': show_pax = 1; break;
787 solar 1.16 case 'e': show_stack = 1; break;
788 vapier 1.10 case 't': show_textrel = 1; break;
789     case 'r': show_rpath = 1; break;
790 vapier 1.32 case 'n': show_needed = 1; break;
791 vapier 1.38 case 'i': show_interp = 1; break;
792 vapier 1.49 case 'b': show_bind = 1; break;
793 vapier 1.10 case 'q': be_quiet = 1; break;
794 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
795 vapier 1.50 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
796     show_needed = show_interp = show_bind = 1; break;
797 vapier 1.10
798     case ':':
799 vapier 1.49 err("Option missing parameter\n");
800 vapier 1.10 case '?':
801 vapier 1.49 err("Unknown option\n");
802 vapier 1.10 default:
803 vapier 1.48 err("Unhandled option '%c'", i);
804 vapier 1.10 }
805     }
806    
807 vapier 1.39 /* let the format option override all other options */
808     if (out_format) {
809     show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
810 vapier 1.48 for (i = 0; out_format[i]; ++i) {
811     if (out_format[i] != '%') continue;
812 vapier 1.39
813 vapier 1.48 switch (out_format[++i]) {
814 vapier 1.39 case '%': break;
815     case 'F': break;
816     case 's': break;
817 vapier 1.41 case 'o': break;
818 vapier 1.39 case 'x': show_pax = 1; break;
819     case 'e': show_stack = 1; break;
820     case 't': show_textrel = 1; break;
821     case 'r': show_rpath = 1; break;
822     case 'n': show_needed = 1; break;
823     case 'i': show_interp = 1; break;
824 vapier 1.49 case 'b': show_bind = 1; break;
825 vapier 1.39 default:
826     err("Invalid format specifier '%c' (byte %i)",
827 vapier 1.48 out_format[i], i+1);
828 vapier 1.39 }
829     }
830 vapier 1.41
831     /* construct our default format */
832     } else {
833     size_t fmt_len = 30;
834     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
835     if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
836     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
837     if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
838     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
839     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
840     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
841     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
842 vapier 1.49 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
843 vapier 1.41 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
844     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
845 vapier 1.39 }
846 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
847 vapier 1.39
848     /* now lets actually do the scanning */
849 vapier 1.48 if (scan_ldpath || (show_rpath && be_quiet))
850     load_ld_so_conf();
851 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
852     if (scan_envpath) scanelf_envpath();
853 solar 1.45 if (from_file) {
854     scanelf_from_file(from_file);
855     free(from_file);
856     from_file = *argv;
857     }
858     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
859 vapier 1.25 err("Nothing to scan !?");
860 vapier 1.10 while (optind < argc)
861     scanelf_dir(argv[optind++]);
862 vapier 1.27
863 vapier 1.39 /* clean up */
864     if (find_sym) {
865     free(find_sym);
866     free(versioned_symname);
867     }
868     if (out_format) free(out_format);
869 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
870     free(ldpaths[i]);
871 vapier 1.10 }
872    
873    
874    
875 vapier 1.41 /* utility funcs */
876     static char *xstrdup(char *s)
877     {
878     char *ret = strdup(s);
879     if (!ret) err("Could not strdup(): %s", strerror(errno));
880     return ret;
881     }
882     static void *xmalloc(size_t size)
883     {
884     void *ret = malloc(size);
885     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
886     return ret;
887     }
888     static void xstrcat(char **dst, const char *src, size_t *curr_len)
889     {
890     long new_len;
891    
892     new_len = strlen(*dst) + strlen(src);
893     if (*curr_len <= new_len) {
894     *curr_len = new_len + (*curr_len / 2);
895     *dst = realloc(*dst, *curr_len);
896     if (!*dst)
897     err("could not realloc %li bytes", (unsigned long)*curr_len);
898     }
899    
900     strcat(*dst, src);
901     }
902     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
903     {
904     static char my_app[2];
905     my_app[0] = append;
906     my_app[1] = '\0';
907     xstrcat(dst, my_app, curr_len);
908     }
909     static int xemptybuffer(const char *buff)
910     {
911     long i;
912 vapier 1.49 for (i = 0; buff[i]; ++i)
913 vapier 1.41 if (buff[i] != ' ')
914     return 0;
915     return 1;
916     }
917    
918    
919    
920 vapier 1.10 int main(int argc, char *argv[])
921 solar 1.1 {
922 vapier 1.10 if (argc < 2)
923     usage(EXIT_FAILURE);
924     parseargs(argc, argv);
925 solar 1.21 fclose(stdout);
926 vapier 1.10 return EXIT_SUCCESS;
927 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20