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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.60 - (hide annotations) (download) (as text)
Fri May 27 02:58:39 2005 UTC (9 years, 3 months ago) by vapier
Branch: MAIN
Changes since 1.59: +12 -6 lines
File MIME type: text/x-csrc
fixes for FreeBSD

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.60 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.59 2005/05/25 21:58:03 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 vapier 1.60 #include <libgen.h>
28     #include <limits.h>
29 solar 1.28 #define __USE_GNU
30 solar 1.1 #include <string.h>
31 vapier 1.10 #include <errno.h>
32 solar 1.1 #include <unistd.h>
33     #include <sys/stat.h>
34     #include <dirent.h>
35     #include <getopt.h>
36 solar 1.20 #include <assert.h>
37 solar 1.21
38 solar 1.1 #include "paxelf.h"
39    
40 vapier 1.60 static const char *rcsid = "$Id: scanelf.c,v 1.59 2005/05/25 21:58:03 vapier Exp $";
41 vapier 1.36 #define argv0 "scanelf"
42 vapier 1.10
43    
44    
45     /* prototypes */
46     static void scanelf_file(const char *filename);
47     static void scanelf_dir(const char *path);
48     static void scanelf_ldpath();
49     static void scanelf_envpath();
50     static void usage(int status);
51     static void parseargs(int argc, char *argv[]);
52 vapier 1.60 static char *xstrdup(const char *s);
53 vapier 1.41 static void *xmalloc(size_t size);
54     static void xstrcat(char **dst, const char *src, size_t *curr_len);
55     static inline void xchrcat(char **dst, const char append, size_t *curr_len);
56 vapier 1.10
57     /* variables to control behavior */
58 vapier 1.48 static char *ldpaths[256];
59 vapier 1.10 static char scan_ldpath = 0;
60     static char scan_envpath = 0;
61 vapier 1.37 static char scan_symlink = 1;
62 vapier 1.10 static char dir_recurse = 0;
63 vapier 1.14 static char dir_crossmount = 1;
64 vapier 1.10 static char show_pax = 0;
65     static char show_stack = 0;
66     static char show_textrel = 0;
67     static char show_rpath = 0;
68 vapier 1.32 static char show_needed = 0;
69 vapier 1.38 static char show_interp = 0;
70 vapier 1.49 static char show_bind = 0;
71 solar 1.16 static char show_banner = 1;
72 vapier 1.10 static char be_quiet = 0;
73 vapier 1.14 static char be_verbose = 0;
74 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
75     static char *out_format = NULL;
76 vapier 1.10
77 solar 1.1
78    
79 vapier 1.39 /* sub-funcs for scanelf_file() */
80 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
81 solar 1.6 {
82 vapier 1.41 static char *paxflags;
83    
84     if (!show_pax) return NULL;
85 vapier 1.10
86 vapier 1.39 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
87     if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
88     *found_pax = 1;
89 vapier 1.41 return paxflags;
90 vapier 1.14 }
91 vapier 1.41
92     return NULL;
93 vapier 1.39 }
94 vapier 1.41 static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
95 vapier 1.39 {
96 solar 1.57 static char ret[8] = "--- ---";
97 vapier 1.41 char *found;
98 vapier 1.44 unsigned long i, off, shown;
99 vapier 1.41
100     if (!show_stack) return NULL;
101    
102     shown = 0;
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 solar 1.53 off = 4; \
116 vapier 1.41 } 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 vapier 1.59 if (EGET(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.60 Elf ## B ## _Xword word; \
192 vapier 1.48 /* 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 vapier 1.51 if (!elf->phdr) return NULL;
315 vapier 1.49
316     #define SHOW_BIND(B) \
317     if (elf->elf_class == ELFCLASS ## B) { \
318     Elf ## B ## _Dyn *dyn; \
319     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
320     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
321     Elf ## B ## _Off offset; \
322     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
323     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
324     offset = EGET(phdr[i].p_offset); \
325     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
326     dyn = DYN ## B (elf->data + offset); \
327     while (EGET(dyn->d_tag) != DT_NULL) { \
328     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
329     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
330     { \
331     if (be_quiet) return NULL; \
332     *found_bind = 1; \
333     return "NOW"; \
334     } \
335     ++dyn; \
336     } \
337     } \
338     }
339     SHOW_BIND(32)
340     SHOW_BIND(64)
341    
342 vapier 1.56 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
343 vapier 1.49 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.60 char *base, *basemem;
361     basemem = xstrdup(filename);
362     base = basename(basemem);
363 vapier 1.27 #define FIND_SYM(B) \
364     if (elf->elf_class == ELFCLASS ## B) { \
365     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
366     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
367     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
368 vapier 1.44 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
369 vapier 1.27 char *symname; \
370     for (i = 0; i < cnt; ++i) { \
371     if (sym->st_name) { \
372     symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
373 solar 1.28 if (*find_sym == '*') { \
374 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
375 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
376 vapier 1.60 base, \
377 vapier 1.32 (long)sym->st_size, \
378     (char *)get_elfstttype(sym->st_info), \
379     symname); \
380 vapier 1.39 *found_sym = 1; \
381 vapier 1.32 } else if ((strcmp(find_sym, symname) == 0) || \
382 vapier 1.39 (strcmp(symname, versioned_symname) == 0)) \
383     (*found_sym)++; \
384 vapier 1.27 } \
385     ++sym; \
386     } }
387     FIND_SYM(32)
388     FIND_SYM(64)
389 vapier 1.60 free(basemem);
390 vapier 1.39 }
391 vapier 1.41 if (*find_sym != '*' && *found_sym)
392     return find_sym;
393     if (be_quiet)
394     return NULL;
395     else
396     return " - ";
397 vapier 1.39 }
398     /* scan an elf file and show all the fun stuff */
399 solar 1.57 // #define prints(str) fputs(str, stdout)
400     #define prints(str) write(fileno(stdout), str, strlen(str))
401 vapier 1.39 static void scanelf_file(const char *filename)
402     {
403 vapier 1.44 unsigned long i;
404 vapier 1.39 char found_pax, found_stack, found_relro, found_textrel,
405 vapier 1.49 found_rpath, found_needed, found_interp, found_bind,
406     found_sym, found_file;
407 vapier 1.39 elfobj *elf;
408     struct stat st;
409 vapier 1.41 static char *out_buffer = NULL;
410     static size_t out_len;
411 vapier 1.39
412     /* make sure 'filename' exists */
413     if (lstat(filename, &st) == -1) {
414     if (be_verbose > 2) printf("%s: does not exist\n", filename);
415     return;
416     }
417     /* always handle regular files and handle symlinked files if no -y */
418 vapier 1.55 if (S_ISLNK(st.st_mode)) {
419     if (!scan_symlink) return;
420     stat(filename, &st);
421     }
422     if (!S_ISREG(st.st_mode)) {
423 vapier 1.39 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
424     return;
425     }
426    
427     found_pax = found_stack = found_relro = found_textrel = \
428 vapier 1.49 found_rpath = found_needed = found_interp = found_bind = \
429     found_sym = found_file = 0;
430 vapier 1.39
431     /* verify this is real ELF */
432     if ((elf = readelf(filename)) == NULL) {
433     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
434     return;
435     }
436    
437     if (be_verbose > 1)
438 vapier 1.41 printf("%s: scanning file {%s,%s}\n", filename,
439 vapier 1.39 get_elfeitype(elf, EI_CLASS, elf->elf_class),
440     get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
441     else if (be_verbose)
442     printf("%s: scanning file\n", filename);
443    
444 vapier 1.41 /* init output buffer */
445     if (!out_buffer) {
446     out_len = sizeof(char) * 80;
447     out_buffer = (char*)xmalloc(out_len);
448     }
449     *out_buffer = '\0';
450    
451 vapier 1.39 /* show the header */
452     if (!be_quiet && show_banner) {
453 vapier 1.49 for (i = 0; out_format[i]; ++i) {
454 vapier 1.41 if (out_format[i] != '%') continue;
455    
456     switch (out_format[++i]) {
457     case '%': break;
458 vapier 1.49 case 'F': prints("FILE "); found_file = 1; break;
459 vapier 1.41 case 'o': prints(" TYPE "); break;
460     case 'x': prints(" PAX "); break;
461     case 'e': prints("STK/REL "); break;
462     case 't': prints("TEXTREL "); break;
463     case 'r': prints("RPATH "); break;
464     case 'n': prints("NEEDED "); break;
465     case 'i': prints("INTERP "); break;
466 vapier 1.49 case 'b': prints("BIND "); break;
467 vapier 1.41 case 's': prints("SYM "); break;
468 vapier 1.39 }
469 vapier 1.27 }
470 vapier 1.49 if (!found_file) prints("FILE ");
471 vapier 1.41 prints("\n");
472 vapier 1.49 found_file = 0;
473 vapier 1.39 show_banner = 0;
474     }
475    
476     /* dump all the good stuff */
477 vapier 1.49 for (i = 0; out_format[i]; ++i) {
478 vapier 1.41 const char *out;
479    
480     /* make sure we trim leading spaces in quiet mode */
481     if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
482     *out_buffer = '\0';
483 vapier 1.39
484 vapier 1.41 if (out_format[i] != '%') {
485     xchrcat(&out_buffer, out_format[i], &out_len);
486     continue;
487     }
488 vapier 1.39
489 vapier 1.41 out = NULL;
490     switch (out_format[++i]) {
491     case '%': xchrcat(&out_buffer, '%', &out_len); break;
492     case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break;
493     case 'o': out = get_elfetype(elf); break;
494     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
495     case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
496     case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
497     case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
498     case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
499     case 'i': out = scanelf_file_interp(elf, &found_interp); break;
500 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
501 vapier 1.41 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
502 vapier 1.29 }
503 vapier 1.41 if (out) xstrcat(&out_buffer, out, &out_len);
504 vapier 1.39 }
505    
506 vapier 1.54 #define FOUND_SOMETHING() \
507     (found_pax || found_stack || found_textrel || found_rpath || \
508     found_needed || found_interp || found_bind || found_sym)
509    
510     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
511     xchrcat(&out_buffer, ' ', &out_len);
512     xstrcat(&out_buffer, filename, &out_len);
513 vapier 1.27 }
514 vapier 1.54 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
515 vapier 1.41 puts(out_buffer);
516 vapier 1.10
517     unreadelf(elf);
518 solar 1.6 }
519    
520 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
521 vapier 1.10 static void scanelf_dir(const char *path)
522 solar 1.1 {
523 vapier 1.10 register DIR *dir;
524     register struct dirent *dentry;
525 vapier 1.14 struct stat st_top, st;
526 solar 1.21 char buf[_POSIX_PATH_MAX];
527 vapier 1.32 size_t pathlen = 0, len = 0;
528 vapier 1.10
529     /* make sure path exists */
530 vapier 1.39 if (lstat(path, &st_top) == -1) {
531     if (be_verbose > 2) printf("%s: does not exist\n", path);
532 vapier 1.10 return;
533 vapier 1.39 }
534 solar 1.11
535 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
536 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
537 vapier 1.10 scanelf_file(path);
538     return;
539     }
540    
541     /* now scan the dir looking for fun stuff */
542     if ((dir = opendir(path)) == NULL) {
543     warnf("could not opendir %s: %s", path, strerror(errno));
544     return;
545     }
546 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
547 solar 1.11
548 vapier 1.32 pathlen = strlen(path);
549 vapier 1.10 while ((dentry = readdir(dir))) {
550     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
551     continue;
552 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
553     if (len >= sizeof(buf)) {
554     warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
555     continue;
556     }
557 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
558 solar 1.20 if (lstat(buf, &st) != -1) {
559 vapier 1.10 if (S_ISREG(st.st_mode))
560 solar 1.20 scanelf_file(buf);
561 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
562 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
563 solar 1.20 scanelf_dir(buf);
564 vapier 1.10 }
565     }
566     }
567     closedir(dir);
568 solar 1.1 }
569    
570 vapier 1.47 static int scanelf_from_file(char *filename)
571     {
572 solar 1.45 FILE *fp = NULL;
573     char *p;
574     char path[_POSIX_PATH_MAX];
575    
576     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
577     fp = stdin;
578     else if ((fp = fopen(filename, "r")) == NULL)
579     return 1;
580    
581     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
582     if ((p = strchr(path, '\n')) != NULL)
583     *p = 0;
584     scanelf_dir(path);
585     }
586     if (fp != stdin)
587     fclose(fp);
588     return 0;
589     }
590    
591 vapier 1.48 static void load_ld_so_conf()
592     {
593     FILE *fp = NULL;
594     char *p;
595     char path[_POSIX_PATH_MAX];
596     int i = 0;
597    
598     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
599     return;
600    
601     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
602     if (*path != '/')
603     continue;
604    
605     if ((p = strrchr(path, '\r')) != NULL)
606     *p = 0;
607     if ((p = strchr(path, '\n')) != NULL)
608     *p = 0;
609    
610     ldpaths[i++] = xstrdup(path);
611    
612     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
613     break;
614     }
615     ldpaths[i] = NULL;
616    
617     fclose(fp);
618     }
619    
620 vapier 1.10 /* scan /etc/ld.so.conf for paths */
621     static void scanelf_ldpath()
622     {
623 vapier 1.17 char scan_l, scan_ul, scan_ull;
624 vapier 1.48 int i = 0;
625 vapier 1.10
626 vapier 1.48 if (!ldpaths[0])
627     err("Unable to load any paths from ld.so.conf");
628 vapier 1.10
629 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
630    
631 vapier 1.48 while (ldpaths[i]) {
632     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
633     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
634     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
635     scanelf_dir(ldpaths[i]);
636     ++i;
637     }
638 vapier 1.10
639 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
640     if (!scan_ul) scanelf_dir("/usr/lib");
641     if (!scan_ull) scanelf_dir("/usr/local/lib");
642 vapier 1.10 }
643 solar 1.1
644 vapier 1.10 /* scan env PATH for paths */
645     static void scanelf_envpath()
646 solar 1.1 {
647 solar 1.34 char *path, *p;
648 vapier 1.10
649     path = getenv("PATH");
650     if (!path)
651     err("PATH is not set in your env !");
652 vapier 1.41 path = xstrdup(path);
653 vapier 1.10
654     while ((p = strrchr(path, ':')) != NULL) {
655     scanelf_dir(p + 1);
656     *p = 0;
657     }
658 vapier 1.17
659 solar 1.34 free(path);
660 solar 1.1 }
661    
662    
663 vapier 1.10
664     /* usage / invocation handling functions */
665 vapier 1.49 #define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
666 vapier 1.27 #define a_argument required_argument
667 vapier 1.10 static struct option const long_opts[] = {
668     {"path", no_argument, NULL, 'p'},
669     {"ldpath", no_argument, NULL, 'l'},
670     {"recursive", no_argument, NULL, 'R'},
671 vapier 1.14 {"mount", no_argument, NULL, 'm'},
672 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
673 vapier 1.10 {"pax", no_argument, NULL, 'x'},
674 solar 1.16 {"header", no_argument, NULL, 'e'},
675 vapier 1.10 {"textrel", no_argument, NULL, 't'},
676     {"rpath", no_argument, NULL, 'r'},
677 vapier 1.32 {"needed", no_argument, NULL, 'n'},
678 vapier 1.38 {"interp", no_argument, NULL, 'i'},
679 vapier 1.49 {"bind", no_argument, NULL, 'b'},
680 vapier 1.27 {"symbol", a_argument, NULL, 's'},
681 vapier 1.10 {"all", no_argument, NULL, 'a'},
682     {"quiet", no_argument, NULL, 'q'},
683 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
684 vapier 1.39 {"format", a_argument, NULL, 'F'},
685 solar 1.45 {"from", a_argument, NULL, 'f'},
686 vapier 1.27 {"file", a_argument, NULL, 'o'},
687 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
688 vapier 1.10 {"help", no_argument, NULL, 'h'},
689     {"version", no_argument, NULL, 'V'},
690     {NULL, no_argument, NULL, 0x0}
691     };
692 solar 1.57
693 vapier 1.10 static char *opts_help[] = {
694     "Scan all directories in PATH environment",
695     "Scan all directories in /etc/ld.so.conf",
696 vapier 1.14 "Scan directories recursively",
697 vapier 1.37 "Don't recursively cross mount points",
698     "Don't scan symlinks\n",
699 vapier 1.10 "Print PaX markings",
700     "Print GNU_STACK markings",
701     "Print TEXTREL information",
702     "Print RPATH information",
703 vapier 1.32 "Print NEEDED information",
704 vapier 1.38 "Print INTERP information",
705 vapier 1.49 "Print BIND information",
706 vapier 1.27 "Find a specified symbol",
707 solar 1.57 "Print all scanned info (-x -e -t -r -n -i -b)\n",
708 vapier 1.14 "Only output 'bad' things",
709     "Be verbose (can be specified more than once)",
710 vapier 1.39 "Use specified format for output",
711 solar 1.45 "Read input stream from a filename",
712 vapier 1.24 "Write output stream to a filename",
713 vapier 1.14 "Don't display the header",
714 vapier 1.10 "Print this help and exit",
715     "Print version and exit",
716     NULL
717     };
718    
719     /* display usage and exit */
720     static void usage(int status)
721 solar 1.1 {
722 vapier 1.44 unsigned long i;
723 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
724 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
725     printf("Options: -[%s]\n", PARSE_FLAGS);
726 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
727 vapier 1.27 if (long_opts[i].has_arg == no_argument)
728 solar 1.52 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
729 vapier 1.27 long_opts[i].name, opts_help[i]);
730     else
731 solar 1.52 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
732 vapier 1.27 long_opts[i].name, opts_help[i]);
733 solar 1.45
734     if (status != EXIT_SUCCESS)
735     exit(status);
736    
737 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
738     puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
739     puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
740 vapier 1.49 puts(" %i INTERP \t%b BIND \t%s symbol");
741 solar 1.45
742 vapier 1.10 exit(status);
743 solar 1.1 }
744    
745     /* parse command line arguments and preform needed actions */
746 vapier 1.10 static void parseargs(int argc, char *argv[])
747     {
748 vapier 1.48 int i;
749 solar 1.45 char *from_file = NULL;
750 vapier 1.10
751     opterr = 0;
752 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
753     switch (i) {
754 vapier 1.10
755 vapier 1.39 case 'V':
756 solar 1.19 printf("%s compiled %s\n%s\n"
757     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
758     __FILE__, __DATE__, rcsid, argv0);
759 vapier 1.10 exit(EXIT_SUCCESS);
760     break;
761     case 'h': usage(EXIT_SUCCESS); break;
762 solar 1.45 case 'f':
763     if (from_file == NULL)
764     from_file = xstrdup(optarg);
765     break;
766 vapier 1.24 case 'o': {
767 solar 1.21 FILE *fp = NULL;
768     fp = freopen(optarg, "w", stdout);
769 vapier 1.24 if (fp == NULL)
770     err("Could not open output stream '%s': %s", optarg, strerror(errno));
771     stdout = fp;
772 solar 1.21 break;
773     }
774 vapier 1.24
775 vapier 1.39 case 's': {
776     size_t len;
777 vapier 1.41 find_sym = xstrdup(optarg);
778 vapier 1.39 len = strlen(find_sym) + 1;
779 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
780 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
781     break;
782     }
783    
784     case 'F': {
785 solar 1.45 out_format = xstrdup(optarg);
786 vapier 1.39 break;
787     }
788 vapier 1.27
789 vapier 1.37 case 'y': scan_symlink = 0; break;
790 solar 1.16 case 'B': show_banner = 0; break;
791 vapier 1.10 case 'l': scan_ldpath = 1; break;
792     case 'p': scan_envpath = 1; break;
793     case 'R': dir_recurse = 1; break;
794 vapier 1.14 case 'm': dir_crossmount = 0; break;
795 vapier 1.10 case 'x': show_pax = 1; break;
796 solar 1.16 case 'e': show_stack = 1; break;
797 vapier 1.10 case 't': show_textrel = 1; break;
798     case 'r': show_rpath = 1; break;
799 vapier 1.32 case 'n': show_needed = 1; break;
800 vapier 1.38 case 'i': show_interp = 1; break;
801 vapier 1.49 case 'b': show_bind = 1; break;
802 vapier 1.10 case 'q': be_quiet = 1; break;
803 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
804 vapier 1.50 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
805     show_needed = show_interp = show_bind = 1; break;
806 vapier 1.10
807     case ':':
808 vapier 1.49 err("Option missing parameter\n");
809 vapier 1.10 case '?':
810 vapier 1.49 err("Unknown option\n");
811 vapier 1.10 default:
812 vapier 1.48 err("Unhandled option '%c'", i);
813 vapier 1.10 }
814     }
815    
816 vapier 1.39 /* let the format option override all other options */
817     if (out_format) {
818 vapier 1.58 show_pax = show_stack = show_textrel = show_rpath = \
819     show_needed = show_interp = show_bind = 0;
820 vapier 1.48 for (i = 0; out_format[i]; ++i) {
821     if (out_format[i] != '%') continue;
822 vapier 1.39
823 vapier 1.48 switch (out_format[++i]) {
824 vapier 1.39 case '%': break;
825     case 'F': break;
826     case 's': break;
827 vapier 1.41 case 'o': break;
828 vapier 1.39 case 'x': show_pax = 1; break;
829     case 'e': show_stack = 1; break;
830     case 't': show_textrel = 1; break;
831     case 'r': show_rpath = 1; break;
832     case 'n': show_needed = 1; break;
833     case 'i': show_interp = 1; break;
834 vapier 1.49 case 'b': show_bind = 1; break;
835 vapier 1.39 default:
836     err("Invalid format specifier '%c' (byte %i)",
837 vapier 1.48 out_format[i], i+1);
838 vapier 1.39 }
839     }
840 vapier 1.41
841     /* construct our default format */
842     } else {
843     size_t fmt_len = 30;
844     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
845     if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
846     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
847     if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
848     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
849     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
850     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
851     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
852 vapier 1.49 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
853 vapier 1.41 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
854     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
855 vapier 1.39 }
856 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
857 vapier 1.39
858     /* now lets actually do the scanning */
859 vapier 1.48 if (scan_ldpath || (show_rpath && be_quiet))
860     load_ld_so_conf();
861 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
862     if (scan_envpath) scanelf_envpath();
863 solar 1.45 if (from_file) {
864     scanelf_from_file(from_file);
865     free(from_file);
866     from_file = *argv;
867     }
868     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
869 vapier 1.25 err("Nothing to scan !?");
870 vapier 1.10 while (optind < argc)
871     scanelf_dir(argv[optind++]);
872 vapier 1.27
873 vapier 1.39 /* clean up */
874     if (find_sym) {
875     free(find_sym);
876     free(versioned_symname);
877     }
878     if (out_format) free(out_format);
879 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
880     free(ldpaths[i]);
881 vapier 1.10 }
882    
883    
884    
885 vapier 1.41 /* utility funcs */
886 vapier 1.60 static char *xstrdup(const char *s)
887 vapier 1.41 {
888     char *ret = strdup(s);
889     if (!ret) err("Could not strdup(): %s", strerror(errno));
890     return ret;
891     }
892 solar 1.57
893 vapier 1.41 static void *xmalloc(size_t size)
894     {
895     void *ret = malloc(size);
896     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
897     return ret;
898     }
899 solar 1.57
900 vapier 1.41 static void xstrcat(char **dst, const char *src, size_t *curr_len)
901     {
902     long new_len;
903    
904     new_len = strlen(*dst) + strlen(src);
905     if (*curr_len <= new_len) {
906     *curr_len = new_len + (*curr_len / 2);
907     *dst = realloc(*dst, *curr_len);
908     if (!*dst)
909     err("could not realloc %li bytes", (unsigned long)*curr_len);
910     }
911    
912     strcat(*dst, src);
913     }
914 solar 1.57
915 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len)
916     {
917     static char my_app[2];
918     my_app[0] = append;
919     my_app[1] = '\0';
920     xstrcat(dst, my_app, curr_len);
921     }
922    
923    
924 vapier 1.10 int main(int argc, char *argv[])
925 solar 1.1 {
926 vapier 1.10 if (argc < 2)
927     usage(EXIT_FAILURE);
928     parseargs(argc, argv);
929 solar 1.21 fclose(stdout);
930 vapier 1.10 return EXIT_SUCCESS;
931 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20