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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.21 - (show annotations) (download) (as text)
Sun Apr 3 16:02:25 2005 UTC (9 years ago) by solar
Branch: MAIN
Changes since 1.20: +19 -4 lines
File MIME type: text/x-csrc
- added -o --file= option for redirecting stdout, use _POSIX_PATH_MAX vs PATH_MAX to mimic what is used elsewhere within the code.

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

  ViewVC Help
Powered by ViewVC 1.1.20