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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.18 - (hide annotations) (download) (as text)
Sat Apr 2 03:25:38 2005 UTC (9 years, 6 months ago) by vapier
Branch: MAIN
Changes since 1.17: +3 -3 lines
File MIME type: text/x-csrc
remove useless null

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.18 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.17 2005/04/02 00:11:01 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 vapier 1.18 static const char *rcsid = "$Id: scanelf.c,v 1.17 2005/04/02 00:11:01 vapier Exp $";
37 vapier 1.10
38    
39     /* helper functions for showing errors */
40 vapier 1.18 #define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
41 vapier 1.10 #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 vapier 1.17 char scan_l, scan_ul, scan_ull;
240 vapier 1.10 char *path, *p;
241     FILE *fp;
242    
243     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
244     err("Unable to open ld.so.conf: %s", strerror(errno));
245    
246 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
247    
248 vapier 1.10 path = malloc(_POSIX_PATH_MAX);
249     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
250     if (*path == '/') {
251     if ((p = strrchr(path, '\r')) != NULL)
252     *p = 0;
253     if ((p = strrchr(path, '\n')) != NULL)
254     *p = 0;
255 vapier 1.17 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
256     if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
257     if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
258 vapier 1.10 scanelf_dir(path);
259     }
260     free(path);
261    
262 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
263     if (!scan_ul) scanelf_dir("/usr/lib");
264     if (!scan_ull) scanelf_dir("/usr/local/lib");
265    
266 vapier 1.10 fclose(fp);
267     }
268 solar 1.1
269 vapier 1.10 /* scan env PATH for paths */
270     static void scanelf_envpath()
271 solar 1.1 {
272 vapier 1.10 char *path, *p;
273    
274     path = getenv("PATH");
275     if (!path)
276     err("PATH is not set in your env !");
277    
278     if ((path = strdup(path)) == NULL)
279     err("stdup failed: %s", strerror(errno));
280    
281     while ((p = strrchr(path, ':')) != NULL) {
282     scanelf_dir(p + 1);
283     *p = 0;
284     }
285 vapier 1.17
286 vapier 1.10 free(path);
287 solar 1.1 }
288    
289    
290 vapier 1.10
291     /* usage / invocation handling functions */
292 solar 1.16 #define PARSE_FLAGS "plRmxetraqvBhV"
293 vapier 1.10 static struct option const long_opts[] = {
294     {"path", no_argument, NULL, 'p'},
295     {"ldpath", no_argument, NULL, 'l'},
296     {"recursive", no_argument, NULL, 'R'},
297 vapier 1.14 {"mount", no_argument, NULL, 'm'},
298 vapier 1.10 {"pax", no_argument, NULL, 'x'},
299 solar 1.16 {"header", no_argument, NULL, 'e'},
300 vapier 1.10 {"textrel", no_argument, NULL, 't'},
301     {"rpath", no_argument, NULL, 'r'},
302     {"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.16 "Print all scanned info (-x -e -t -r)\n",
320 vapier 1.14 "Only output 'bad' things",
321     "Be verbose (can be specified more than once)",
322     "Don't display the header",
323 vapier 1.10 "Print this help and exit",
324     "Print version and exit",
325     NULL
326     };
327    
328     /* display usage and exit */
329     static void usage(int status)
330 solar 1.1 {
331 vapier 1.10 int i;
332     printf(" Scan ELF binaries for stuff\n\n"
333     "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
334 solar 1.12 fputs("Options:\n", stdout);
335 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
336     printf(" -%c, --%-12s %s\n", long_opts[i].val,
337     long_opts[i].name, opts_help[i]);
338 solar 1.16 #ifdef MANLYPAGE
339     for (i = 0; long_opts[i].name; ++i)
340     printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
341     long_opts[i].name, opts_help[i]);
342     #endif
343 vapier 1.10 exit(status);
344 solar 1.1 }
345    
346     /* parse command line arguments and preform needed actions */
347 vapier 1.10 static void parseargs(int argc, char *argv[])
348     {
349     int flag;
350    
351     opterr = 0;
352     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
353     switch (flag) {
354    
355     case 'V': /* version info */
356     printf("%s compiled %s\n"
357 solar 1.11 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n"
358 vapier 1.10 "%s\n",
359     __FILE__, __DATE__, argv0, rcsid);
360     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.16 case 'B': show_banner = 0; break;
366 vapier 1.10 case 'l': scan_ldpath = 1; break;
367     case 'p': scan_envpath = 1; break;
368     case 'R': dir_recurse = 1; break;
369 vapier 1.14 case 'm': dir_crossmount = 0; break;
370 vapier 1.10 case 'x': show_pax = 1; break;
371 solar 1.16 case 'e': show_stack = 1; break;
372 vapier 1.10 case 't': show_textrel = 1; break;
373     case 'r': show_rpath = 1; break;
374     case 'q': be_quiet = 1; break;
375 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
376 vapier 1.10 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
377    
378     case ':':
379     warn("Option missing parameter");
380     usage(EXIT_FAILURE);
381     break;
382     case '?':
383     warn("Unknown option");
384     usage(EXIT_FAILURE);
385     break;
386     default:
387     err("Unhandled option '%c'", flag);
388     break;
389     }
390     }
391    
392 vapier 1.14 if (be_quiet && be_verbose)
393     err("You can be quiet or you can be verbose, not both, stupid");
394    
395 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
396     if (scan_envpath) scanelf_envpath();
397     while (optind < argc)
398     scanelf_dir(argv[optind++]);
399     }
400    
401    
402    
403     int main(int argc, char *argv[])
404 solar 1.1 {
405 vapier 1.10 if (argc < 2)
406     usage(EXIT_FAILURE);
407     parseargs(argc, argv);
408     return EXIT_SUCCESS;
409 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20