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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (hide annotations) (download) (as text)
Sun Apr 3 18:27:45 2005 UTC (9 years ago) by vapier
Branch: MAIN
Changes since 1.22: +30 -16 lines
File MIME type: text/x-csrc
handle rpath and runpath and make sure they are sane

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

  ViewVC Help
Powered by ViewVC 1.1.20