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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (hide annotations) (download) (as text)
Fri Apr 1 20:44:11 2005 UTC (9 years, 6 months ago) by solar
Branch: MAIN
Changes since 1.15: +17 -11 lines
File MIME type: text/x-csrc
- updated manpage again, rename -s/--stack to -e/--header and rename -H/--noheader to -B/--nobanner

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

  ViewVC Help
Powered by ViewVC 1.1.20