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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.20 - (show annotations) (download) (as text)
Sat Apr 2 19:06:36 2005 UTC (9 years ago) by solar
Branch: MAIN
Changes since 1.19: +13 -15 lines
File MIME type: text/x-csrc
- work around problem freeing memory on uclibc systems by using a static buffer for path handling. this should also speed up the scanelf_dir function

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.19 2005/04/02 04:13: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 #include "paxelf.h"
35
36 static const char *rcsid = "$Id: scanelf.c,v 1.19 2005/04/02 04:13:36 solar Exp $";
37
38
39 /* helper functions for showing errors */
40 #define argv0 "scanelf" /*((*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 buf[PATH_MAX];
194 size_t 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 assert(len < sizeof(buf));
218 strncpy(buf, path, len);
219 strncat(buf, "/", len);
220 strncat(buf, dentry->d_name, len);
221 buf[sizeof(buf)] = 0;
222 if (lstat(buf, &st) != -1) {
223 if (S_ISREG(st.st_mode))
224 scanelf_file(buf);
225 else if (dir_recurse && S_ISDIR(st.st_mode)) {
226 if (dir_crossmount || (st_top.st_dev == st.st_dev))
227 scanelf_dir(buf);
228 }
229 }
230 }
231 closedir(dir);
232 }
233
234 /* scan /etc/ld.so.conf for paths */
235 static void scanelf_ldpath()
236 {
237 char scan_l, scan_ul, scan_ull;
238 char *path, *p;
239 FILE *fp;
240
241 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
242 err("Unable to open ld.so.conf: %s", strerror(errno));
243
244 scan_l = scan_ul = scan_ull = 0;
245
246 path = malloc(_POSIX_PATH_MAX);
247 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
248 if (*path == '/') {
249 if ((p = strrchr(path, '\r')) != NULL)
250 *p = 0;
251 if ((p = strrchr(path, '\n')) != NULL)
252 *p = 0;
253 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
254 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
255 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
256 scanelf_dir(path);
257 }
258 free(path);
259
260 if (!scan_l) scanelf_dir("/lib");
261 if (!scan_ul) scanelf_dir("/usr/lib");
262 if (!scan_ull) scanelf_dir("/usr/local/lib");
263
264 fclose(fp);
265 }
266
267 /* scan env PATH for paths */
268 static void scanelf_envpath()
269 {
270 char *path, *p;
271
272 path = getenv("PATH");
273 if (!path)
274 err("PATH is not set in your env !");
275
276 if ((path = strdup(path)) == NULL)
277 err("stdup failed: %s", strerror(errno));
278
279 while ((p = strrchr(path, ':')) != NULL) {
280 scanelf_dir(p + 1);
281 *p = 0;
282 }
283
284 free(path);
285 }
286
287
288
289 /* usage / invocation handling functions */
290 #define PARSE_FLAGS "plRmxetraqvBhV"
291 static struct option const long_opts[] = {
292 {"path", no_argument, NULL, 'p'},
293 {"ldpath", no_argument, NULL, 'l'},
294 {"recursive", no_argument, NULL, 'R'},
295 {"mount", no_argument, NULL, 'm'},
296 {"pax", no_argument, NULL, 'x'},
297 {"header", no_argument, NULL, 'e'},
298 {"textrel", no_argument, NULL, 't'},
299 {"rpath", no_argument, NULL, 'r'},
300 {"all", no_argument, NULL, 'a'},
301 {"quiet", no_argument, NULL, 'q'},
302 {"verbose", no_argument, NULL, 'v'},
303 {"nobanner", no_argument, NULL, 'B'},
304 {"help", no_argument, NULL, 'h'},
305 {"version", no_argument, NULL, 'V'},
306 {NULL, no_argument, NULL, 0x0}
307 };
308 static char *opts_help[] = {
309 "Scan all directories in PATH environment",
310 "Scan all directories in /etc/ld.so.conf",
311 "Scan directories recursively",
312 "Don't recursively cross mount points\n",
313 "Print PaX markings",
314 "Print GNU_STACK markings",
315 "Print TEXTREL information",
316 "Print RPATH information",
317 "Print all scanned info (-x -e -t -r)\n",
318 "Only output 'bad' things",
319 "Be verbose (can be specified more than once)",
320 "Don't display the header",
321 "Print this help and exit",
322 "Print version and exit",
323 NULL
324 };
325
326 /* display usage and exit */
327 static void usage(int status)
328 {
329 int i;
330 printf(" Scan ELF binaries for stuff\n\n"
331 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0);
332 fputs("Options:\n", stdout);
333 for (i = 0; long_opts[i].name; ++i)
334 printf(" -%c, --%-12s %s\n", long_opts[i].val,
335 long_opts[i].name, opts_help[i]);
336 #ifdef MANLYPAGE
337 for (i = 0; long_opts[i].name; ++i)
338 printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
339 long_opts[i].name, opts_help[i]);
340 #endif
341 exit(status);
342 }
343
344 /* parse command line arguments and preform needed actions */
345 static void parseargs(int argc, char *argv[])
346 {
347 int flag;
348
349 opterr = 0;
350 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
351 switch (flag) {
352
353 case 'V': /* version info */
354 printf("%s compiled %s\n%s\n"
355 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
356 __FILE__, __DATE__, rcsid, argv0);
357 exit(EXIT_SUCCESS);
358 break;
359 case 's': /* reserved for -s, --symbol= */
360 case 'h': usage(EXIT_SUCCESS); break;
361
362 case 'B': show_banner = 0; break;
363 case 'l': scan_ldpath = 1; break;
364 case 'p': scan_envpath = 1; break;
365 case 'R': dir_recurse = 1; break;
366 case 'm': dir_crossmount = 0; break;
367 case 'x': show_pax = 1; break;
368 case 'e': show_stack = 1; break;
369 case 't': show_textrel = 1; break;
370 case 'r': show_rpath = 1; break;
371 case 'q': be_quiet = 1; break;
372 case 'v': be_verbose = (be_verbose % 20) + 1; break;
373 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break;
374
375 case ':':
376 warn("Option missing parameter");
377 usage(EXIT_FAILURE);
378 break;
379 case '?':
380 warn("Unknown option");
381 usage(EXIT_FAILURE);
382 break;
383 default:
384 err("Unhandled option '%c'", flag);
385 break;
386 }
387 }
388
389 if (be_quiet && be_verbose)
390 err("You can be quiet or you can be verbose, not both, stupid");
391
392 if (scan_ldpath) scanelf_ldpath();
393 if (scan_envpath) scanelf_envpath();
394 while (optind < argc)
395 scanelf_dir(argv[optind++]);
396 }
397
398
399
400 int main(int argc, char *argv[])
401 {
402 if (argc < 2)
403 usage(EXIT_FAILURE);
404 parseargs(argc, argv);
405 return EXIT_SUCCESS;
406 }

  ViewVC Help
Powered by ViewVC 1.1.20