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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.21 - (hide annotations) (download) (as text)
Sun Apr 3 16:02:25 2005 UTC (9 years, 8 months ago) by solar
Branch: MAIN
Changes since 1.20: +19 -4 lines
File MIME type: text/x-csrc
- added -o --file= option for redirecting stdout, use _POSIX_PATH_MAX vs PATH_MAX to mimic what is used elsewhere within the code.

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 solar 1.21 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.20 2005/04/02 19:06:36 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     #include <string.h>
28 vapier 1.10 #include <errno.h>
29 solar 1.1 #include <unistd.h>
30     #include <sys/stat.h>
31     #include <dirent.h>
32     #include <getopt.h>
33 solar 1.20 #include <assert.h>
34 solar 1.21
35 solar 1.1 #include "paxelf.h"
36    
37 solar 1.21 static const char *rcsid = "$Id: scanelf.c,v 1.20 2005/04/02 19:06:36 solar Exp $";
38 vapier 1.10
39    
40     /* helper functions for showing errors */
41 vapier 1.18 #define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
42 vapier 1.10 #define warn(fmt, args...) \
43     fprintf(stderr, "%s: " fmt "\n", argv0, ## args)
44     #define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args)
45     #define err(fmt, args...) \
46     do { \
47     warn(fmt, ## args); \
48     exit(EXIT_FAILURE); \
49     } while (0)
50    
51    
52    
53     /* prototypes */
54     static void scanelf_file(const char *filename);
55     static void scanelf_dir(const char *path);
56     static void scanelf_ldpath();
57     static void scanelf_envpath();
58     static void usage(int status);
59     static void parseargs(int argc, char *argv[]);
60    
61     /* variables to control behavior */
62     static char scan_ldpath = 0;
63     static char scan_envpath = 0;
64     static char dir_recurse = 0;
65 vapier 1.14 static char dir_crossmount = 1;
66 vapier 1.10 static char show_pax = 0;
67     static char show_stack = 0;
68     static char show_textrel = 0;
69     static char show_rpath = 0;
70 solar 1.16 static char show_banner = 1;
71 vapier 1.10 static char be_quiet = 0;
72 vapier 1.14 static char be_verbose = 0;
73 vapier 1.10
74 solar 1.1
75    
76 vapier 1.10 /* scan an elf file and show all the fun stuff */
77     static void scanelf_file(const char *filename)
78 solar 1.6 {
79 vapier 1.10 int i;
80 vapier 1.14 char found_pax, found_stack, found_relro, found_textrel, found_rpath;
81 vapier 1.10 Elf_Dyn *dyn;
82     elfobj *elf = NULL;
83    
84 vapier 1.14 found_pax = found_stack = found_relro = found_textrel = found_rpath = 0;
85 solar 1.12
86 vapier 1.10 /* verify this is real ELF */
87 vapier 1.14 if ((elf = readelf(filename)) == NULL) {
88 vapier 1.15 if (be_verbose > 1) printf("%s: not an ELF\n", filename);
89 vapier 1.10 return;
90 vapier 1.14 }
91     if (check_elf_header(elf->ehdr) || !IS_ELF(elf)) {
92 vapier 1.15 if (be_verbose > 1) printf("%s: cannot handle ELF :(\n", filename);
93 vapier 1.10 goto bail;
94 vapier 1.14 }
95    
96 vapier 1.15 if (be_verbose) printf("%s: scanning file\n", filename);
97 vapier 1.10
98     /* show the header */
99 solar 1.16 if (!be_quiet && show_banner) {
100 vapier 1.14 fputs(" TYPE ", stdout);
101     if (show_pax) fputs(" PAX ", stdout);
102     if (show_stack) fputs(" STK/REL ", stdout);
103     if (show_textrel) fputs("TEXTREL ", stdout);
104     if (show_rpath) fputs("RPATH ", stdout);
105     fputs(" FILE\n", stdout);
106 solar 1.16 show_banner = 0;
107 vapier 1.10 }
108    
109     /* dump all the good stuff */
110     if (!be_quiet)
111     printf("%-7s ", get_elfetype(elf->ehdr->e_type));
112    
113 vapier 1.14 if (show_pax) {
114     char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
115     if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
116     found_pax = 1;
117     printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
118     }
119     }
120 vapier 1.10
121     /* stack fun */
122     if (show_stack) {
123     for (i = 0; i < elf->ehdr->e_phnum; i++) {
124     if (elf->phdr[i].p_type != PT_GNU_STACK && \
125     elf->phdr[i].p_type != PT_GNU_RELRO) continue;
126    
127     if (be_quiet && !(elf->phdr[i].p_flags & PF_X))
128     continue;
129    
130 solar 1.12 if (elf->phdr[i].p_type == PT_GNU_STACK)
131     found_stack = 1;
132     if (elf->phdr[i].p_type == PT_GNU_RELRO)
133     found_relro = 1;
134    
135 vapier 1.10 printf("%s ", gnu_short_stack_flags(elf->phdr[i].p_flags));
136     }
137 solar 1.12 if (!be_quiet && !found_stack) fputs("--- ", stdout);
138     if (!be_quiet && !found_relro) fputs("--- ", stdout);
139 vapier 1.10 }
140    
141     /* textrel fun */
142     if (show_textrel) {
143     for (i = 0; i < elf->ehdr->e_phnum; i++) {
144     if (elf->phdr[i].p_type != PT_DYNAMIC) continue;
145    
146     dyn = (Elf_Dyn *)(elf->data + elf->phdr[i].p_offset);
147     while (dyn->d_tag != DT_NULL) {
148     if (dyn->d_tag == DT_TEXTREL) { //dyn->d_tag != DT_FLAGS)
149     found_textrel = 1;
150     // if (dyn->d_un.d_val & DF_TEXTREL)
151 solar 1.12 fputs("TEXTREL ", stdout);
152 vapier 1.10 }
153     ++dyn;
154     }
155     }
156 solar 1.12 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
157 vapier 1.10 }
158    
159     /* rpath fun */
160     /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
161     if (show_rpath) {
162     Elf_Shdr *strtbl = elf_findsecbyname(elf, ".dynstr");
163    
164     if (strtbl)
165     for (i = 0; i < elf->ehdr->e_phnum; i++) {
166     if (elf->phdr[i].p_type != PT_DYNAMIC) continue;
167    
168     dyn = (Elf_Dyn *)(elf->data + elf->phdr[i].p_offset);
169     while (dyn->d_tag != DT_NULL) {
170     if (dyn->d_tag == DT_RPATH) { //|| dyn->d_tag != DT_RUNPATH)
171     char *rpath = elf->data + strtbl->sh_offset + dyn->d_un.d_ptr;
172     found_rpath = 1;
173     printf("%s ", rpath);
174     }
175     ++dyn;
176     }
177     }
178 vapier 1.14 if (!be_quiet && !found_rpath) fputs(" - ", stdout);
179 vapier 1.10 }
180    
181 vapier 1.14 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath)
182 solar 1.13 puts(filename);
183 vapier 1.10
184     bail:
185     unreadelf(elf);
186 solar 1.6 }
187    
188 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
189 vapier 1.10 static void scanelf_dir(const char *path)
190 solar 1.1 {
191 vapier 1.10 register DIR *dir;
192     register struct dirent *dentry;
193 vapier 1.14 struct stat st_top, st;
194 solar 1.21 char buf[_POSIX_PATH_MAX];
195 solar 1.20 size_t len = 0;
196 vapier 1.10
197     /* make sure path exists */
198 vapier 1.14 if (lstat(path, &st_top) == -1)
199 vapier 1.10 return;
200 solar 1.11
201 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
202 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
203 vapier 1.10 scanelf_file(path);
204     return;
205     }
206    
207     /* now scan the dir looking for fun stuff */
208     if ((dir = opendir(path)) == NULL) {
209     warnf("could not opendir %s: %s", path, strerror(errno));
210     return;
211     }
212 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
213 solar 1.11
214 vapier 1.10 while ((dentry = readdir(dir))) {
215     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
216     continue;
217     len = (strlen(path) + 2 + strlen(dentry->d_name));
218 solar 1.20 assert(len < sizeof(buf));
219     strncpy(buf, path, len);
220     strncat(buf, "/", len);
221     strncat(buf, dentry->d_name, len);
222     buf[sizeof(buf)] = 0;
223     if (lstat(buf, &st) != -1) {
224 vapier 1.10 if (S_ISREG(st.st_mode))
225 solar 1.20 scanelf_file(buf);
226 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
227 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
228 solar 1.20 scanelf_dir(buf);
229 vapier 1.10 }
230     }
231     }
232     closedir(dir);
233 solar 1.1 }
234    
235 vapier 1.10 /* scan /etc/ld.so.conf for paths */
236     static void scanelf_ldpath()
237     {
238 vapier 1.17 char scan_l, scan_ul, scan_ull;
239 vapier 1.10 char *path, *p;
240     FILE *fp;
241    
242     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
243     err("Unable to open ld.so.conf: %s", strerror(errno));
244    
245 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
246    
247 vapier 1.10 path = malloc(_POSIX_PATH_MAX);
248     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
249     if (*path == '/') {
250     if ((p = strrchr(path, '\r')) != NULL)
251     *p = 0;
252     if ((p = strrchr(path, '\n')) != NULL)
253     *p = 0;
254 vapier 1.17 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
255     if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
256     if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
257 vapier 1.10 scanelf_dir(path);
258     }
259     free(path);
260    
261 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
262     if (!scan_ul) scanelf_dir("/usr/lib");
263     if (!scan_ull) scanelf_dir("/usr/local/lib");
264    
265 vapier 1.10 fclose(fp);
266     }
267 solar 1.1
268 vapier 1.10 /* scan env PATH for paths */
269     static void scanelf_envpath()
270 solar 1.1 {
271 vapier 1.10 char *path, *p;
272    
273     path = getenv("PATH");
274     if (!path)
275     err("PATH is not set in your env !");
276    
277     if ((path = strdup(path)) == NULL)
278     err("stdup failed: %s", strerror(errno));
279    
280     while ((p = strrchr(path, ':')) != NULL) {
281     scanelf_dir(p + 1);
282     *p = 0;
283     }
284 vapier 1.17
285 vapier 1.10 free(path);
286 solar 1.1 }
287    
288    
289 vapier 1.10
290     /* usage / invocation handling functions */
291 solar 1.21 #define PARSE_FLAGS "plRmxetro:aqvBhV"
292 vapier 1.10 static struct option const long_opts[] = {
293     {"path", no_argument, NULL, 'p'},
294     {"ldpath", no_argument, NULL, 'l'},
295     {"recursive", no_argument, NULL, 'R'},
296 vapier 1.14 {"mount", no_argument, NULL, 'm'},
297 vapier 1.10 {"pax", no_argument, NULL, 'x'},
298 solar 1.16 {"header", no_argument, NULL, 'e'},
299 vapier 1.10 {"textrel", no_argument, NULL, 't'},
300     {"rpath", no_argument, NULL, 'r'},
301 solar 1.21 {"file",required_argument, NULL, 'o'},
302 vapier 1.10 {"all", no_argument, NULL, 'a'},
303     {"quiet", no_argument, NULL, 'q'},
304 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
305 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
306 vapier 1.10 {"help", no_argument, NULL, 'h'},
307     {"version", no_argument, NULL, 'V'},
308     {NULL, no_argument, NULL, 0x0}
309     };
310     static char *opts_help[] = {
311     "Scan all directories in PATH environment",
312     "Scan all directories in /etc/ld.so.conf",
313 vapier 1.14 "Scan directories recursively",
314     "Don't recursively cross mount points\n",
315 vapier 1.10 "Print PaX markings",
316     "Print GNU_STACK markings",
317     "Print TEXTREL information",
318     "Print RPATH information",
319 solar 1.21 "Write output stream to a filename",
320 solar 1.16 "Print all scanned info (-x -e -t -r)\n",
321 vapier 1.14 "Only output 'bad' things",
322     "Be verbose (can be specified more than once)",
323     "Don't display the header",
324 vapier 1.10 "Print this help and exit",
325     "Print version and exit",
326     NULL
327     };
328    
329     /* display usage and exit */
330     static void usage(int status)
331 solar 1.1 {
332 vapier 1.10 int i;
333     printf(" Scan ELF binaries for stuff\n\n"
334     "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
335 solar 1.12 fputs("Options:\n", stdout);
336 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
337     printf(" -%c, --%-12s %s\n", long_opts[i].val,
338     long_opts[i].name, opts_help[i]);
339 solar 1.16 #ifdef MANLYPAGE
340     for (i = 0; long_opts[i].name; ++i)
341     printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
342     long_opts[i].name, opts_help[i]);
343     #endif
344 vapier 1.10 exit(status);
345 solar 1.1 }
346    
347     /* parse command line arguments and preform needed actions */
348 vapier 1.10 static void parseargs(int argc, char *argv[])
349     {
350     int flag;
351    
352     opterr = 0;
353     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
354     switch (flag) {
355    
356     case 'V': /* version info */
357 solar 1.19 printf("%s compiled %s\n%s\n"
358     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
359     __FILE__, __DATE__, rcsid, argv0);
360 vapier 1.10 exit(EXIT_SUCCESS);
361     break;
362 solar 1.16 case 's': /* reserved for -s, --symbol= */
363 vapier 1.10 case 'h': usage(EXIT_SUCCESS); break;
364    
365 solar 1.21 case 'o':
366     {
367     FILE *fp = NULL;
368     fp = freopen(optarg, "w", stdout);
369     if (fp == NULL) {
370     fputs("open ", stderr);
371     perror(optarg);
372     } else
373     stdout = fp;
374     break;
375     }
376 solar 1.16 case 'B': show_banner = 0; break;
377 vapier 1.10 case 'l': scan_ldpath = 1; break;
378     case 'p': scan_envpath = 1; break;
379     case 'R': dir_recurse = 1; break;
380 vapier 1.14 case 'm': dir_crossmount = 0; break;
381 vapier 1.10 case 'x': show_pax = 1; break;
382 solar 1.16 case 'e': show_stack = 1; break;
383 vapier 1.10 case 't': show_textrel = 1; break;
384     case 'r': show_rpath = 1; break;
385     case 'q': be_quiet = 1; break;
386 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
387 vapier 1.10 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
388    
389     case ':':
390     warn("Option missing parameter");
391     usage(EXIT_FAILURE);
392     break;
393     case '?':
394     warn("Unknown option");
395     usage(EXIT_FAILURE);
396     break;
397     default:
398     err("Unhandled option '%c'", flag);
399     break;
400     }
401     }
402    
403 vapier 1.14 if (be_quiet && be_verbose)
404     err("You can be quiet or you can be verbose, not both, stupid");
405    
406 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
407     if (scan_envpath) scanelf_envpath();
408     while (optind < argc)
409     scanelf_dir(argv[optind++]);
410     }
411    
412    
413    
414     int main(int argc, char *argv[])
415 solar 1.1 {
416 vapier 1.10 if (argc < 2)
417     usage(EXIT_FAILURE);
418     parseargs(argc, argv);
419 solar 1.21 fclose(stdout);
420 vapier 1.10 return EXIT_SUCCESS;
421 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20