/[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.33 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.33 2005/04/10 15:15:40 solar 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
33#include <getopt.h> 33#include <getopt.h>
34#include <assert.h> 34#include <assert.h>
35 35
36#include "paxelf.h" 36#include "paxelf.h"
37 37
38static const char *rcsid = "$Id: scanelf.c,v 1.33 2005/04/10 15:15:40 solar Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $";
39 39#define argv0 "scanelf"
40
41/* helper functions for showing errors */
42#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
43#define warn(fmt, args...) \
44 fprintf(stderr, "%s: " fmt "\n", argv0, ## args)
45#define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args)
46#define err(fmt, args...) \
47 do { \
48 warn(fmt, ## args); \
49 exit(EXIT_FAILURE); \
50 } while (0)
51 40
52 41
53 42
54/* prototypes */ 43/* prototypes */
55static void scanelf_file(const char *filename); 44static void scanelf_file(const char *filename);
56static void scanelf_dir(const char *path); 45static void scanelf_dir(const char *path);
57static void scanelf_ldpath(); 46static void scanelf_ldpath();
58static void scanelf_envpath(); 47static void scanelf_envpath();
59static void usage(int status); 48static void usage(int status);
60static 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);
61 55
62/* variables to control behavior */ 56/* variables to control behavior */
63static char scan_ldpath = 0; 57static char scan_ldpath = 0;
64static char scan_envpath = 0; 58static char scan_envpath = 0;
59static char scan_symlink = 1;
65static char dir_recurse = 0; 60static char dir_recurse = 0;
66static char dir_crossmount = 1; 61static char dir_crossmount = 1;
67static char show_pax = 0; 62static char show_pax = 0;
68static char show_stack = 0; 63static char show_stack = 0;
69static char show_textrel = 0; 64static char show_textrel = 0;
70static char show_rpath = 0; 65static char show_rpath = 0;
71static char show_needed = 0; 66static char show_needed = 0;
67static char show_interp = 0;
72static char show_banner = 1; 68static char show_banner = 1;
73static char be_quiet = 0; 69static char be_quiet = 0;
74static char be_verbose = 0; 70static char be_verbose = 0;
71static char *find_sym = NULL, *versioned_symname = NULL;
75static char *find_sym = NULL; 72static char *out_format = NULL;
76 73
77 74
78 75
79/* scan an elf file and show all the fun stuff */ 76/* sub-funcs for scanelf_file() */
80static void scanelf_file(const char *filename) 77static char *scanelf_file_pax(elfobj *elf, char *found_pax)
81{ 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";
82 int i; 131 int i;
83 char found_pax, found_stack, found_relro, found_textrel,
84 found_rpath, found_needed, found_sym;
85 elfobj *elf;
86 struct stat st;
87 132
88 /* make sure path exists */ 133 if (!show_textrel) return NULL;
89 if (lstat(filename, &st) == -1)
90 return;
91 if (!S_ISREG(st.st_mode))
92 return;
93 found_pax = found_stack = found_relro = found_textrel = \
94 found_rpath = found_needed = found_sym = 0;
95 134
96 /* verify this is real ELF */
97 if ((elf = readelf(filename)) == NULL) {
98 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
99 return;
100 }
101
102 if (be_verbose > 1)
103 printf("%s: {%s,%s} scanning file\n", filename,
104 get_elfeitype(elf, EI_CLASS, elf->elf_class),
105 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
106 else if (be_verbose)
107 printf("%s: scanning file\n", filename);
108
109 /* show the header */
110 if (!be_quiet && show_banner) {
111 printf(" TYPE ");
112 if (show_pax) printf(" PAX ");
113 if (show_stack) printf("STK/REL ");
114 if (show_textrel) printf("TEXTREL ");
115 if (show_rpath) printf("RPATH ");
116 if (show_needed) printf("NEEDED ");
117 printf(" FILE\n");
118 show_banner = 0;
119 }
120
121 /* dump all the good stuff */
122 if (!be_quiet)
123 printf("%-7s ", get_elfetype(elf));
124
125 if (show_pax) {
126 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
127 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
128 found_pax = 1;
129 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
130 }
131 }
132
133 /* stack fun */
134 if (show_stack) {
135#define SHOW_STACK(B) \ 135#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 136 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \
137 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
138 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
139 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
140 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \ 141 if (phdr[i].p_type != PT_DYNAMIC) continue; \
141 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \ 142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
142 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 143 while (EGET(dyn->d_tag) != DT_NULL) { \
143 continue; \ 144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
144 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \
145 found_stack = 1; \
146 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \
147 found_relro = 1; \ 145 *found_textrel = 1; \
148 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \ 146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \
148 } \
149 ++dyn; \
149 } \ 150 } \
150 }
151 SHOW_STACK(32)
152 SHOW_STACK(64)
153 if (!be_quiet && !found_stack) printf("--- ");
154 if (!be_quiet && !found_relro) printf("--- ");
155 }
156
157 /* textrel fun */
158 if (show_textrel) {
159#define SHOW_TEXTREL(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Dyn *dyn; \
162 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
163 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
164 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
165 if (phdr[i].p_type != PT_DYNAMIC) continue; \
166 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
167 while (EGET(dyn->d_tag) != DT_NULL) { \
168 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
169 found_textrel = 1; \
170 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
171 fputs("TEXTREL ", stdout); \
172 } \
173 ++dyn; \
174 } \
175 } } 151 } }
176 SHOW_TEXTREL(32) 152 SHOW_TEXTREL(32)
177 SHOW_TEXTREL(64) 153 SHOW_TEXTREL(64)
178 if (!be_quiet && !found_textrel) fputs("------- ", stdout); 154 if (be_quiet)
179 } 155 return NULL;
180 156 else
181 /* rpath fun */ 157 return " - ";
158}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{
182 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
183 if (show_rpath) { 162 int i;
184 char *rpath, *runpath; 163 char *rpath, *runpath;
164 void *strtbl_void;
165
166 if (!show_rpath) return;
167
185 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 168 strtbl_void = elf_findsecbyname(elf, ".dynstr");
186 rpath = runpath = NULL; 169 rpath = runpath = NULL;
187 170
188 if (strtbl_void) { 171 if (strtbl_void) {
189#define SHOW_RPATH(B) \ 172#define SHOW_RPATH(B) \
190 if (elf->elf_class == ELFCLASS ## B) { \ 173 if (elf->elf_class == ELFCLASS ## B) { \
191 Elf ## B ## _Dyn *dyn; \ 174 Elf ## B ## _Dyn *dyn; \
192 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
193 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
195 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
196 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
197 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
198 while (EGET(dyn->d_tag) != DT_NULL) { \ 181 while (EGET(dyn->d_tag) != DT_NULL) { \
199 if (EGET(dyn->d_tag) == DT_RPATH) { \ 182 if (EGET(dyn->d_tag) == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \
200 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
201 found_rpath = 1; \ 185 *found_rpath = 1; \
202 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \ 186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
203 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204 found_rpath = 1; \ 189 *found_rpath = 1; \
205 } \ 190 } \
206 ++dyn; \ 191 ++dyn; \
207 } \ 192 } \
208 } } 193 } }
209 SHOW_RPATH(32) 194 SHOW_RPATH(32)
210 SHOW_RPATH(64) 195 SHOW_RPATH(64)
211 } 196 }
197
212 if (rpath && runpath) { 198 if (rpath && runpath) {
213 if (!strcmp(rpath, runpath)) 199 if (!strcmp(rpath, runpath)) {
214 printf("%-5s ", runpath); 200 xstrcat(ret, runpath, ret_len);
215 else { 201 } else {
216 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath); 202 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
217 printf("{%s,%s} ", 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);
218 } 208 }
219 } else if (rpath || runpath) 209 } else if (rpath || runpath)
220 printf("%-5s ", (runpath ? runpath : rpath)); 210 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
221 else if (!be_quiet && !found_rpath) 211 else if (!be_quiet)
222 printf(" - "); 212 xstrcat(ret, " - ", ret_len);
223 } 213}
224 214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
225 /* print out all the NEEDED entries */ 215{
226 if (show_needed) { 216 int i;
227 char *needed; 217 char *needed;
218 void *strtbl_void;
219
220 if (!show_needed) return;
221
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 222 strtbl_void = elf_findsecbyname(elf, ".dynstr");
229 223
230 if (strtbl_void) { 224 if (strtbl_void) {
231#define SHOW_NEEDED(B) \ 225#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \ 226 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \ 227 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
238 if (be_verbose && EGET(phdr[i].p_type) == PT_INTERP) { \
239 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
240 printf("%s\n", elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr)); \
241 exit(0); \
242 } \
243 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \ 234 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 235 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
248 if (found_needed) printf(","); \ 237 if (*found_needed) xchrcat(ret, ',', ret_len); \
249 printf("%s", needed); \ 238 xstrcat(ret, needed, ret_len); \
250 found_needed = 1; \ 239 *found_needed = 1; \
251 } \ 240 } \
252 ++dyn; \ 241 ++dyn; \
253 } \ 242 } \
254 } } 243 } }
255 SHOW_NEEDED(32) 244 SHOW_NEEDED(32)
256 SHOW_NEEDED(64) 245 SHOW_NEEDED(64)
257 } 246 }
258 if (!be_quiet && !found_needed) 247}
259 printf(" - "); 248static char *scanelf_file_interp(elfobj *elf, char *found_interp)
260 else if (found_needed) 249{
261 printf(" "); 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 } 262 }
263 263 SHOW_INTERP(32)
264 /* search the symbol table for a specified symbol */ 264 SHOW_INTERP(64)
265 if (find_sym) { 265 }
266 return NULL;
267}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
269{
270 int i;
266 void *symtab_void, *strtab_void; 271 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269 272
270 len = strlen(find_sym) + 1; 273 if (!find_sym) return NULL;
271 versioned_symname = (char *)malloc(sizeof(char) * (len+1));
272 if (!versioned_symname) {
273 warnf("Could not malloc() mem for sym scan");
274 return;
275 }
276 sprintf(versioned_symname, "%s@", find_sym);
277 274
278 symtab_void = elf_findsecbyname(elf, ".symtab"); 275 symtab_void = elf_findsecbyname(elf, ".symtab");
279 strtab_void = elf_findsecbyname(elf, ".strtab"); 276 strtab_void = elf_findsecbyname(elf, ".strtab");
280 277
281 if (symtab_void && strtab_void) { 278 if (symtab_void && strtab_void) {
282#define FIND_SYM(B) \ 279#define FIND_SYM(B) \
283 if (elf->elf_class == ELFCLASS ## B) { \ 280 if (elf->elf_class == ELFCLASS ## B) { \
284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
286 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
289 for (i = 0; i < cnt; ++i) { \ 286 for (i = 0; i < cnt; ++i) { \
290 if (sym->st_name) { \ 287 if (sym->st_name) { \
291 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
292 if (*find_sym == '*') { \ 289 if (*find_sym == '*') { \
293 printf("%s(%s) %5lX %15s %s\n", \ 290 printf("%s(%s) %5lX %15s %s\n", \
294 ((found_sym == 0) ? "\n\t" : "\t"), \ 291 ((*found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \ 292 (char *)basename(filename), \
296 (long)sym->st_size, \ 293 (long)sym->st_size, \
297 (char *)get_elfstttype(sym->st_info), \ 294 (char *)get_elfstttype(sym->st_info), \
298 symname); \ 295 symname); \
299 found_sym = 1; \ 296 *found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \ 297 } else if ((strcmp(find_sym, symname) == 0) || \
301 (strncmp(symname, versioned_symname, len) == 0)) \ 298 (strcmp(symname, versioned_symname) == 0)) \
302 found_sym++; \ 299 (*found_sym)++; \
303 } \ 300 } \
304 ++sym; \ 301 ++sym; \
305 } } 302 } }
306 FIND_SYM(32) 303 FIND_SYM(32)
307 FIND_SYM(64) 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}
313/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout)
315static void scanelf_file(const char *filename)
316{
317 int i;
318 char found_pax, found_stack, found_relro, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym,
320 found_file;
321 elfobj *elf;
322 struct stat st;
323 static char *out_buffer = NULL;
324 static size_t out_len;
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
337 found_pax = found_stack = found_relro = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \
339 found_file = 0;
340
341 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return;
345 }
346
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';
360
361 /* show the header */
362 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue;
365
366 switch (out_format[++i]) {
367 case '%': break;
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;
308 } 377 }
309 free(versioned_symname);
310 if (*find_sym != '*') {
311 if (found_sym)
312 printf(" %s ", find_sym);
313 else if (!be_quiet)
314 fputs(" - ", stdout);
315 }
316 } 378 }
379 prints("\n");
380 show_banner = 0;
381 }
317 382
383 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) {
385 const char *out;
386
387 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0';
390
391 if (out_format[i] != '%') {
392 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue;
394 }
395
396 out = NULL;
397 switch (out_format[++i]) {
398 case '%': xchrcat(&out_buffer, '%', &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break;
400 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
408 }
409 if (out) xstrcat(&out_buffer, out, &out_len);
410 }
411
412 if (!found_file) {
318 if (!be_quiet || found_pax || found_stack || found_textrel || \ 413 if (!be_quiet || found_pax || found_stack || found_textrel || \
319 found_rpath || found_needed || found_sym) 414 found_rpath || found_needed || found_interp || found_sym)
320 puts(filename); 415 xstrcat(&out_buffer, filename, &out_len);
416 }
417 if (!(be_quiet && xemptybuffer(out_buffer)))
418 puts(out_buffer);
321 419
322 unreadelf(elf); 420 unreadelf(elf);
323} 421}
324 422
325/* 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 */
330 struct stat st_top, st; 428 struct stat st_top, st;
331 char buf[_POSIX_PATH_MAX]; 429 char buf[_POSIX_PATH_MAX];
332 size_t pathlen = 0, len = 0; 430 size_t pathlen = 0, len = 0;
333 431
334 /* make sure path exists */ 432 /* make sure path exists */
335 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);
336 return; 435 return;
436 }
337 437
338 /* 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 */
339 if (!S_ISDIR(st_top.st_mode)) { 439 if (!S_ISDIR(st_top.st_mode)) {
340 scanelf_file(path); 440 scanelf_file(path);
341 return; 441 return;
380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
381 err("Unable to open ld.so.conf: %s", strerror(errno)); 481 err("Unable to open ld.so.conf: %s", strerror(errno));
382 482
383 scan_l = scan_ul = scan_ull = 0; 483 scan_l = scan_ul = scan_ull = 0;
384 484
385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 485 path = (char*)xmalloc(_POSIX_PATH_MAX);
386 warn("Can not malloc() memory for ldpath scanning");
387 return;
388 }
389 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) 486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
390 if (*path == '/') { 487 if (*path == '/') {
391 if ((p = strrchr(path, '\r')) != NULL) 488 if ((p = strrchr(path, '\r')) != NULL)
392 *p = 0; 489 *p = 0;
393 if ((p = strrchr(path, '\n')) != NULL) 490 if ((p = strrchr(path, '\n')) != NULL)
406} 503}
407 504
408/* scan env PATH for paths */ 505/* scan env PATH for paths */
409static void scanelf_envpath() 506static void scanelf_envpath()
410{ 507{
411 char *orig_path, *path, *p; 508 char *path, *p;
412 509
413 path = getenv("PATH"); 510 path = getenv("PATH");
414 if (!path) 511 if (!path)
415 err("PATH is not set in your env !"); 512 err("PATH is not set in your env !");
416 513 path = xstrdup(path);
417 if ((orig_path = path = strdup(path)) == NULL)
418 err("strdup failed: %s", strerror(errno));
419 514
420 while ((p = strrchr(path, ':')) != NULL) { 515 while ((p = strrchr(path, ':')) != NULL) {
421 scanelf_dir(p + 1); 516 scanelf_dir(p + 1);
422 *p = 0; 517 *p = 0;
423 } 518 }
424 519
425 free(orig_path); 520 free(path);
426} 521}
427 522
428 523
429 524
430/* usage / invocation handling functions */ 525/* usage / invocation handling functions */
431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV" 526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV"
432#define a_argument required_argument 527#define a_argument required_argument
433static struct option const long_opts[] = { 528static struct option const long_opts[] = {
434 {"path", no_argument, NULL, 'p'}, 529 {"path", no_argument, NULL, 'p'},
435 {"ldpath", no_argument, NULL, 'l'}, 530 {"ldpath", no_argument, NULL, 'l'},
436 {"recursive", no_argument, NULL, 'R'}, 531 {"recursive", no_argument, NULL, 'R'},
437 {"mount", no_argument, NULL, 'm'}, 532 {"mount", no_argument, NULL, 'm'},
533 {"symlink", no_argument, NULL, 'y'},
438 {"pax", no_argument, NULL, 'x'}, 534 {"pax", no_argument, NULL, 'x'},
439 {"header", no_argument, NULL, 'e'}, 535 {"header", no_argument, NULL, 'e'},
440 {"textrel", no_argument, NULL, 't'}, 536 {"textrel", no_argument, NULL, 't'},
441 {"rpath", no_argument, NULL, 'r'}, 537 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'}, 538 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'},
443 {"symbol", a_argument, NULL, 's'}, 540 {"symbol", a_argument, NULL, 's'},
444 {"all", no_argument, NULL, 'a'}, 541 {"all", no_argument, NULL, 'a'},
445 {"quiet", no_argument, NULL, 'q'}, 542 {"quiet", no_argument, NULL, 'q'},
446 {"verbose", no_argument, NULL, 'v'}, 543 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'},
447 {"file", a_argument, NULL, 'o'}, 545 {"file", a_argument, NULL, 'o'},
448 {"nobanner", no_argument, NULL, 'B'}, 546 {"nobanner", no_argument, NULL, 'B'},
449 {"help", no_argument, NULL, 'h'}, 547 {"help", no_argument, NULL, 'h'},
450 {"version", no_argument, NULL, 'V'}, 548 {"version", no_argument, NULL, 'V'},
451 {NULL, no_argument, NULL, 0x0} 549 {NULL, no_argument, NULL, 0x0}
452}; 550};
453static char *opts_help[] = { 551static char *opts_help[] = {
454 "Scan all directories in PATH environment", 552 "Scan all directories in PATH environment",
455 "Scan all directories in /etc/ld.so.conf", 553 "Scan all directories in /etc/ld.so.conf",
456 "Scan directories recursively", 554 "Scan directories recursively",
457 "Don't recursively cross mount points\n", 555 "Don't recursively cross mount points",
556 "Don't scan symlinks\n",
458 "Print PaX markings", 557 "Print PaX markings",
459 "Print GNU_STACK markings", 558 "Print GNU_STACK markings",
460 "Print TEXTREL information", 559 "Print TEXTREL information",
461 "Print RPATH information", 560 "Print RPATH information",
462 "Print NEEDED information", 561 "Print NEEDED information",
562 "Print INTERP information",
463 "Find a specified symbol", 563 "Find a specified symbol",
464 "Print all scanned info (-x -e -t -r)\n", 564 "Print all scanned info (-x -e -t -r)\n",
465 "Only output 'bad' things", 565 "Only output 'bad' things",
466 "Be verbose (can be specified more than once)", 566 "Be verbose (can be specified more than once)",
567 "Use specified format for output",
467 "Write output stream to a filename", 568 "Write output stream to a filename",
468 "Don't display the header", 569 "Don't display the header",
469 "Print this help and exit", 570 "Print this help and exit",
470 "Print version and exit", 571 "Print version and exit",
471 NULL 572 NULL
473 574
474/* display usage and exit */ 575/* display usage and exit */
475static void usage(int status) 576static void usage(int status)
476{ 577{
477 int i; 578 int i;
478 printf(" Scan ELF binaries for stuff\n" 579 printf(" Scan ELF binaries for stuff\n\n"
479 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); 580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
480 printf("Options:\n"); 581 printf("Options: -[%s]\n", PARSE_FLAGS);
481 for (i = 0; long_opts[i].name; ++i) 582 for (i = 0; long_opts[i].name; ++i)
482 if (long_opts[i].has_arg == no_argument) 583 if (long_opts[i].has_arg == no_argument)
483 printf(" -%c, --%-13s %s\n", long_opts[i].val, 584 printf(" -%c, --%-13s %s\n", long_opts[i].val,
484 long_opts[i].name, opts_help[i]); 585 long_opts[i].name, opts_help[i]);
485 else 586 else
495 596
496 opterr = 0; 597 opterr = 0;
497 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) {
498 switch (flag) { 599 switch (flag) {
499 600
500 case 'V': /* version info */ 601 case 'V':
501 printf("%s compiled %s\n%s\n" 602 printf("%s compiled %s\n%s\n"
502 "%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",
503 __FILE__, __DATE__, rcsid, argv0); 604 __FILE__, __DATE__, rcsid, argv0);
504 exit(EXIT_SUCCESS); 605 exit(EXIT_SUCCESS);
505 break; 606 break;
512 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 613 err("Could not open output stream '%s': %s", optarg, strerror(errno));
513 stdout = fp; 614 stdout = fp;
514 break; 615 break;
515 } 616 }
516 617
517 case 's': find_sym = strdup(optarg); break; 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 }
518 626
627 case 'F': {
628 out_format = strdup(optarg);
629 break;
630 }
631
632 case 'y': scan_symlink = 0; break;
519 case 'B': show_banner = 0; break; 633 case 'B': show_banner = 0; break;
520 case 'l': scan_ldpath = 1; break; 634 case 'l': scan_ldpath = 1; break;
521 case 'p': scan_envpath = 1; break; 635 case 'p': scan_envpath = 1; break;
522 case 'R': dir_recurse = 1; break; 636 case 'R': dir_recurse = 1; break;
523 case 'm': dir_crossmount = 0; break; 637 case 'm': dir_crossmount = 0; break;
524 case 'x': show_pax = 1; break; 638 case 'x': show_pax = 1; break;
525 case 'e': show_stack = 1; break; 639 case 'e': show_stack = 1; break;
526 case 't': show_textrel = 1; break; 640 case 't': show_textrel = 1; break;
527 case 'r': show_rpath = 1; break; 641 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break; 642 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break;
529 case 'q': be_quiet = 1; break; 644 case 'q': be_quiet = 1; break;
530 case 'v': be_verbose = (be_verbose % 20) + 1; break; 645 case 'v': be_verbose = (be_verbose % 20) + 1; break;
531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
532 647
533 case ':': 648 case ':':
534 warn("Option missing parameter"); 649 warn("Option missing parameter\n");
535 usage(EXIT_FAILURE); 650 usage(EXIT_FAILURE);
536 break; 651 break;
537 case '?': 652 case '?':
538 warn("Unknown option"); 653 warn("Unknown option\n");
539 usage(EXIT_FAILURE); 654 usage(EXIT_FAILURE);
540 break; 655 break;
541 default: 656 default:
542 err("Unhandled option '%c'", flag); 657 err("Unhandled option '%c'", flag);
543 break; 658 break;
545 } 660 }
546 661
547 if (be_quiet && be_verbose) 662 if (be_quiet && be_verbose)
548 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");
549 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 */
550 if (scan_ldpath) scanelf_ldpath(); 705 if (scan_ldpath) scanelf_ldpath();
551 if (scan_envpath) scanelf_envpath(); 706 if (scan_envpath) scanelf_envpath();
552 if (optind == argc && !scan_ldpath && !scan_envpath) 707 if (optind == argc && !scan_ldpath && !scan_envpath)
553 err("Nothing to scan !?"); 708 err("Nothing to scan !?");
554 while (optind < argc) 709 while (optind < argc)
555 scanelf_dir(argv[optind++]); 710 scanelf_dir(argv[optind++]);
556 711
557 if (find_sym) free(find_sym); 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;
558} 763}
559 764
560 765
561 766
562int main(int argc, char *argv[]) 767int main(int argc, char *argv[])

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

  ViewVC Help
Powered by ViewVC 1.1.20