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

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.14 Revision 1.43
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org> 2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 3 * Copyright 1999-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 4 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.14 2005/04/01 19:56:34 vapier Exp $ 5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $
6 * 6 *
7 ******************************************************************** 7 ********************************************************************
8 * This program is free software; you can redistribute it and/or 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 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 10 * published by the Free Software Foundation; either version 2 of the
22 */ 22 */
23 23
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <sys/types.h> 26#include <sys/types.h>
27#define __USE_GNU
27#include <string.h> 28#include <string.h>
28#include <errno.h> 29#include <errno.h>
29#include <unistd.h> 30#include <unistd.h>
30#include <sys/stat.h> 31#include <sys/stat.h>
31#include <dirent.h> 32#include <dirent.h>
32#include <getopt.h> 33#include <getopt.h>
34#include <assert.h>
33 35
34#include "paxelf.h" 36#include "paxelf.h"
35 37
36static const char *rcsid = "$Id: scanelf.c,v 1.14 2005/04/01 19:56:34 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $";
37 39#define argv0 "scanelf"
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 40
50 41
51 42
52/* prototypes */ 43/* prototypes */
53static void scanelf_file(const char *filename); 44static void scanelf_file(const char *filename);
54static void scanelf_dir(const char *path); 45static void scanelf_dir(const char *path);
55static void scanelf_ldpath(); 46static void scanelf_ldpath();
56static void scanelf_envpath(); 47static void scanelf_envpath();
57static void usage(int status); 48static void usage(int status);
58static void parseargs(int argc, char *argv[]); 49static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s);
51static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
59 55
60/* variables to control behavior */ 56/* variables to control behavior */
61static char scan_ldpath = 0; 57static char scan_ldpath = 0;
62static char scan_envpath = 0; 58static char scan_envpath = 0;
59static char scan_symlink = 1;
63static char dir_recurse = 0; 60static char dir_recurse = 0;
64static char dir_crossmount = 1; 61static char dir_crossmount = 1;
65static char show_pax = 0; 62static char show_pax = 0;
66static char show_stack = 0; 63static char show_stack = 0;
67static char show_textrel = 0; 64static char show_textrel = 0;
68static char show_rpath = 0; 65static char show_rpath = 0;
66static char show_needed = 0;
67static char show_interp = 0;
69static char show_header = 1; 68static char show_banner = 1;
70static char be_quiet = 0; 69static char be_quiet = 0;
71static char be_verbose = 0; 70static char be_verbose = 0;
71static char *find_sym = NULL, *versioned_symname = NULL;
72static char *out_format = NULL;
72 73
73 74
74 75
76/* sub-funcs for scanelf_file() */
77static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{
79 static char *paxflags;
80
81 if (!show_pax) return NULL;
82
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85 *found_pax = 1;
86 return paxflags;
87 }
88
89 return NULL;
90}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{
93 static char ret[8];
94 char *found;
95 int i, off, shown;
96
97 if (!show_stack) return NULL;
98
99 shown = 0;
100 strcpy(ret, "--- ---");
101#define SHOW_STACK(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
107 found = found_stack; \
108 off = 0; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
110 found = found_relro; \
111 off = 3; \
112 } else \
113 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
115 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
117 *found = 1; \
118 ++shown; \
119 } \
120 }
121 SHOW_STACK(32)
122 SHOW_STACK(64)
123 if (be_quiet && !shown)
124 return NULL;
125 else
126 return ret;
127}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{
130 static char *ret = "TEXTREL";
131 int i;
132
133 if (!show_textrel) return NULL;
134
135#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \
148 } \
149 ++dyn; \
150 } \
151 } }
152 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64)
154 if (be_quiet)
155 return NULL;
156 else
157 return " - ";
158}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
162 int i;
163 char *rpath, *runpath;
164 void *strtbl_void;
165
166 if (!show_rpath) return;
167
168 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL;
170
171 if (strtbl_void) {
172#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
185 *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \
191 ++dyn; \
192 } \
193 } }
194 SHOW_RPATH(32)
195 SHOW_RPATH(64)
196 }
197
198 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len);
201 } else {
202 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
203 xchrcat(ret, '{', ret_len);
204 xstrcat(ret, rpath, ret_len);
205 xchrcat(ret, ',', ret_len);
206 xstrcat(ret, runpath, ret_len);
207 xchrcat(ret, '}', ret_len);
208 }
209 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len);
213}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
215{
216 int i;
217 char *needed;
218 void *strtbl_void;
219
220 if (!show_needed) return;
221
222 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223
224 if (strtbl_void) {
225#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \
239 *found_needed = 1; \
240 } \
241 ++dyn; \
242 } \
243 } }
244 SHOW_NEEDED(32)
245 SHOW_NEEDED(64)
246 }
247}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{
250 void *strtbl_void;
251
252 if (!show_interp) return NULL;
253
254 strtbl_void = elf_findsecbyname(elf, ".interp");
255
256 if (strtbl_void) {
257#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \
262 }
263 SHOW_INTERP(32)
264 SHOW_INTERP(64)
265 }
266 return NULL;
267}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
269{
270 int i;
271 void *symtab_void, *strtab_void;
272
273 if (!find_sym) return NULL;
274
275 symtab_void = elf_findsecbyname(elf, ".symtab");
276 strtab_void = elf_findsecbyname(elf, ".strtab");
277
278 if (symtab_void && strtab_void) {
279#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \
286 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \
293 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \
295 symname); \
296 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \
298 (strcmp(symname, versioned_symname) == 0)) \
299 (*found_sym)++; \
300 } \
301 ++sym; \
302 } }
303 FIND_SYM(32)
304 FIND_SYM(64)
305 }
306 if (*find_sym != '*' && *found_sym)
307 return find_sym;
308 if (be_quiet)
309 return NULL;
310 else
311 return " - ";
312}
75/* scan an elf file and show all the fun stuff */ 313/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout)
76static void scanelf_file(const char *filename) 315static void scanelf_file(const char *filename)
77{ 316{
78 int i; 317 int i;
79 char found_pax, found_stack, found_relro, found_textrel, found_rpath; 318 char found_pax, found_stack, found_relro, found_textrel,
80 Elf_Dyn *dyn; 319 found_rpath, found_needed, found_interp, found_sym,
320 found_file;
81 elfobj *elf = NULL; 321 elfobj *elf;
322 struct stat st;
323 static char *out_buffer = NULL;
324 static size_t out_len;
82 325
326 /* make sure 'filename' exists */
327 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return;
330 }
331 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return;
335 }
336
83 found_pax = found_stack = found_relro = found_textrel = found_rpath = 0; 337 found_pax = found_stack = found_relro = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \
339 found_file = 0;
84 340
85 /* verify this is real ELF */ 341 /* verify this is real ELF */
86 if ((elf = readelf(filename)) == NULL) { 342 if ((elf = readelf(filename)) == NULL) {
87 if (be_verbose > 1) printf("File '%s' is not an ELF\n", filename); 343 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
88 return; 344 return;
89 } 345 }
90 if (check_elf_header(elf->ehdr) || !IS_ELF(elf)) {
91 if (be_verbose > 1) printf("Cannot handle ELF '%s' :(\n", filename);
92 goto bail;
93 }
94 346
95 if (be_verbose) printf("Scanning file %s\n", filename); 347 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose)
352 printf("%s: scanning file\n", filename);
353
354 /* init output buffer */
355 if (!out_buffer) {
356 out_len = sizeof(char) * 80;
357 out_buffer = (char*)xmalloc(out_len);
358 }
359 *out_buffer = '\0';
96 360
97 /* show the header */ 361 /* show the header */
98 if (!be_quiet && show_header) { 362 if (!be_quiet && show_banner) {
99 fputs(" TYPE ", stdout); 363 for (i=0; out_format[i]; ++i) {
100 if (show_pax) fputs(" PAX ", stdout); 364 if (out_format[i] != '%') continue;
101 if (show_stack) fputs(" STK/REL ", stdout); 365
102 if (show_textrel) fputs("TEXTREL ", stdout); 366 switch (out_format[++i]) {
103 if (show_rpath) fputs("RPATH ", stdout); 367 case '%': break;
104 fputs(" FILE\n", stdout); 368 case 'F': prints("FILE "); break;
369 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break;
372 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break;
376 case 's': prints("SYM "); break;
377 }
378 }
379 prints("\n");
105 show_header = 0; 380 show_banner = 0;
106 } 381 }
107 382
108 /* dump all the good stuff */ 383 /* dump all the good stuff */
109 if (!be_quiet) 384 for (i=0; out_format[i]; ++i) {
110 printf("%-7s ", get_elfetype(elf->ehdr->e_type)); 385 const char *out;
111 386
112 if (show_pax) { 387 /* make sure we trim leading spaces in quiet mode */
113 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf)); 388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
114 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) { 389 *out_buffer = '\0';
115 found_pax = 1;
116 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
117 }
118 }
119 390
120 /* stack fun */ 391 if (out_format[i] != '%') {
121 if (show_stack) { 392 xchrcat(&out_buffer, out_format[i], &out_len);
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; 393 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 } 394 }
154 }
155 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
156 }
157 395
158 /* rpath fun */ 396 out = NULL;
159 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 397 switch (out_format[++i]) {
160 if (show_rpath) { 398 case '%': xchrcat(&out_buffer, '%', &out_len); break;
161 Elf_Shdr *strtbl = elf_findsecbyname(elf, ".dynstr"); 399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break;
162 400 case 'o': out = get_elfetype(elf); break;
163 if (strtbl) 401 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
164 for (i = 0; i < elf->ehdr->e_phnum; i++) { 402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
165 if (elf->phdr[i].p_type != PT_DYNAMIC) continue; 403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
166 404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
167 dyn = (Elf_Dyn *)(elf->data + elf->phdr[i].p_offset); 405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
168 while (dyn->d_tag != DT_NULL) { 406 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
169 if (dyn->d_tag == DT_RPATH) { //|| dyn->d_tag != DT_RUNPATH) 407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
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 } 408 }
409 if (out) xstrcat(&out_buffer, out, &out_len);
176 } 410 }
177 if (!be_quiet && !found_rpath) fputs(" - ", stdout);
178 }
179 411
412 if (!found_file) {
180 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath) 413 if (!be_quiet || found_pax || found_stack || found_textrel || \
181 puts(filename); 414 found_rpath || found_needed || found_interp || found_sym)
415 xstrcat(&out_buffer, filename, &out_len);
416 }
417 if (!(be_quiet && xemptybuffer(out_buffer)))
418 puts(out_buffer);
182 419
183bail:
184 unreadelf(elf); 420 unreadelf(elf);
185} 421}
186 422
187/* scan a directory for ET_EXEC files and print when we find one */ 423/* scan a directory for ET_EXEC files and print when we find one */
188static void scanelf_dir(const char *path) 424static void scanelf_dir(const char *path)
189{ 425{
190 register DIR *dir; 426 register DIR *dir;
191 register struct dirent *dentry; 427 register struct dirent *dentry;
192 struct stat st_top, st; 428 struct stat st_top, st;
193 char *p; 429 char buf[_POSIX_PATH_MAX];
194 int len = 0; 430 size_t pathlen = 0, len = 0;
195 431
196 /* make sure path exists */ 432 /* make sure path exists */
197 if (lstat(path, &st_top) == -1) 433 if (lstat(path, &st_top) == -1) {
434 if (be_verbose > 2) printf("%s: does not exist\n", path);
198 return; 435 return;
436 }
199 437
200 /* ok, if it isn't a directory, assume we can open it */ 438 /* ok, if it isn't a directory, assume we can open it */
201 if (!S_ISDIR(st_top.st_mode)) { 439 if (!S_ISDIR(st_top.st_mode)) {
202 scanelf_file(path); 440 scanelf_file(path);
203 return; 441 return;
206 /* now scan the dir looking for fun stuff */ 444 /* now scan the dir looking for fun stuff */
207 if ((dir = opendir(path)) == NULL) { 445 if ((dir = opendir(path)) == NULL) {
208 warnf("could not opendir %s: %s", path, strerror(errno)); 446 warnf("could not opendir %s: %s", path, strerror(errno));
209 return; 447 return;
210 } 448 }
211 if (be_verbose) printf("Scanning dir %s\n", path); 449 if (be_verbose) printf("%s: scanning dir\n", path);
212 450
451 pathlen = strlen(path);
213 while ((dentry = readdir(dir))) { 452 while ((dentry = readdir(dir))) {
214 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 453 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
215 continue; 454 continue;
216 len = (strlen(path) + 2 + strlen(dentry->d_name)); 455 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
217 p = malloc(len); 456 if (len >= sizeof(buf)) {
218 if (!p) 457 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
219 err("scanelf_dir(): Could not malloc: %s", strerror(errno)); 458 continue;
220 strncpy(p, path, len); 459 }
221 strncat(p, "/", len); 460 sprintf(buf, "%s/%s", path, dentry->d_name);
222 strncat(p, dentry->d_name, len);
223 if (lstat(p, &st) != -1) { 461 if (lstat(buf, &st) != -1) {
224 if (S_ISREG(st.st_mode)) 462 if (S_ISREG(st.st_mode))
225 scanelf_file(p); 463 scanelf_file(buf);
226 else if (dir_recurse && S_ISDIR(st.st_mode)) { 464 else if (dir_recurse && S_ISDIR(st.st_mode)) {
227 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 465 if (dir_crossmount || (st_top.st_dev == st.st_dev))
228 scanelf_dir(p); 466 scanelf_dir(buf);
229 } 467 }
230 } 468 }
231 free(p);
232 } 469 }
233 closedir(dir); 470 closedir(dir);
234} 471}
235 472
236/* scan /etc/ld.so.conf for paths */ 473/* scan /etc/ld.so.conf for paths */
237static void scanelf_ldpath() 474static void scanelf_ldpath()
238{ 475{
476 char scan_l, scan_ul, scan_ull;
239 char *path, *p; 477 char *path, *p;
240 FILE *fp; 478 FILE *fp;
241 479
242 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
243 err("Unable to open ld.so.conf: %s", strerror(errno)); 481 err("Unable to open ld.so.conf: %s", strerror(errno));
244 482
483 scan_l = scan_ul = scan_ull = 0;
484
245 path = malloc(_POSIX_PATH_MAX); 485 path = (char*)xmalloc(_POSIX_PATH_MAX);
246 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) 486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
247 if (*path == '/') { 487 if (*path == '/') {
248 if ((p = strrchr(path, '\r')) != NULL) 488 if ((p = strrchr(path, '\r')) != NULL)
249 *p = 0; 489 *p = 0;
250 if ((p = strrchr(path, '\n')) != NULL) 490 if ((p = strrchr(path, '\n')) != NULL)
251 *p = 0; 491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
252 scanelf_dir(path); 495 scanelf_dir(path);
253 } 496 }
254 free(path); 497 free(path);
255
256 fclose(fp); 498 fclose(fp);
499
500 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib");
257} 503}
258 504
259/* scan env PATH for paths */ 505/* scan env PATH for paths */
260static void scanelf_envpath() 506static void scanelf_envpath()
261{ 507{
262 char *path, *p; 508 char *path, *p;
263 509
264 path = getenv("PATH"); 510 path = getenv("PATH");
265 if (!path) 511 if (!path)
266 err("PATH is not set in your env !"); 512 err("PATH is not set in your env !");
267 513 path = xstrdup(path);
268 if ((path = strdup(path)) == NULL)
269 err("stdup failed: %s", strerror(errno));
270 514
271 while ((p = strrchr(path, ':')) != NULL) { 515 while ((p = strrchr(path, ':')) != NULL) {
272 scanelf_dir(p + 1); 516 scanelf_dir(p + 1);
273 *p = 0; 517 *p = 0;
274 } 518 }
519
275 free(path); 520 free(path);
276} 521}
277 522
278 523
279 524
280/* usage / invocation handling functions */ 525/* usage / invocation handling functions */
281#define PARSE_FLAGS "plRmxstraqvHhV" 526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV"
527#define a_argument required_argument
282static struct option const long_opts[] = { 528static struct option const long_opts[] = {
283 {"path", no_argument, NULL, 'p'}, 529 {"path", no_argument, NULL, 'p'},
284 {"ldpath", no_argument, NULL, 'l'}, 530 {"ldpath", no_argument, NULL, 'l'},
285 {"recursive", no_argument, NULL, 'R'}, 531 {"recursive", no_argument, NULL, 'R'},
286 {"mount", no_argument, NULL, 'm'}, 532 {"mount", no_argument, NULL, 'm'},
533 {"symlink", no_argument, NULL, 'y'},
287 {"pax", no_argument, NULL, 'x'}, 534 {"pax", no_argument, NULL, 'x'},
288 {"stack", no_argument, NULL, 's'}, 535 {"header", no_argument, NULL, 'e'},
289 {"textrel", no_argument, NULL, 't'}, 536 {"textrel", no_argument, NULL, 't'},
290 {"rpath", no_argument, NULL, 'r'}, 537 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'},
540 {"symbol", a_argument, NULL, 's'},
291 {"all", no_argument, NULL, 'a'}, 541 {"all", no_argument, NULL, 'a'},
292 {"quiet", no_argument, NULL, 'q'}, 542 {"quiet", no_argument, NULL, 'q'},
293 {"verbose", no_argument, NULL, 'v'}, 543 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'},
545 {"file", a_argument, NULL, 'o'},
294 {"noheader", no_argument, NULL, 'H'}, 546 {"nobanner", no_argument, NULL, 'B'},
295 {"help", no_argument, NULL, 'h'}, 547 {"help", no_argument, NULL, 'h'},
296 {"version", no_argument, NULL, 'V'}, 548 {"version", no_argument, NULL, 'V'},
297 {NULL, no_argument, NULL, 0x0} 549 {NULL, no_argument, NULL, 0x0}
298}; 550};
299static char *opts_help[] = { 551static char *opts_help[] = {
300 "Scan all directories in PATH environment", 552 "Scan all directories in PATH environment",
301 "Scan all directories in /etc/ld.so.conf", 553 "Scan all directories in /etc/ld.so.conf",
302 "Scan directories recursively", 554 "Scan directories recursively",
303 "Don't recursively cross mount points\n", 555 "Don't recursively cross mount points",
556 "Don't scan symlinks\n",
304 "Print PaX markings", 557 "Print PaX markings",
305 "Print GNU_STACK markings", 558 "Print GNU_STACK markings",
306 "Print TEXTREL information", 559 "Print TEXTREL information",
307 "Print RPATH information", 560 "Print RPATH information",
561 "Print NEEDED information",
562 "Print INTERP information",
563 "Find a specified symbol",
308 "Print all scanned info (-x -s -t -r)\n", 564 "Print all scanned info (-x -e -t -r)\n",
309 "Only output 'bad' things", 565 "Only output 'bad' things",
310 "Be verbose (can be specified more than once)", 566 "Be verbose (can be specified more than once)",
567 "Use specified format for output",
568 "Write output stream to a filename",
311 "Don't display the header", 569 "Don't display the header",
312 "Print this help and exit", 570 "Print this help and exit",
313 "Print version and exit", 571 "Print version and exit",
314 NULL 572 NULL
315}; 573};
317/* display usage and exit */ 575/* display usage and exit */
318static void usage(int status) 576static void usage(int status)
319{ 577{
320 int i; 578 int i;
321 printf(" Scan ELF binaries for stuff\n\n" 579 printf(" Scan ELF binaries for stuff\n\n"
322 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); 580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
323 fputs("Options:\n", stdout); 581 printf("Options: -[%s]\n", PARSE_FLAGS);
324 for (i = 0; long_opts[i].name; ++i) 582 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument)
325 printf(" -%c, --%-12s %s\n", long_opts[i].val, 584 printf(" -%c, --%-13s %s\n", long_opts[i].val,
326 long_opts[i].name, opts_help[i]); 585 long_opts[i].name, opts_help[i]);
586 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]);
327 exit(status); 589 exit(status);
328} 590}
329 591
330/* parse command line arguments and preform needed actions */ 592/* parse command line arguments and preform needed actions */
331static void parseargs(int argc, char *argv[]) 593static void parseargs(int argc, char *argv[])
334 596
335 opterr = 0; 597 opterr = 0;
336 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
337 switch (flag) { 599 switch (flag) {
338 600
339 case 'V': /* version info */ 601 case 'V':
340 printf("%s compiled %s\n" 602 printf("%s compiled %s\n%s\n"
341 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n" 603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
342 "%s\n",
343 __FILE__, __DATE__, argv0, rcsid); 604 __FILE__, __DATE__, rcsid, argv0);
344 exit(EXIT_SUCCESS); 605 exit(EXIT_SUCCESS);
345 break; 606 break;
346 case 'h': usage(EXIT_SUCCESS); break; 607 case 'h': usage(EXIT_SUCCESS); break;
347 608
609 case 'o': {
610 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout);
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp;
615 break;
616 }
617
618 case 's': {
619 size_t len;
620 find_sym = xstrdup(optarg);
621 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
623 sprintf(versioned_symname, "%s@", find_sym);
624 break;
625 }
626
627 case 'F': {
628 out_format = strdup(optarg);
629 break;
630 }
631
632 case 'y': scan_symlink = 0; break;
348 case 'H': show_header = 0; break; 633 case 'B': show_banner = 0; break;
349 case 'l': scan_ldpath = 1; break; 634 case 'l': scan_ldpath = 1; break;
350 case 'p': scan_envpath = 1; break; 635 case 'p': scan_envpath = 1; break;
351 case 'R': dir_recurse = 1; break; 636 case 'R': dir_recurse = 1; break;
352 case 'm': dir_crossmount = 0; break; 637 case 'm': dir_crossmount = 0; break;
353 case 'x': show_pax = 1; break; 638 case 'x': show_pax = 1; break;
354 case 's': show_stack = 1; break; 639 case 'e': show_stack = 1; break;
355 case 't': show_textrel = 1; break; 640 case 't': show_textrel = 1; break;
356 case 'r': show_rpath = 1; break; 641 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break;
357 case 'q': be_quiet = 1; break; 644 case 'q': be_quiet = 1; break;
358 case 'v': be_verbose = (be_verbose % 20) + 1; break; 645 case 'v': be_verbose = (be_verbose % 20) + 1; break;
359 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break; 646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
360 647
361 case ':': 648 case ':':
362 warn("Option missing parameter"); 649 warn("Option missing parameter\n");
363 usage(EXIT_FAILURE); 650 usage(EXIT_FAILURE);
364 break; 651 break;
365 case '?': 652 case '?':
366 warn("Unknown option"); 653 warn("Unknown option\n");
367 usage(EXIT_FAILURE); 654 usage(EXIT_FAILURE);
368 break; 655 break;
369 default: 656 default:
370 err("Unhandled option '%c'", flag); 657 err("Unhandled option '%c'", flag);
371 break; 658 break;
373 } 660 }
374 661
375 if (be_quiet && be_verbose) 662 if (be_quiet && be_verbose)
376 err("You can be quiet or you can be verbose, not both, stupid"); 663 err("You can be quiet or you can be verbose, not both, stupid");
377 664
665 /* let the format option override all other options */
666 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
668 for (flag=0; out_format[flag]; ++flag) {
669 if (out_format[flag] != '%') continue;
670
671 switch (out_format[++flag]) {
672 case '%': break;
673 case 'F': break;
674 case 's': break;
675 case 'o': break;
676 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break;
682 default:
683 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1);
685 }
686 }
687
688 /* construct our default format */
689 } else {
690 size_t fmt_len = 30;
691 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
692 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
693 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format);
703
704 /* now lets actually do the scanning */
378 if (scan_ldpath) scanelf_ldpath(); 705 if (scan_ldpath) scanelf_ldpath();
379 if (scan_envpath) scanelf_envpath(); 706 if (scan_envpath) scanelf_envpath();
707 if (optind == argc && !scan_ldpath && !scan_envpath)
708 err("Nothing to scan !?");
380 while (optind < argc) 709 while (optind < argc)
381 scanelf_dir(argv[optind++]); 710 scanelf_dir(argv[optind++]);
711
712 /* clean up */
713 if (find_sym) {
714 free(find_sym);
715 free(versioned_symname);
716 }
717 if (out_format) free(out_format);
718}
719
720
721
722/* utility funcs */
723static char *xstrdup(char *s)
724{
725 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret;
728}
729static void *xmalloc(size_t size)
730{
731 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret;
734}
735static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{
737 long new_len;
738
739 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len);
743 if (!*dst)
744 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 }
746
747 strcat(*dst, src);
748}
749static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{
751 static char my_app[2];
752 my_app[0] = append;
753 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len);
755}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
382} 763}
383 764
384 765
385 766
386int main(int argc, char *argv[]) 767int main(int argc, char *argv[])
387{ 768{
388 if (argc < 2) 769 if (argc < 2)
389 usage(EXIT_FAILURE); 770 usage(EXIT_FAILURE);
390 parseargs(argc, argv); 771 parseargs(argc, argv);
772 fclose(stdout);
391 return EXIT_SUCCESS; 773 return EXIT_SUCCESS;
392} 774}

Legend:
Removed from v.1.14  
changed lines
  Added in v.1.43

  ViewVC Help
Powered by ViewVC 1.1.20