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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.68 - (hide annotations) (download) (as text)
Fri Jun 3 15:03:25 2005 UTC (9 years, 5 months ago) by solar
Branch: MAIN
Changes since 1.67: +8 -8 lines
File MIME type: text/x-csrc
- make scanelf/pspax happy with -Wwrite-strings

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

  ViewVC Help
Powered by ViewVC 1.1.20