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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (show annotations) (download) (as text)
Fri Apr 1 20:08:44 2005 UTC (9 years, 4 months ago) by vapier
Branch: MAIN
Changes since 1.14: +6 -6 lines
File MIME type: text/x-csrc
make output with verbose easier to parse

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.14 2005/04/01 19:56:34 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.14 2005/04/01 19:56:34 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_header = 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_header) {
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_header = 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 "plRmxstraqvHhV"
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 {"stack", no_argument, NULL, 's'},
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 {"noheader", no_argument, NULL, 'H'},
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 -s -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 exit(status);
328 }
329
330 /* parse command line arguments and preform needed actions */
331 static void parseargs(int argc, char *argv[])
332 {
333 int flag;
334
335 opterr = 0;
336 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
337 switch (flag) {
338
339 case 'V': /* version info */
340 printf("%s compiled %s\n"
341 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n"
342 "%s\n",
343 __FILE__, __DATE__, argv0, rcsid);
344 exit(EXIT_SUCCESS);
345 break;
346 case 'h': usage(EXIT_SUCCESS); break;
347
348 case 'H': show_header = 0; break;
349 case 'l': scan_ldpath = 1; break;
350 case 'p': scan_envpath = 1; break;
351 case 'R': dir_recurse = 1; break;
352 case 'm': dir_crossmount = 0; break;
353 case 'x': show_pax = 1; break;
354 case 's': show_stack = 1; break;
355 case 't': show_textrel = 1; break;
356 case 'r': show_rpath = 1; break;
357 case 'q': be_quiet = 1; break;
358 case 'v': be_verbose = (be_verbose % 20) + 1; break;
359 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
360
361 case ':':
362 warn("Option missing parameter");
363 usage(EXIT_FAILURE);
364 break;
365 case '?':
366 warn("Unknown option");
367 usage(EXIT_FAILURE);
368 break;
369 default:
370 err("Unhandled option '%c'", flag);
371 break;
372 }
373 }
374
375 if (be_quiet && be_verbose)
376 err("You can be quiet or you can be verbose, not both, stupid");
377
378 if (scan_ldpath) scanelf_ldpath();
379 if (scan_envpath) scanelf_envpath();
380 while (optind < argc)
381 scanelf_dir(argv[optind++]);
382 }
383
384
385
386 int main(int argc, char *argv[])
387 {
388 if (argc < 2)
389 usage(EXIT_FAILURE);
390 parseargs(argc, argv);
391 return EXIT_SUCCESS;
392 }

  ViewVC Help
Powered by ViewVC 1.1.20