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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.20 - (hide annotations) (download) (as text)
Sat Apr 2 19:06:36 2005 UTC (9 years, 5 months ago) by solar
Branch: MAIN
Changes since 1.19: +13 -15 lines
File MIME type: text/x-csrc
- work around problem freeing memory on uclibc systems by using a static buffer for path handling. this should also speed up the scanelf_dir function

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.20 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.19 2005/04/02 04:13:36 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.1 #include "paxelf.h"
35    
36 solar 1.20 static const char *rcsid = "$Id: scanelf.c,v 1.19 2005/04/02 04:13:36 solar 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 solar 1.20 char buf[PATH_MAX];
194     size_t len = 0;
195 vapier 1.10
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 solar 1.20 assert(len < sizeof(buf));
218     strncpy(buf, path, len);
219     strncat(buf, "/", len);
220     strncat(buf, dentry->d_name, len);
221     buf[sizeof(buf)] = 0;
222     if (lstat(buf, &st) != -1) {
223 vapier 1.10 if (S_ISREG(st.st_mode))
224 solar 1.20 scanelf_file(buf);
225 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
226 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
227 solar 1.20 scanelf_dir(buf);
228 vapier 1.10 }
229     }
230     }
231     closedir(dir);
232 solar 1.1 }
233    
234 vapier 1.10 /* scan /etc/ld.so.conf for paths */
235     static void scanelf_ldpath()
236     {
237 vapier 1.17 char scan_l, scan_ul, scan_ull;
238 vapier 1.10 char *path, *p;
239     FILE *fp;
240    
241     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
242     err("Unable to open ld.so.conf: %s", strerror(errno));
243    
244 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
245    
246 vapier 1.10 path = malloc(_POSIX_PATH_MAX);
247     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
248     if (*path == '/') {
249     if ((p = strrchr(path, '\r')) != NULL)
250     *p = 0;
251     if ((p = strrchr(path, '\n')) != NULL)
252     *p = 0;
253 vapier 1.17 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
254     if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
255     if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
256 vapier 1.10 scanelf_dir(path);
257     }
258     free(path);
259    
260 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
261     if (!scan_ul) scanelf_dir("/usr/lib");
262     if (!scan_ull) scanelf_dir("/usr/local/lib");
263    
264 vapier 1.10 fclose(fp);
265     }
266 solar 1.1
267 vapier 1.10 /* scan env PATH for paths */
268     static void scanelf_envpath()
269 solar 1.1 {
270 vapier 1.10 char *path, *p;
271    
272     path = getenv("PATH");
273     if (!path)
274     err("PATH is not set in your env !");
275    
276     if ((path = strdup(path)) == NULL)
277     err("stdup failed: %s", strerror(errno));
278    
279     while ((p = strrchr(path, ':')) != NULL) {
280     scanelf_dir(p + 1);
281     *p = 0;
282     }
283 vapier 1.17
284 vapier 1.10 free(path);
285 solar 1.1 }
286    
287    
288 vapier 1.10
289     /* usage / invocation handling functions */
290 solar 1.16 #define PARSE_FLAGS "plRmxetraqvBhV"
291 vapier 1.10 static struct option const long_opts[] = {
292     {"path", no_argument, NULL, 'p'},
293     {"ldpath", no_argument, NULL, 'l'},
294     {"recursive", no_argument, NULL, 'R'},
295 vapier 1.14 {"mount", no_argument, NULL, 'm'},
296 vapier 1.10 {"pax", no_argument, NULL, 'x'},
297 solar 1.16 {"header", no_argument, NULL, 'e'},
298 vapier 1.10 {"textrel", no_argument, NULL, 't'},
299     {"rpath", no_argument, NULL, 'r'},
300     {"all", no_argument, NULL, 'a'},
301     {"quiet", no_argument, NULL, 'q'},
302 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
303 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
304 vapier 1.10 {"help", no_argument, NULL, 'h'},
305     {"version", no_argument, NULL, 'V'},
306     {NULL, no_argument, NULL, 0x0}
307     };
308     static char *opts_help[] = {
309     "Scan all directories in PATH environment",
310     "Scan all directories in /etc/ld.so.conf",
311 vapier 1.14 "Scan directories recursively",
312     "Don't recursively cross mount points\n",
313 vapier 1.10 "Print PaX markings",
314     "Print GNU_STACK markings",
315     "Print TEXTREL information",
316     "Print RPATH information",
317 solar 1.16 "Print all scanned info (-x -e -t -r)\n",
318 vapier 1.14 "Only output 'bad' things",
319     "Be verbose (can be specified more than once)",
320     "Don't display the header",
321 vapier 1.10 "Print this help and exit",
322     "Print version and exit",
323     NULL
324     };
325    
326     /* display usage and exit */
327     static void usage(int status)
328 solar 1.1 {
329 vapier 1.10 int i;
330     printf(" Scan ELF binaries for stuff\n\n"
331     "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
332 solar 1.12 fputs("Options:\n", stdout);
333 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
334     printf(" -%c, --%-12s %s\n", long_opts[i].val,
335     long_opts[i].name, opts_help[i]);
336 solar 1.16 #ifdef MANLYPAGE
337     for (i = 0; long_opts[i].name; ++i)
338     printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
339     long_opts[i].name, opts_help[i]);
340     #endif
341 vapier 1.10 exit(status);
342 solar 1.1 }
343    
344     /* parse command line arguments and preform needed actions */
345 vapier 1.10 static void parseargs(int argc, char *argv[])
346     {
347     int flag;
348    
349     opterr = 0;
350     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
351     switch (flag) {
352    
353     case 'V': /* version info */
354 solar 1.19 printf("%s compiled %s\n%s\n"
355     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
356     __FILE__, __DATE__, rcsid, argv0);
357 vapier 1.10 exit(EXIT_SUCCESS);
358     break;
359 solar 1.16 case 's': /* reserved for -s, --symbol= */
360 vapier 1.10 case 'h': usage(EXIT_SUCCESS); break;
361    
362 solar 1.16 case 'B': show_banner = 0; break;
363 vapier 1.10 case 'l': scan_ldpath = 1; break;
364     case 'p': scan_envpath = 1; break;
365     case 'R': dir_recurse = 1; break;
366 vapier 1.14 case 'm': dir_crossmount = 0; break;
367 vapier 1.10 case 'x': show_pax = 1; break;
368 solar 1.16 case 'e': show_stack = 1; break;
369 vapier 1.10 case 't': show_textrel = 1; break;
370     case 'r': show_rpath = 1; break;
371     case 'q': be_quiet = 1; break;
372 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
373 vapier 1.10 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
374    
375     case ':':
376     warn("Option missing parameter");
377     usage(EXIT_FAILURE);
378     break;
379     case '?':
380     warn("Unknown option");
381     usage(EXIT_FAILURE);
382     break;
383     default:
384     err("Unhandled option '%c'", flag);
385     break;
386     }
387     }
388    
389 vapier 1.14 if (be_quiet && be_verbose)
390     err("You can be quiet or you can be verbose, not both, stupid");
391    
392 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
393     if (scan_envpath) scanelf_envpath();
394     while (optind < argc)
395     scanelf_dir(argv[optind++]);
396     }
397    
398    
399    
400     int main(int argc, char *argv[])
401 solar 1.1 {
402 vapier 1.10 if (argc < 2)
403     usage(EXIT_FAILURE);
404     parseargs(argc, argv);
405     return EXIT_SUCCESS;
406 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20