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

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.45

  ViewVC Help
Powered by ViewVC 1.1.20