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

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

  ViewVC Help
Powered by ViewVC 1.1.20