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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations) (download) (as text)
Fri Apr 1 19:56:34 2005 UTC (9 years ago) by vapier
Branch: MAIN
Changes since 1.13: +51 -26 lines
File MIME type: text/x-csrc
add --mount, --verbose, and --noheader options

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.14 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.13 2005/03/31 18:34:01 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    
34     #include "paxelf.h"
35    
36 vapier 1.14 static const char *rcsid = "$Id: scanelf.c,v 1.13 2005/03/31 18:34:01 solar 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     static char show_header = 1;
70     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     if (be_verbose > 1) printf("File '%s' is 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     if (be_verbose > 1) printf("Cannot handle ELF '%s' :(\n", filename);
92 vapier 1.10 goto bail;
93 vapier 1.14 }
94    
95     if (be_verbose) printf("Scanning file %s\n", filename);
96 vapier 1.10
97     /* show the header */
98     if (!be_quiet && show_header) {
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 vapier 1.10 show_header = 0;
106     }
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.14 if (be_verbose) printf("Scanning dir %s\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 vapier 1.14 #define PARSE_FLAGS "plRmxstraqvHhV"
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     {"stack", no_argument, NULL, 's'},
289     {"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     {"noheader", no_argument, NULL, 'H'},
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 vapier 1.14 "Print all scanned info (-x -s -t -r)\n",
309     "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     exit(status);
328 solar 1.1 }
329    
330     /* parse command line arguments and preform needed actions */
331 vapier 1.10 static void parseargs(int argc, char *argv[])
332     {
333     int flag;
334    
335     opterr = 0;
336     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
337     switch (flag) {
338    
339     case 'V': /* version info */
340     printf("%s compiled %s\n"
341 solar 1.11 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n"
342 vapier 1.10 "%s\n",
343     __FILE__, __DATE__, argv0, rcsid);
344     exit(EXIT_SUCCESS);
345     break;
346     case 'h': usage(EXIT_SUCCESS); break;
347    
348 vapier 1.14 case 'H': show_header = 0; break;
349 vapier 1.10 case 'l': scan_ldpath = 1; break;
350     case 'p': scan_envpath = 1; break;
351     case 'R': dir_recurse = 1; break;
352 vapier 1.14 case 'm': dir_crossmount = 0; break;
353 vapier 1.10 case 'x': show_pax = 1; break;
354     case 's': show_stack = 1; break;
355     case 't': show_textrel = 1; break;
356     case 'r': show_rpath = 1; break;
357     case 'q': be_quiet = 1; break;
358 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
359 vapier 1.10 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
360    
361     case ':':
362     warn("Option missing parameter");
363     usage(EXIT_FAILURE);
364     break;
365     case '?':
366     warn("Unknown option");
367     usage(EXIT_FAILURE);
368     break;
369     default:
370     err("Unhandled option '%c'", flag);
371     break;
372     }
373     }
374    
375 vapier 1.14 if (be_quiet && be_verbose)
376     err("You can be quiet or you can be verbose, not both, stupid");
377    
378 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
379     if (scan_envpath) scanelf_envpath();
380     while (optind < argc)
381     scanelf_dir(argv[optind++]);
382     }
383    
384    
385    
386     int main(int argc, char *argv[])
387 solar 1.1 {
388 vapier 1.10 if (argc < 2)
389     usage(EXIT_FAILURE);
390     parseargs(argc, argv);
391     return EXIT_SUCCESS;
392 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20