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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (show annotations) (download) (as text)
Fri Apr 1 20:44:11 2005 UTC (9 years, 3 months ago) by solar
Branch: MAIN
Changes since 1.15: +17 -11 lines
File MIME type: text/x-csrc
- updated manpage again, rename -s/--stack to -e/--header and rename -H/--noheader to -B/--nobanner

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.15 2005/04/01 20:08:44 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
34 #include "paxelf.h"
35
36 static const char *rcsid = "$Id: scanelf.c,v 1.15 2005/04/01 20:08:44 vapier Exp $";
37
38
39 /* helper functions for showing errors */
40 #define argv0 "scanelf\0" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
41 #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 static char dir_crossmount = 1;
65 static char show_pax = 0;
66 static char show_stack = 0;
67 static char show_textrel = 0;
68 static char show_rpath = 0;
69 static char show_banner = 1;
70 static char be_quiet = 0;
71 static char be_verbose = 0;
72
73
74
75 /* scan an elf file and show all the fun stuff */
76 static void scanelf_file(const char *filename)
77 {
78 int i;
79 char found_pax, found_stack, found_relro, found_textrel, found_rpath;
80 Elf_Dyn *dyn;
81 elfobj *elf = NULL;
82
83 found_pax = found_stack = found_relro = found_textrel = found_rpath = 0;
84
85 /* verify this is real ELF */
86 if ((elf = readelf(filename)) == NULL) {
87 if (be_verbose > 1) printf("%s: not an ELF\n", filename);
88 return;
89 }
90 if (check_elf_header(elf->ehdr) || !IS_ELF(elf)) {
91 if (be_verbose > 1) printf("%s: cannot handle ELF :(\n", filename);
92 goto bail;
93 }
94
95 if (be_verbose) printf("%s: scanning file\n", filename);
96
97 /* show the header */
98 if (!be_quiet && show_banner) {
99 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 show_banner = 0;
106 }
107
108 /* dump all the good stuff */
109 if (!be_quiet)
110 printf("%-7s ", get_elfetype(elf->ehdr->e_type));
111
112 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
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 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 printf("%s ", gnu_short_stack_flags(elf->phdr[i].p_flags));
135 }
136 if (!be_quiet && !found_stack) fputs("--- ", stdout);
137 if (!be_quiet && !found_relro) fputs("--- ", stdout);
138 }
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 fputs("TEXTREL ", stdout);
151 }
152 ++dyn;
153 }
154 }
155 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
156 }
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 if (!be_quiet && !found_rpath) fputs(" - ", stdout);
178 }
179
180 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath)
181 puts(filename);
182
183 bail:
184 unreadelf(elf);
185 }
186
187 /* scan a directory for ET_EXEC files and print when we find one */
188 static void scanelf_dir(const char *path)
189 {
190 register DIR *dir;
191 register struct dirent *dentry;
192 struct stat st_top, st;
193 char *p;
194 int len = 0;
195
196 /* make sure path exists */
197 if (lstat(path, &st_top) == -1)
198 return;
199
200 /* ok, if it isn't a directory, assume we can open it */
201 if (!S_ISDIR(st_top.st_mode)) {
202 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 if (be_verbose) printf("%s: scanning dir\n", path);
212
213 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 if (dir_crossmount || (st_top.st_dev == st.st_dev))
228 scanelf_dir(p);
229 }
230 }
231 free(p);
232 }
233 closedir(dir);
234 }
235
236 /* scan /etc/ld.so.conf for paths */
237 static void scanelf_ldpath()
238 {
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 path = malloc(_POSIX_PATH_MAX);
246 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
247 if (*path == '/') {
248 if ((p = strrchr(path, '\r')) != NULL)
249 *p = 0;
250 if ((p = strrchr(path, '\n')) != NULL)
251 *p = 0;
252 scanelf_dir(path);
253 }
254 free(path);
255
256 fclose(fp);
257 }
258
259 /* scan env PATH for paths */
260 static void scanelf_envpath()
261 {
262 char *path, *p;
263
264 path = getenv("PATH");
265 if (!path)
266 err("PATH is not set in your env !");
267
268 if ((path = strdup(path)) == NULL)
269 err("stdup failed: %s", strerror(errno));
270
271 while ((p = strrchr(path, ':')) != NULL) {
272 scanelf_dir(p + 1);
273 *p = 0;
274 }
275 free(path);
276 }
277
278
279
280 /* usage / invocation handling functions */
281 #define PARSE_FLAGS "plRmxetraqvBhV"
282 static struct option const long_opts[] = {
283 {"path", no_argument, NULL, 'p'},
284 {"ldpath", no_argument, NULL, 'l'},
285 {"recursive", no_argument, NULL, 'R'},
286 {"mount", no_argument, NULL, 'm'},
287 {"pax", no_argument, NULL, 'x'},
288 {"header", no_argument, NULL, 'e'},
289 {"textrel", no_argument, NULL, 't'},
290 {"rpath", no_argument, NULL, 'r'},
291 {"all", no_argument, NULL, 'a'},
292 {"quiet", no_argument, NULL, 'q'},
293 {"verbose", no_argument, NULL, 'v'},
294 {"nobanner", no_argument, NULL, 'B'},
295 {"help", no_argument, NULL, 'h'},
296 {"version", no_argument, NULL, 'V'},
297 {NULL, no_argument, NULL, 0x0}
298 };
299 static char *opts_help[] = {
300 "Scan all directories in PATH environment",
301 "Scan all directories in /etc/ld.so.conf",
302 "Scan directories recursively",
303 "Don't recursively cross mount points\n",
304 "Print PaX markings",
305 "Print GNU_STACK markings",
306 "Print TEXTREL information",
307 "Print RPATH information",
308 "Print all scanned info (-x -e -t -r)\n",
309 "Only output 'bad' things",
310 "Be verbose (can be specified more than once)",
311 "Don't display the header",
312 "Print this help and exit",
313 "Print version and exit",
314 NULL
315 };
316
317 /* display usage and exit */
318 static void usage(int status)
319 {
320 int i;
321 printf(" Scan ELF binaries for stuff\n\n"
322 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
323 fputs("Options:\n", stdout);
324 for (i = 0; long_opts[i].name; ++i)
325 printf(" -%c, --%-12s %s\n", long_opts[i].val,
326 long_opts[i].name, opts_help[i]);
327 #ifdef MANLYPAGE
328 for (i = 0; long_opts[i].name; ++i)
329 printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
330 long_opts[i].name, opts_help[i]);
331 #endif
332 exit(status);
333 }
334
335 /* parse command line arguments and preform needed actions */
336 static void parseargs(int argc, char *argv[])
337 {
338 int flag;
339
340 opterr = 0;
341 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
342 switch (flag) {
343
344 case 'V': /* version info */
345 printf("%s compiled %s\n"
346 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n"
347 "%s\n",
348 __FILE__, __DATE__, argv0, rcsid);
349 exit(EXIT_SUCCESS);
350 break;
351 case 's': /* reserved for -s, --symbol= */
352 case 'h': usage(EXIT_SUCCESS); break;
353
354 case 'B': show_banner = 0; break;
355 case 'l': scan_ldpath = 1; break;
356 case 'p': scan_envpath = 1; break;
357 case 'R': dir_recurse = 1; break;
358 case 'm': dir_crossmount = 0; break;
359 case 'x': show_pax = 1; break;
360 case 'e': show_stack = 1; break;
361 case 't': show_textrel = 1; break;
362 case 'r': show_rpath = 1; break;
363 case 'q': be_quiet = 1; break;
364 case 'v': be_verbose = (be_verbose % 20) + 1; break;
365 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
366
367 case ':':
368 warn("Option missing parameter");
369 usage(EXIT_FAILURE);
370 break;
371 case '?':
372 warn("Unknown option");
373 usage(EXIT_FAILURE);
374 break;
375 default:
376 err("Unhandled option '%c'", flag);
377 break;
378 }
379 }
380
381 if (be_quiet && be_verbose)
382 err("You can be quiet or you can be verbose, not both, stupid");
383
384 if (scan_ldpath) scanelf_ldpath();
385 if (scan_envpath) scanelf_envpath();
386 while (optind < argc)
387 scanelf_dir(argv[optind++]);
388 }
389
390
391
392 int main(int argc, char *argv[])
393 {
394 if (argc < 2)
395 usage(EXIT_FAILURE);
396 parseargs(argc, argv);
397 return EXIT_SUCCESS;
398 }

  ViewVC Help
Powered by ViewVC 1.1.20