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

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

  ViewVC Help
Powered by ViewVC 1.1.20