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

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.46

  ViewVC Help
Powered by ViewVC 1.1.20