/[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.43 Revision 1.78
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 2 * Copyright 2003-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.78 2005/06/08 22:23:16 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 ********************************************************************
8 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 8 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the 9 * published by the Free Software Foundation; either version 2 of the
22 */ 21 */
23 22
24#include <stdio.h> 23#include <stdio.h>
25#include <stdlib.h> 24#include <stdlib.h>
26#include <sys/types.h> 25#include <sys/types.h>
26#include <libgen.h>
27#include <limits.h>
27#define __USE_GNU 28#define __USE_GNU
28#include <string.h> 29#include <string.h>
29#include <errno.h> 30#include <errno.h>
30#include <unistd.h> 31#include <unistd.h>
31#include <sys/stat.h> 32#include <sys/stat.h>
32#include <dirent.h> 33#include <dirent.h>
33#include <getopt.h> 34#include <getopt.h>
34#include <assert.h> 35#include <assert.h>
35
36#include "paxelf.h" 36#include "paxelf.h"
37 37
38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.78 2005/06/08 22:23:16 vapier Exp $";
39#define argv0 "scanelf" 39#define argv0 "scanelf"
40
41#define IS_MODIFIER(c) (c == '%' || c == '#')
40 42
41 43
42 44
43/* prototypes */ 45/* prototypes */
44static void scanelf_file(const char *filename); 46static void scanelf_file(const char *filename);
45static void scanelf_dir(const char *path); 47static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 48static void scanelf_ldpath();
47static void scanelf_envpath(); 49static void scanelf_envpath();
48static void usage(int status); 50static void usage(int status);
49static void parseargs(int argc, char *argv[]); 51static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 52static char *xstrdup(const char *s);
51static void *xmalloc(size_t size); 53static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 54static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 55static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
55 56
56/* variables to control behavior */ 57/* variables to control behavior */
58static char *ldpaths[256];
57static char scan_ldpath = 0; 59static char scan_ldpath = 0;
58static char scan_envpath = 0; 60static char scan_envpath = 0;
59static char scan_symlink = 1; 61static char scan_symlink = 1;
60static char dir_recurse = 0; 62static char dir_recurse = 0;
61static char dir_crossmount = 1; 63static char dir_crossmount = 1;
62static char show_pax = 0; 64static char show_pax = 0;
63static char show_stack = 0; 65static char show_phdr = 0;
64static char show_textrel = 0; 66static char show_textrel = 0;
65static char show_rpath = 0; 67static char show_rpath = 0;
66static char show_needed = 0; 68static char show_needed = 0;
67static char show_interp = 0; 69static char show_interp = 0;
70static char show_bind = 0;
71static char show_textrels = 0;
68static char show_banner = 1; 72static char show_banner = 1;
69static char be_quiet = 0; 73static char be_quiet = 0;
70static char be_verbose = 0; 74static char be_verbose = 0;
75static char be_wewy_wewy_quiet = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 76static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL;
72static char *out_format = NULL; 78static char *out_format = NULL;
79static char *search_path = NULL;
73 80
74 81
75 82
76/* sub-funcs for scanelf_file() */ 83/* sub-funcs for scanelf_file() */
84static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
85{
86 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
87#define GET_SYMTABS(B) \
88 if (elf->elf_class == ELFCLASS ## B) { \
89 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
90 /* debug sections */ \
91 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
92 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
93 /* runtime sections */ \
94 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
95 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
96 if (symtab && dynsym) { \
97 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
98 } else { \
99 *sym = (void*)(symtab ? symtab : dynsym); \
100 } \
101 if (strtab && dynstr) { \
102 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
103 } else { \
104 *tab = (void*)(strtab ? strtab : dynstr); \
105 } \
106 }
107 GET_SYMTABS(32)
108 GET_SYMTABS(64)
109}
77static char *scanelf_file_pax(elfobj *elf, char *found_pax) 110static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{ 111{
79 static char *paxflags; 112 static char *paxflags;
113 static char ret[7];
114 unsigned long i, shown;
115
80 116
81 if (!show_pax) return NULL; 117 if (!show_pax) return NULL;
82 118
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85 *found_pax = 1;
86 return paxflags;
87 }
88
89 return NULL;
90}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{
93 static char ret[8];
94 char *found;
95 int i, off, shown;
96
97 if (!show_stack) return NULL;
98
99 shown = 0; 119 shown = 0;
100 strcpy(ret, "--- ---"); 120 memset(&ret, 0, sizeof(ret));
121
122 if (elf->phdr) {
101#define SHOW_STACK(B) \ 123#define SHOW_PAX(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 124 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 125 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 126 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 127 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
128 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
129 continue; \
130 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
131 continue; \
132 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
133 *found_pax = 1; \
134 ++shown; \
135 break; \
136 } \
137 }
138 SHOW_PAX(32)
139 SHOW_PAX(64)
140 }
141
142 /* fall back to EI_PAX if no PT_PAX was found */
143 if (!*ret) {
144 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
145 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
146 *found_pax = 1;
147 return paxflags;
148 }
149 strncpy(ret, paxflags, sizeof(ret));
150 // ++shown;
151 }
152
153 if (be_quiet && !shown)
154 return NULL;
155 return ret;
156
157}
158static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
159{
160 static char ret[12];
161 char *found;
162 unsigned long i, off, shown, check_flags;
163 unsigned char multi_stack, multi_relro, multi_load;
164
165 if (!show_phdr) return NULL;
166
167 memcpy(ret, "--- --- ---\0", 12);
168
169 shown = 0;
170 multi_stack = multi_relro = multi_load = 0;
171
172 if (elf->phdr) {
173#define SHOW_PHDR(B) \
174 if (elf->elf_class == ELFCLASS ## B) { \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 uint32_t flags; \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 179 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
180 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
107 found = found_stack; \ 181 found = found_phdr; \
108 off = 0; \ 182 off = 0; \
183 check_flags = PF_X; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 184 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
185 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
110 found = found_relro; \ 186 found = found_relro; \
111 off = 3; \ 187 off = 4; \
188 check_flags = PF_X; \
189 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
190 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
191 found = found_load; \
192 off = 8; \
193 check_flags = PF_W|PF_X; \
112 } else \ 194 } else \
113 continue; \ 195 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 196 flags = EGET(phdr[i].p_flags); \
197 if (be_quiet && ((flags & check_flags) != check_flags)) \
115 continue; \ 198 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 199 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
117 *found = 1; \ 200 *found = 1; \
118 ++shown; \ 201 ++shown; \
119 } \ 202 } \
120 } 203 }
121 SHOW_STACK(32) 204 SHOW_PHDR(32)
122 SHOW_STACK(64) 205 SHOW_PHDR(64)
206 }
207
123 if (be_quiet && !shown) 208 if (be_quiet && !shown)
124 return NULL; 209 return NULL;
125 else 210 else
126 return ret; 211 return ret;
127} 212}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 213static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 214{
130 static char *ret = "TEXTREL"; 215 static char ret[] = "TEXTREL";
131 int i; 216 unsigned long i;
132 217
133 if (!show_textrel) return NULL; 218 if (!show_textrel) return NULL;
134 219
220 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 221#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 222 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 223 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 224 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 225 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
226 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 227 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 228 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
229 offset = EGET(phdr[i].p_offset); \
230 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 231 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 232 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 233 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 234 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 235 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 236 return (be_wewy_wewy_quiet ? NULL : ret); \
148 } \ 237 } \
149 ++dyn; \ 238 ++dyn; \
150 } \ 239 } \
151 } } 240 } }
152 SHOW_TEXTREL(32) 241 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 242 SHOW_TEXTREL(64)
154 if (be_quiet) 243 }
244
245 if (be_quiet || be_wewy_wewy_quiet)
155 return NULL; 246 return NULL;
156 else 247 else
157 return " - "; 248 return (char *)" - ";
249}
250static char *scanelf_file_textrels(elfobj *elf, char *found_textrels)
251{
252 unsigned long p, s, r, rmax;
253 void *symtab_void, *strtab_void;
254
255 if (!show_textrels) return NULL;
256
257 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
258
259 if (symtab_void && strtab_void && elf->phdr && elf->shdr) {
260#define SHOW_TEXTRELS(B) \
261 if (elf->elf_class == ELFCLASS ## B) { \
262 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
263 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
264 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
265 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
266 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
267 Elf ## B ## _Rel *rel; \
268 Elf ## B ## _Rela *rela; \
269 /* search the section headers for relocations */ \
270 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
271 uint32_t sh_type = EGET(shdr[s].sh_type); \
272 if (sh_type == SHT_REL) { \
273 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
274 rela = NULL; \
275 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
276 } else if (sh_type == SHT_RELA) { \
277 rel = NULL; \
278 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
279 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
280 } else \
281 continue; \
282 /* search the program headers for PT_LOAD headers */ \
283 for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
284 Elf ## B ## _Addr vaddr; \
285 uint ## B ## _t memsz; \
286 if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
287 if (EGET(phdr[p].p_flags) & PF_W) continue; \
288 vaddr = EGET(phdr[p].p_vaddr); \
289 memsz = EGET(phdr[p].p_memsz); \
290 /* now see if any of the relocs are in the PT_LOAD */ \
291 for (r = 0; r < rmax; ++r) { \
292 unsigned long sym_max; \
293 Elf ## B ## _Addr offset_tmp; \
294 Elf ## B ## _Sym *func; \
295 Elf ## B ## _Sym *sym; \
296 Elf ## B ## _Addr r_offset; \
297 uint ## B ## _t r_info; \
298 if (sh_type == SHT_REL) { \
299 r_offset = EGET(rel[r].r_offset); \
300 r_info = EGET(rel[r].r_info); \
301 } else { \
302 r_offset = EGET(rela[r].r_offset); \
303 r_info = EGET(rela[r].r_info); \
304 } \
305 /* make sure this relocation is inside of the .text */ \
306 if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \
307 *found_textrels = 1; \
308 /* locate this relocation symbol name */ \
309 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
310 sym_max = ELF ## B ## _R_SYM(r_info); \
311 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
312 sym += sym_max; \
313 else \
314 sym = NULL; \
315 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
316 /* show the raw details about this reloc */ \
317 printf("\tTEXTREL %s: ", elf->base_filename); \
318 if (sym && sym->st_name) \
319 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
320 else \
321 printf("(NULL: fake?)"); \
322 printf(" [0x%lX]", (unsigned long)r_offset); \
323 /* now try to find the closest symbol that this rel is probably in */ \
324 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
325 func = NULL; \
326 offset_tmp = 0; \
327 while (sym_max--) { \
328 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
329 func = sym; \
330 offset_tmp = EGET(sym->st_value); \
331 } \
332 ++sym; \
333 } \
334 printf(" in "); \
335 if (func && func->st_name) \
336 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
337 else \
338 printf("(NULL: fake?)"); \
339 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
340 } \
341 } \
342 } }
343 SHOW_TEXTRELS(32)
344 SHOW_TEXTRELS(64)
345 }
346
347 return NULL;
158} 348}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 349static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 350{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 351 unsigned long i, s;
162 int i;
163 char *rpath, *runpath; 352 char *rpath, *runpath, **r;
164 void *strtbl_void; 353 void *strtbl_void;
165 354
166 if (!show_rpath) return; 355 if (!show_rpath) return;
167 356
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 357 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 358 rpath = runpath = NULL;
170 359
171 if (strtbl_void) { 360 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 361#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 362 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 363 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 364 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 365 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 366 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
367 Elf ## B ## _Off offset; \
368 Elf ## B ## _Xword word; \
369 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 370 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
371 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 372 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
373 offset = EGET(phdr[i].p_offset); \
374 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
375 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 376 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 377 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 378 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 379 r = &rpath; \
380 } else if (word == DT_RUNPATH) { \
381 r = &runpath; \
382 } else { \
383 ++dyn; \
384 continue; \
385 } \
386 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 387 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
388 if (offset < (Elf ## B ## _Off)elf->len) { \
389 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
390 *r = (char*)(elf->data + offset); \
391 /* If quiet, don't output paths in ld.so.conf */ \
392 if (be_quiet) { \
393 size_t len; \
394 char *start, *end; \
395 /* note that we only 'chop' off leading known paths. */ \
396 /* since *r is read-only memory, we can only move the ptr forward. */ \
397 start = *r; \
398 /* scan each path in : delimited list */ \
399 while (start) { \
400 end = strchr(start, ':'); \
401 len = (end ? abs(end - start) : strlen(start)); \
402 for (s = 0; ldpaths[s]; ++s) { \
403 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
404 *r = (end ? end + 1 : NULL); \
405 break; \
406 } \
407 } \
408 if (!*r || !ldpaths[s] || !end) \
409 start = NULL; \
410 else \
411 start = start + len + 1; \
412 } \
413 } \
185 *found_rpath = 1; \ 414 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 415 } \
191 ++dyn; \ 416 ++dyn; \
192 } \ 417 } \
193 } } 418 } }
194 SHOW_RPATH(32) 419 SHOW_RPATH(32)
195 SHOW_RPATH(64) 420 SHOW_RPATH(64)
196 } 421 }
422
423 if (be_wewy_wewy_quiet) return;
197 424
198 if (rpath && runpath) { 425 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) { 426 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len); 427 xstrcat(ret, runpath, ret_len);
201 } else { 428 } else {
209 } else if (rpath || runpath) 436 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 437 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet) 438 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 439 xstrcat(ret, " - ", ret_len);
213} 440}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 441static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
215{ 442{
216 int i; 443 unsigned long i;
217 char *needed; 444 char *needed;
218 void *strtbl_void; 445 void *strtbl_void;
219 446
220 if (!show_needed) return; 447 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
221 448
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 449 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 450
224 if (strtbl_void) { 451 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 452#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 453 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 454 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 455 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 456 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 457 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
458 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 459 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 460 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
461 offset = EGET(phdr[i].p_offset); \
462 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 463 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 464 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 465 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 466 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
467 if (offset >= (Elf ## B ## _Off)elf->len) { \
468 ++dyn; \
469 continue; \
470 } \
471 needed = (char*)(elf->data + offset); \
472 if (op == 0) { \
473 if (!be_wewy_wewy_quiet) { \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 474 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 475 xstrcat(ret, needed, ret_len); \
476 } \
239 *found_needed = 1; \ 477 *found_needed = 1; \
478 } else { \
479 if (strcmp(find_lib, needed)) return NULL; \
480 *found_lib = 1; \
481 return (be_wewy_wewy_quiet ? NULL : find_lib); \
482 } \
240 } \ 483 } \
241 ++dyn; \ 484 ++dyn; \
242 } \ 485 } \
243 } } 486 } }
244 SHOW_NEEDED(32) 487 SHOW_NEEDED(32)
245 SHOW_NEEDED(64) 488 SHOW_NEEDED(64)
246 } 489 }
490
491 return NULL;
247} 492}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp) 493static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{ 494{
250 void *strtbl_void; 495 void *strtbl_void;
251 496
256 if (strtbl_void) { 501 if (strtbl_void) {
257#define SHOW_INTERP(B) \ 502#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \ 503 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 504 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \ 505 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \ 506 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 507 }
263 SHOW_INTERP(32) 508 SHOW_INTERP(32)
264 SHOW_INTERP(64) 509 SHOW_INTERP(64)
265 } 510 }
266 return NULL; 511 return NULL;
267} 512}
513static char *scanelf_file_bind(elfobj *elf, char *found_bind)
514{
515 unsigned long i;
516 struct stat s;
517
518 if (!show_bind) return NULL;
519 if (!elf->phdr) return NULL;
520
521#define SHOW_BIND(B) \
522 if (elf->elf_class == ELFCLASS ## B) { \
523 Elf ## B ## _Dyn *dyn; \
524 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
525 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
526 Elf ## B ## _Off offset; \
527 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
528 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
529 offset = EGET(phdr[i].p_offset); \
530 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
531 dyn = DYN ## B (elf->data + offset); \
532 while (EGET(dyn->d_tag) != DT_NULL) { \
533 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
534 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
535 { \
536 if (be_quiet) return NULL; \
537 *found_bind = 1; \
538 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
539 } \
540 ++dyn; \
541 } \
542 } \
543 }
544 SHOW_BIND(32)
545 SHOW_BIND(64)
546
547 if (be_wewy_wewy_quiet) return NULL;
548
549 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
550 return NULL;
551 } else {
552 *found_bind = 1;
553 return (char *) "LAZY";
554 }
555}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 556static char *scanelf_file_sym(elfobj *elf, char *found_sym)
269{ 557{
270 int i; 558 unsigned long i;
271 void *symtab_void, *strtab_void; 559 void *symtab_void, *strtab_void;
272 560
273 if (!find_sym) return NULL; 561 if (!find_sym) return NULL;
274 562
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 563 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 strtab_void = elf_findsecbyname(elf, ".strtab");
277 564
278 if (symtab_void && strtab_void) { 565 if (symtab_void && strtab_void) {
279#define FIND_SYM(B) \ 566#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 567 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 568 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 569 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 570 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 571 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 572 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 573 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 574 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 575 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 576 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 577 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 578 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 579 elf->base_filename, \
293 (long)sym->st_size, \ 580 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 581 (char *)get_elfstttype(sym->st_info), \
295 symname); \ 582 symname); \
296 *found_sym = 1; \ 583 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \ 584 } else if ((strcmp(find_sym, symname) == 0) || \
301 ++sym; \ 588 ++sym; \
302 } } 589 } }
303 FIND_SYM(32) 590 FIND_SYM(32)
304 FIND_SYM(64) 591 FIND_SYM(64)
305 } 592 }
593
594 if (be_wewy_wewy_quiet) return NULL;
595
306 if (*find_sym != '*' && *found_sym) 596 if (*find_sym != '*' && *found_sym)
307 return find_sym; 597 return find_sym;
308 if (be_quiet) 598 if (be_quiet)
309 return NULL; 599 return NULL;
310 else 600 else
311 return " - "; 601 return (char *)" - ";
312} 602}
313/* scan an elf file and show all the fun stuff */ 603/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 604#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 605static void scanelf_file(const char *filename)
316{ 606{
317 int i; 607 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 608 char found_pax, found_phdr, found_relro, found_load, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 609 found_rpath, found_needed, found_interp, found_bind,
320 found_file; 610 found_sym, found_lib, found_file, found_textrels;
321 elfobj *elf; 611 elfobj *elf;
322 struct stat st; 612 struct stat st;
323 static char *out_buffer = NULL; 613 static char *out_buffer = NULL;
324 static size_t out_len; 614 static size_t out_len;
325 615
327 if (lstat(filename, &st) == -1) { 617 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 618 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 619 return;
330 } 620 }
331 /* always handle regular files and handle symlinked files if no -y */ 621 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 622 if (S_ISLNK(st.st_mode)) {
623 if (!scan_symlink) return;
624 stat(filename, &st);
625 }
626 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 627 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 628 return;
335 } 629 }
336 630
337 found_pax = found_stack = found_relro = found_textrel = \ 631 found_pax = found_phdr = found_relro = found_load = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 632 found_rpath = found_needed = found_interp = found_bind = \
339 found_file = 0; 633 found_sym = found_lib = found_file = found_textrels = 0;
340 634
341 /* verify this is real ELF */ 635 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 636 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 637 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 638 return;
345 } 639 }
346 640
347 if (be_verbose > 1) 641 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename, 642 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class), 643 get_elfeitype(EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 644 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose) 645 else if (be_verbose)
352 printf("%s: scanning file\n", filename); 646 printf("%s: scanning file\n", filename);
353 647
354 /* init output buffer */ 648 /* init output buffer */
355 if (!out_buffer) { 649 if (!out_buffer) {
358 } 652 }
359 *out_buffer = '\0'; 653 *out_buffer = '\0';
360 654
361 /* show the header */ 655 /* show the header */
362 if (!be_quiet && show_banner) { 656 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 657 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 658 if (!IS_MODIFIER(out_format[i])) continue;
365 659
366 switch (out_format[++i]) { 660 switch (out_format[++i]) {
367 case '%': break; 661 case '%': break;
662 case '#': break;
663 case 'F':
664 case 'p':
368 case 'F': prints("FILE "); break; 665 case 'f': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 666 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 667 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 668 case 'e': prints("STK/REL/PTL "); break;
372 case 't': prints("TEXTREL "); break; 669 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 670 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 671 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 672 case 'i': prints("INTERP "); break;
673 case 'b': prints("BIND "); break;
376 case 's': prints("SYM "); break; 674 case 's': prints("SYM "); break;
675 case 'N': prints("LIB "); break;
676 case 'T': prints("TEXTRELS "); break;
677 default: warnf("'%c' has no title ?", out_format[i]);
377 } 678 }
378 } 679 }
680 if (!found_file) prints("FILE ");
379 prints("\n"); 681 prints("\n");
682 found_file = 0;
380 show_banner = 0; 683 show_banner = 0;
381 } 684 }
382 685
383 /* dump all the good stuff */ 686 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 687 for (i = 0; out_format[i]; ++i) {
385 const char *out; 688 const char *out;
689 const char *tmp;
386 690
387 /* make sure we trim leading spaces in quiet mode */ 691 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 692 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 693 *out_buffer = '\0';
390 694
391 if (out_format[i] != '%') { 695 if (!IS_MODIFIER(out_format[i])) {
392 xchrcat(&out_buffer, out_format[i], &out_len); 696 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue; 697 continue;
394 } 698 }
395 699
396 out = NULL; 700 out = NULL;
701 be_wewy_wewy_quiet = (out_format[i] == '#');
397 switch (out_format[++i]) { 702 switch (out_format[++i]) {
703 case '%':
704 case '#':
398 case '%': xchrcat(&out_buffer, '%', &out_len); break; 705 xchrcat(&out_buffer, out_format[i], &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 706 case 'F':
707 found_file = 1;
708 if (be_wewy_wewy_quiet) break;
709 xstrcat(&out_buffer, filename, &out_len);
710 break;
711 case 'p':
712 found_file = 1;
713 if (be_wewy_wewy_quiet) break;
714 tmp = filename;
715 if (search_path) {
716 ssize_t len_search = strlen(search_path);
717 ssize_t len_file = strlen(filename);
718 if (!strncmp(filename, search_path, len_search) && \
719 len_file > len_search)
720 tmp += len_search;
721 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
722 }
723 xstrcat(&out_buffer, tmp, &out_len);
724 break;
725 case 'f':
726 found_file = 1;
727 if (be_wewy_wewy_quiet) break;
728 tmp = strrchr(filename, '/');
729 tmp = (tmp == NULL ? filename : tmp+1);
730 xstrcat(&out_buffer, tmp, &out_len);
731 break;
400 case 'o': out = get_elfetype(elf); break; 732 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 733 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 734 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 735 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
736 case 'T': out = scanelf_file_textrels(elf, &found_textrels); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 737 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
738 case 'n':
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 739 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 740 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
741 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 742 case 's': out = scanelf_file_sym(elf, &found_sym); break;
743 default: warnf("'%c' has no scan code?", out_format[i]);
408 } 744 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 745 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 746 }
411 747
412 if (!found_file) { 748#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 749 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 750 found_rpath || found_needed || found_interp || found_bind || \
751 found_sym || found_lib || found_textrels)
752
753 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
754 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 755 xstrcat(&out_buffer, filename, &out_len);
416 } 756 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 757 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
418 puts(out_buffer); 758 puts(out_buffer);
419 759
420 unreadelf(elf); 760 unreadelf(elf);
421} 761}
422 762
452 while ((dentry = readdir(dir))) { 792 while ((dentry = readdir(dir))) {
453 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 793 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
454 continue; 794 continue;
455 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 795 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
456 if (len >= sizeof(buf)) { 796 if (len >= sizeof(buf)) {
457 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 797 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
798 (unsigned long)len, (unsigned long)sizeof(buf));
458 continue; 799 continue;
459 } 800 }
460 sprintf(buf, "%s/%s", path, dentry->d_name); 801 sprintf(buf, "%s/%s", path, dentry->d_name);
461 if (lstat(buf, &st) != -1) { 802 if (lstat(buf, &st) != -1) {
462 if (S_ISREG(st.st_mode)) 803 if (S_ISREG(st.st_mode))
468 } 809 }
469 } 810 }
470 closedir(dir); 811 closedir(dir);
471} 812}
472 813
814static int scanelf_from_file(char *filename)
815{
816 FILE *fp = NULL;
817 char *p;
818 char path[_POSIX_PATH_MAX];
819
820 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
821 fp = stdin;
822 else if ((fp = fopen(filename, "r")) == NULL)
823 return 1;
824
825 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
826 if ((p = strchr(path, '\n')) != NULL)
827 *p = 0;
828 search_path = path;
829 scanelf_dir(path);
830 }
831 if (fp != stdin)
832 fclose(fp);
833 return 0;
834}
835
836static void load_ld_so_conf()
837{
838 FILE *fp = NULL;
839 char *p;
840 char path[_POSIX_PATH_MAX];
841 int i = 0;
842
843 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
844 return;
845
846 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
847 if (*path != '/')
848 continue;
849
850 if ((p = strrchr(path, '\r')) != NULL)
851 *p = 0;
852 if ((p = strchr(path, '\n')) != NULL)
853 *p = 0;
854
855 ldpaths[i++] = xstrdup(path);
856
857 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
858 break;
859 }
860 ldpaths[i] = NULL;
861
862 fclose(fp);
863}
864
473/* scan /etc/ld.so.conf for paths */ 865/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 866static void scanelf_ldpath()
475{ 867{
476 char scan_l, scan_ul, scan_ull; 868 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 869 int i = 0;
478 FILE *fp;
479 870
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 871 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 872 err("Unable to load any paths from ld.so.conf");
482 873
483 scan_l = scan_ul = scan_ull = 0; 874 scan_l = scan_ul = scan_ull = 0;
484 875
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 876 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 877 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 878 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 879 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 880 scanelf_dir(ldpaths[i]);
881 ++i;
496 } 882 }
497 free(path);
498 fclose(fp);
499 883
500 if (!scan_l) scanelf_dir("/lib"); 884 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 885 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 886 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 887}
521} 905}
522 906
523 907
524 908
525/* usage / invocation handling functions */ 909/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 910#define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV"
527#define a_argument required_argument 911#define a_argument required_argument
528static struct option const long_opts[] = { 912static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 913 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 914 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 915 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 919 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 920 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 921 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 922 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 923 {"interp", no_argument, NULL, 'i'},
924 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 925 {"symbol", a_argument, NULL, 's'},
926 {"lib", a_argument, NULL, 'N'},
927 {"textrels", no_argument, NULL, 'T'},
541 {"all", no_argument, NULL, 'a'}, 928 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 929 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 930 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 931 {"format", a_argument, NULL, 'F'},
932 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 933 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 934 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 935 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 936 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 937 {NULL, no_argument, NULL, 0x0}
550}; 938};
939
551static char *opts_help[] = { 940static const char *opts_help[] = {
552 "Scan all directories in PATH environment", 941 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 942 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 943 "Scan directories recursively",
555 "Don't recursively cross mount points", 944 "Don't recursively cross mount points",
556 "Don't scan symlinks\n", 945 "Don't scan symlinks\n",
557 "Print PaX markings", 946 "Print PaX markings",
558 "Print GNU_STACK markings", 947 "Print GNU_STACK/PT_LOAD markings",
559 "Print TEXTREL information", 948 "Print TEXTREL information",
560 "Print RPATH information", 949 "Print RPATH information",
561 "Print NEEDED information", 950 "Print NEEDED information",
562 "Print INTERP information", 951 "Print INTERP information",
952 "Print BIND information",
563 "Find a specified symbol", 953 "Find a specified symbol",
954 "Find a specified library",
955 "Locate cause of TEXTREL",
564 "Print all scanned info (-x -e -t -r)\n", 956 "Print all scanned info (-x -e -t -r -n -i -b)\n",
565 "Only output 'bad' things", 957 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 958 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 959 "Use specified format for output",
960 "Read input stream from a filename",
568 "Write output stream to a filename", 961 "Write output stream to a filename",
569 "Don't display the header", 962 "Don't display the header",
570 "Print this help and exit", 963 "Print this help and exit",
571 "Print version and exit", 964 "Print version and exit",
572 NULL 965 NULL
573}; 966};
574 967
575/* display usage and exit */ 968/* display usage and exit */
576static void usage(int status) 969static void usage(int status)
577{ 970{
578 int i; 971 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 972 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 973 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 974 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 975 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 976 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 977 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 978 long_opts[i].name, opts_help[i]);
586 else 979 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 980 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 981 long_opts[i].name, opts_help[i]);
982
983 if (status != EXIT_SUCCESS)
984 exit(status);
985
986 puts("\nThe format modifiers for the -F option are:");
987 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
988 puts(" t TEXTREL \tr RPATH \tn NEEDED");
989 puts(" i INTERP \tb BIND \ts symbol");
990 puts(" N library \to Type \tT TEXTRELs");
991 puts(" p filename (with search path removed)");
992 puts(" f base filename");
993 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
994
589 exit(status); 995 exit(status);
590} 996}
591 997
592/* parse command line arguments and preform needed actions */ 998/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 999static void parseargs(int argc, char *argv[])
594{ 1000{
595 int flag; 1001 int i;
1002 char *from_file = NULL;
596 1003
597 opterr = 0; 1004 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1005 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 1006 switch (i) {
600 1007
601 case 'V': 1008 case 'V':
602 printf("%s compiled %s\n%s\n" 1009 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1010 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 1011 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 1012 exit(EXIT_SUCCESS);
606 break; 1013 break;
607 case 'h': usage(EXIT_SUCCESS); break; 1014 case 'h': usage(EXIT_SUCCESS); break;
608 1015 case 'f':
1016 if (from_file) err("Don't specify -f twice");
1017 from_file = xstrdup(optarg);
1018 break;
609 case 'o': { 1019 case 'o': {
610 FILE *fp = NULL; 1020 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 1021 if ((fp = freopen(optarg, "w", stdout)) == NULL)
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1022 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp; 1023 SET_STDOUT(fp);
615 break; 1024 break;
616 } 1025 }
617 1026
618 case 's': { 1027 case 's': {
619 size_t len; 1028 size_t len;
1029 if (find_sym) err("Don't specify -s twice");
620 find_sym = xstrdup(optarg); 1030 find_sym = xstrdup(optarg);
621 len = strlen(find_sym) + 1; 1031 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1032 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
623 sprintf(versioned_symname, "%s@", find_sym); 1033 sprintf(versioned_symname, "%s@", find_sym);
624 break; 1034 break;
625 } 1035 }
1036 case 'N': {
1037 if (find_lib) err("Don't specify -N twice");
1038 find_lib = xstrdup(optarg);
1039 break;
1040 }
626 1041
627 case 'F': { 1042 case 'F': {
1043 if (out_format) err("Don't specify -F twice");
628 out_format = strdup(optarg); 1044 out_format = xstrdup(optarg);
629 break; 1045 break;
630 } 1046 }
631 1047
632 case 'y': scan_symlink = 0; break; 1048 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 1049 case 'B': show_banner = 0; break;
634 case 'l': scan_ldpath = 1; break; 1050 case 'l': scan_ldpath = 1; break;
635 case 'p': scan_envpath = 1; break; 1051 case 'p': scan_envpath = 1; break;
636 case 'R': dir_recurse = 1; break; 1052 case 'R': dir_recurse = 1; break;
637 case 'm': dir_crossmount = 0; break; 1053 case 'm': dir_crossmount = 0; break;
638 case 'x': show_pax = 1; break; 1054 case 'x': show_pax = 1; break;
639 case 'e': show_stack = 1; break; 1055 case 'e': show_phdr = 1; break;
640 case 't': show_textrel = 1; break; 1056 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 1057 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 1058 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 1059 case 'i': show_interp = 1; break;
1060 case 'b': show_bind = 1; break;
1061 case 'T': show_textrels = 1; break;
644 case 'q': be_quiet = 1; break; 1062 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1063 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 1064 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \
1065 show_needed = show_interp = show_bind = 1; break;
647 1066
648 case ':': 1067 case ':':
649 warn("Option missing parameter\n"); 1068 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 1069 case '?':
653 warn("Unknown option\n"); 1070 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 1071 default:
657 err("Unhandled option '%c'", flag); 1072 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 1073 }
661 1074 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 1075
665 /* let the format option override all other options */ 1076 /* let the format option override all other options */
666 if (out_format) { 1077 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 1078 show_pax = show_phdr = show_textrel = show_rpath = \
1079 show_needed = show_interp = show_bind = show_textrels = 0;
668 for (flag=0; out_format[flag]; ++flag) { 1080 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 1081 if (!IS_MODIFIER(out_format[i])) continue;
670 1082
671 switch (out_format[++flag]) { 1083 switch (out_format[++i]) {
672 case '%': break; 1084 case '%': break;
1085 case '#': break;
673 case 'F': break; 1086 case 'F': break;
1087 case 'p': break;
1088 case 'f': break;
674 case 's': break; 1089 case 's': break;
1090 case 'N': break;
675 case 'o': break; 1091 case 'o': break;
676 case 'x': show_pax = 1; break; 1092 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 1093 case 'e': show_phdr = 1; break;
678 case 't': show_textrel = 1; break; 1094 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 1095 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 1096 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 1097 case 'i': show_interp = 1; break;
1098 case 'b': show_bind = 1; break;
1099 case 'T': show_textrels = 1; break;
682 default: 1100 default:
683 err("Invalid format specifier '%c' (byte %i)", 1101 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 1102 out_format[i], i+1);
685 } 1103 }
686 } 1104 }
687 1105
688 /* construct our default format */ 1106 /* construct our default format */
689 } else { 1107 } else {
690 size_t fmt_len = 30; 1108 size_t fmt_len = 30;
691 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1109 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
692 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1110 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
693 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1111 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1112 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1113 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1114 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1115 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1116 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1117 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1118 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1119 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1120 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1121 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 1122 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 1123 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 1124
704 /* now lets actually do the scanning */ 1125 /* now lets actually do the scanning */
1126 if (scan_ldpath || (show_rpath && be_quiet))
1127 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 1128 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 1129 if (scan_envpath) scanelf_envpath();
1130 if (from_file) {
1131 scanelf_from_file(from_file);
1132 free(from_file);
1133 from_file = *argv;
1134 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 1135 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 1136 err("Nothing to scan !?");
709 while (optind < argc) 1137 while (optind < argc) {
710 scanelf_dir(argv[optind++]); 1138 search_path = argv[optind++];
1139 scanelf_dir(search_path);
1140 }
711 1141
712 /* clean up */ 1142 /* clean up */
713 if (find_sym) { 1143 if (find_sym) {
714 free(find_sym); 1144 free(find_sym);
715 free(versioned_symname); 1145 free(versioned_symname);
716 } 1146 }
1147 if (find_lib) free(find_lib);
717 if (out_format) free(out_format); 1148 if (out_format) free(out_format);
1149 for (i = 0; ldpaths[i]; ++i)
1150 free(ldpaths[i]);
718} 1151}
719 1152
720 1153
721 1154
722/* utility funcs */ 1155/* utility funcs */
723static char *xstrdup(char *s) 1156static char *xstrdup(const char *s)
724{ 1157{
725 char *ret = strdup(s); 1158 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1159 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 1160 return ret;
728} 1161}
1162
729static void *xmalloc(size_t size) 1163static void *xmalloc(size_t size)
730{ 1164{
731 void *ret = malloc(size); 1165 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1166 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 1167 return ret;
734} 1168}
1169
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 1170static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 1171{
737 long new_len; 1172 size_t new_len;
738 1173
739 new_len = strlen(*dst) + strlen(src); 1174 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) { 1175 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2); 1176 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len); 1177 *dst = realloc(*dst, *curr_len);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 1179 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 1180 }
746 1181
747 strcat(*dst, src); 1182 strcat(*dst, src);
748} 1183}
1184
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1185static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 1186{
751 static char my_app[2]; 1187 static char my_app[2];
752 my_app[0] = append; 1188 my_app[0] = append;
753 my_app[1] = '\0'; 1189 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 1190 xstrcat(dst, my_app, curr_len);
755} 1191}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764 1192
765 1193
766 1194
767int main(int argc, char *argv[]) 1195int main(int argc, char *argv[])
768{ 1196{
769 if (argc < 2) 1197 if (argc < 2)
770 usage(EXIT_FAILURE); 1198 usage(EXIT_FAILURE);
771 parseargs(argc, argv); 1199 parseargs(argc, argv);
772 fclose(stdout); 1200 fclose(stdout);
1201#ifdef __BOUNDS_CHECKING_ON
1202 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1203#endif
773 return EXIT_SUCCESS; 1204 return EXIT_SUCCESS;
774} 1205}

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

  ViewVC Help
Powered by ViewVC 1.1.20