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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.22 - (hide annotations) (download) (as text)
Sun Apr 3 18:03:22 2005 UTC (9 years ago) by vapier
Branch: MAIN
Changes since 1.21: +2 -7 lines
File MIME type: text/x-csrc
remove check_elf_header and IS_ELF since readelf() has these checks built in now

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

  ViewVC Help
Powered by ViewVC 1.1.20