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

Legend:
Removed from v.1.40  
changed lines
  Added in v.1.48

  ViewVC Help
Powered by ViewVC 1.1.20