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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (show annotations) (download) (as text)
Sun Apr 3 18:27:45 2005 UTC (9 years, 8 months 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 /*
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.22 2005/04/03 18:03:22 vapier 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.22 2005/04/03 18:03:22 vapier 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 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 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) printf("--- ");
134 if (!be_quiet && !found_relro) printf("--- ");
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 printf("TEXTREL ");
148 }
149 ++dyn;
150 }
151 }
152 if (!be_quiet && !found_textrel) printf("------- ");
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 char *rpath, *runpath;
159 Elf_Shdr *strtbl = elf_findsecbyname(elf, ".dynstr");
160 rpath = runpath = NULL;
161
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 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 found_rpath = 1;
174 }
175 ++dyn;
176 }
177 }
178 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 }
190
191 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath)
192 puts(filename);
193
194 unreadelf(elf);
195 }
196
197 /* scan a directory for ET_EXEC files and print when we find one */
198 static void scanelf_dir(const char *path)
199 {
200 register DIR *dir;
201 register struct dirent *dentry;
202 struct stat st_top, st;
203 char buf[_POSIX_PATH_MAX];
204 size_t len = 0;
205
206 /* make sure path exists */
207 if (lstat(path, &st_top) == -1)
208 return;
209
210 /* ok, if it isn't a directory, assume we can open it */
211 if (!S_ISDIR(st_top.st_mode)) {
212 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 if (be_verbose) printf("%s: scanning dir\n", path);
222
223 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 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 if (S_ISREG(st.st_mode))
234 scanelf_file(buf);
235 else if (dir_recurse && S_ISDIR(st.st_mode)) {
236 if (dir_crossmount || (st_top.st_dev == st.st_dev))
237 scanelf_dir(buf);
238 }
239 }
240 }
241 closedir(dir);
242 }
243
244 /* scan /etc/ld.so.conf for paths */
245 static void scanelf_ldpath()
246 {
247 char scan_l, scan_ul, scan_ull;
248 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 scan_l = scan_ul = scan_ull = 0;
255
256 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 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 scanelf_dir(path);
267 }
268 free(path);
269
270 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 fclose(fp);
275 }
276
277 /* scan env PATH for paths */
278 static void scanelf_envpath()
279 {
280 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
294 free(path);
295 }
296
297
298
299 /* usage / invocation handling functions */
300 #define PARSE_FLAGS "plRmxetro:aqvBhV"
301 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 {"mount", no_argument, NULL, 'm'},
306 {"pax", no_argument, NULL, 'x'},
307 {"header", no_argument, NULL, 'e'},
308 {"textrel", no_argument, NULL, 't'},
309 {"rpath", no_argument, NULL, 'r'},
310 {"file",required_argument, NULL, 'o'},
311 {"all", no_argument, NULL, 'a'},
312 {"quiet", no_argument, NULL, 'q'},
313 {"verbose", no_argument, NULL, 'v'},
314 {"nobanner", no_argument, NULL, 'B'},
315 {"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 "Scan directories recursively",
323 "Don't recursively cross mount points\n",
324 "Print PaX markings",
325 "Print GNU_STACK markings",
326 "Print TEXTREL information",
327 "Print RPATH information",
328 "Write output stream to a filename",
329 "Print all scanned info (-x -e -t -r)\n",
330 "Only output 'bad' things",
331 "Be verbose (can be specified more than once)",
332 "Don't display the header",
333 "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 {
341 int i;
342 printf(" Scan ELF binaries for stuff\n\n"
343 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
344 printf("Options:\n");
345 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 #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 exit(status);
354 }
355
356 /* parse command line arguments and preform needed actions */
357 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 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 exit(EXIT_SUCCESS);
370 break;
371 case 's': /* reserved for -s, --symbol= */
372 case 'h': usage(EXIT_SUCCESS); break;
373
374 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 case 'B': show_banner = 0; break;
386 case 'l': scan_ldpath = 1; break;
387 case 'p': scan_envpath = 1; break;
388 case 'R': dir_recurse = 1; break;
389 case 'm': dir_crossmount = 0; break;
390 case 'x': show_pax = 1; break;
391 case 'e': show_stack = 1; break;
392 case 't': show_textrel = 1; break;
393 case 'r': show_rpath = 1; break;
394 case 'q': be_quiet = 1; break;
395 case 'v': be_verbose = (be_verbose % 20) + 1; break;
396 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 if (be_quiet && be_verbose)
413 err("You can be quiet or you can be verbose, not both, stupid");
414
415 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 {
425 if (argc < 2)
426 usage(EXIT_FAILURE);
427 parseargs(argc, argv);
428 fclose(stdout);
429 return EXIT_SUCCESS;
430 }

  ViewVC Help
Powered by ViewVC 1.1.20