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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.22 - (show annotations) (download) (as text)
Sun Apr 3 18:03:22 2005 UTC (9 years, 6 months 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 /*
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.21 2005/04/03 16:02:25 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.21 2005/04/03 16:02:25 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
92 if (be_verbose) printf("%s: scanning file\n", filename);
93
94 /* show the header */
95 if (!be_quiet && show_banner) {
96 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 show_banner = 0;
103 }
104
105 /* dump all the good stuff */
106 if (!be_quiet)
107 printf("%-7s ", get_elfetype(elf->ehdr->e_type));
108
109 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
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 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 printf("%s ", gnu_short_stack_flags(elf->phdr[i].p_flags));
132 }
133 if (!be_quiet && !found_stack) fputs("--- ", stdout);
134 if (!be_quiet && !found_relro) fputs("--- ", stdout);
135 }
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 fputs("TEXTREL ", stdout);
148 }
149 ++dyn;
150 }
151 }
152 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
153 }
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 if (!be_quiet && !found_rpath) fputs(" - ", stdout);
175 }
176
177 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath)
178 puts(filename);
179
180 unreadelf(elf);
181 }
182
183 /* scan a directory for ET_EXEC files and print when we find one */
184 static void scanelf_dir(const char *path)
185 {
186 register DIR *dir;
187 register struct dirent *dentry;
188 struct stat st_top, st;
189 char buf[_POSIX_PATH_MAX];
190 size_t len = 0;
191
192 /* make sure path exists */
193 if (lstat(path, &st_top) == -1)
194 return;
195
196 /* ok, if it isn't a directory, assume we can open it */
197 if (!S_ISDIR(st_top.st_mode)) {
198 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 if (be_verbose) printf("%s: scanning dir\n", path);
208
209 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 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 if (S_ISREG(st.st_mode))
220 scanelf_file(buf);
221 else if (dir_recurse && S_ISDIR(st.st_mode)) {
222 if (dir_crossmount || (st_top.st_dev == st.st_dev))
223 scanelf_dir(buf);
224 }
225 }
226 }
227 closedir(dir);
228 }
229
230 /* scan /etc/ld.so.conf for paths */
231 static void scanelf_ldpath()
232 {
233 char scan_l, scan_ul, scan_ull;
234 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 scan_l = scan_ul = scan_ull = 0;
241
242 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 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 scanelf_dir(path);
253 }
254 free(path);
255
256 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 fclose(fp);
261 }
262
263 /* scan env PATH for paths */
264 static void scanelf_envpath()
265 {
266 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
280 free(path);
281 }
282
283
284
285 /* usage / invocation handling functions */
286 #define PARSE_FLAGS "plRmxetro:aqvBhV"
287 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 {"mount", no_argument, NULL, 'm'},
292 {"pax", no_argument, NULL, 'x'},
293 {"header", no_argument, NULL, 'e'},
294 {"textrel", no_argument, NULL, 't'},
295 {"rpath", no_argument, NULL, 'r'},
296 {"file",required_argument, NULL, 'o'},
297 {"all", no_argument, NULL, 'a'},
298 {"quiet", no_argument, NULL, 'q'},
299 {"verbose", no_argument, NULL, 'v'},
300 {"nobanner", no_argument, NULL, 'B'},
301 {"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 "Scan directories recursively",
309 "Don't recursively cross mount points\n",
310 "Print PaX markings",
311 "Print GNU_STACK markings",
312 "Print TEXTREL information",
313 "Print RPATH information",
314 "Write output stream to a filename",
315 "Print all scanned info (-x -e -t -r)\n",
316 "Only output 'bad' things",
317 "Be verbose (can be specified more than once)",
318 "Don't display the header",
319 "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 {
327 int i;
328 printf(" Scan ELF binaries for stuff\n\n"
329 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
330 fputs("Options:\n", stdout);
331 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 #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 exit(status);
340 }
341
342 /* parse command line arguments and preform needed actions */
343 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 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 exit(EXIT_SUCCESS);
356 break;
357 case 's': /* reserved for -s, --symbol= */
358 case 'h': usage(EXIT_SUCCESS); break;
359
360 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 case 'B': show_banner = 0; break;
372 case 'l': scan_ldpath = 1; break;
373 case 'p': scan_envpath = 1; break;
374 case 'R': dir_recurse = 1; break;
375 case 'm': dir_crossmount = 0; break;
376 case 'x': show_pax = 1; break;
377 case 'e': show_stack = 1; break;
378 case 't': show_textrel = 1; break;
379 case 'r': show_rpath = 1; break;
380 case 'q': be_quiet = 1; break;
381 case 'v': be_verbose = (be_verbose % 20) + 1; break;
382 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 if (be_quiet && be_verbose)
399 err("You can be quiet or you can be verbose, not both, stupid");
400
401 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 {
411 if (argc < 2)
412 usage(EXIT_FAILURE);
413 parseargs(argc, argv);
414 fclose(stdout);
415 return EXIT_SUCCESS;
416 }

  ViewVC Help
Powered by ViewVC 1.1.20