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

Legend:
Removed from v.1.61  
changed lines
  Added in v.1.92

  ViewVC Help
Powered by ViewVC 1.1.20