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

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

  ViewVC Help
Powered by ViewVC 1.1.20