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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (show annotations) (download) (as text)
Sat Apr 2 00:11:01 2005 UTC (9 years, 3 months ago) by vapier
Branch: MAIN
Changes since 1.16: +13 -2 lines
File MIME type: text/x-csrc
make sure scanelf_ldpath scans /lib /usr/lib /usr/local/lib even if it isnt in ld.so.conf

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

  ViewVC Help
Powered by ViewVC 1.1.20