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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.58 - (hide annotations) (download) (as text)
Tue May 24 22:04:34 2005 UTC (9 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.57: +4 -3 lines
File MIME type: text/x-csrc
make sure -F disables -b too

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

  ViewVC Help
Powered by ViewVC 1.1.20