/[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.97
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.97 2005/12/29 14:03:25 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org>
8 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org>
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 * MA 02111-1307, USA.
22 */ 8 */
23 9
24#include <stdio.h> 10#include <stdio.h>
25#include <stdlib.h> 11#include <stdlib.h>
26#include <sys/types.h> 12#include <sys/types.h>
27#include <libgen.h> 13#include <libgen.h>
28#include <limits.h> 14#include <limits.h>
29#define __USE_GNU
30#include <string.h> 15#include <string.h>
31#include <errno.h> 16#include <errno.h>
32#include <unistd.h> 17#include <unistd.h>
33#include <sys/stat.h> 18#include <sys/stat.h>
19#include <sys/mman.h>
20#include <fcntl.h>
34#include <dirent.h> 21#include <dirent.h>
35#include <getopt.h> 22#include <getopt.h>
36#include <assert.h> 23#include <assert.h>
37#include "paxelf.h" 24#include "paxinc.h"
38 25
39static const char *rcsid = "$Id: scanelf.c,v 1.61 2005/05/28 22:09:36 solar Exp $"; 26static const char *rcsid = "$Id: scanelf.c,v 1.97 2005/12/29 14:03:25 vapier Exp $";
40#define argv0 "scanelf" 27#define argv0 "scanelf"
28
29#define IS_MODIFIER(c) (c == '%' || c == '#')
41 30
42 31
43 32
44/* prototypes */ 33/* prototypes */
45static void scanelf_file(const char *filename); 34static void scanelf_file(const char *filename);
48static void scanelf_envpath(); 37static void scanelf_envpath();
49static void usage(int status); 38static void usage(int status);
50static void parseargs(int argc, char *argv[]); 39static void parseargs(int argc, char *argv[]);
51static char *xstrdup(const char *s); 40static char *xstrdup(const char *s);
52static void *xmalloc(size_t size); 41static void *xmalloc(size_t size);
53static void xstrcat(char **dst, const char *src, size_t *curr_len); 42static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
43#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
54static inline void xchrcat(char **dst, const char append, size_t *curr_len); 44static inline void xchrcat(char **dst, const char append, size_t *curr_len);
55 45
56/* variables to control behavior */ 46/* variables to control behavior */
57static char *ldpaths[256]; 47static char *ldpaths[256];
58static char scan_ldpath = 0; 48static char scan_ldpath = 0;
59static char scan_envpath = 0; 49static char scan_envpath = 0;
60static char scan_symlink = 1; 50static char scan_symlink = 1;
61static char dir_recurse = 0; 51static char dir_recurse = 0;
62static char dir_crossmount = 1; 52static char dir_crossmount = 1;
63static char show_pax = 0; 53static char show_pax = 0;
64static char show_stack = 0; 54static char show_phdr = 0;
65static char show_textrel = 0; 55static char show_textrel = 0;
66static char show_rpath = 0; 56static char show_rpath = 0;
67static char show_needed = 0; 57static char show_needed = 0;
68static char show_interp = 0; 58static char show_interp = 0;
69static char show_bind = 0; 59static char show_bind = 0;
60static char show_soname = 0;
61static char show_textrels = 0;
70static char show_banner = 1; 62static char show_banner = 1;
71static char be_quiet = 0; 63static char be_quiet = 0;
72static char be_verbose = 0; 64static char be_verbose = 0;
65static char be_wewy_wewy_quiet = 0;
73static char *find_sym = NULL, *versioned_symname = NULL; 66static char *find_sym = NULL, *versioned_symname = NULL;
67static char *find_lib = NULL;
74static char *out_format = NULL; 68static char *out_format = NULL;
69static char *search_path = NULL;
70static char gmatch = 0;
71static char printcache = 0;
75 72
73
74caddr_t ldcache = 0;
75size_t ldcache_size = 0;
76 76
77/* sub-funcs for scanelf_file() */ 77/* sub-funcs for scanelf_file() */
78static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
79{
80 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
81#define GET_SYMTABS(B) \
82 if (elf->elf_class == ELFCLASS ## B) { \
83 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
84 /* debug sections */ \
85 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
86 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
87 /* runtime sections */ \
88 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
89 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
90 if (symtab && dynsym) { \
91 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
92 } else { \
93 *sym = (void*)(symtab ? symtab : dynsym); \
94 } \
95 if (strtab && dynstr) { \
96 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
97 } else { \
98 *tab = (void*)(strtab ? strtab : dynstr); \
99 } \
100 }
101 GET_SYMTABS(32)
102 GET_SYMTABS(64)
103}
78static char *scanelf_file_pax(elfobj *elf, char *found_pax) 104static char *scanelf_file_pax(elfobj *elf, char *found_pax)
79{ 105{
80 static char *paxflags;
81 static char ret[7]; 106 static char ret[7];
82 unsigned long i, shown; 107 unsigned long i, shown;
83
84 108
85 if (!show_pax) return NULL; 109 if (!show_pax) return NULL;
86 110
87 shown = 0; 111 shown = 0;
88 memset(&ret, 0, sizeof(ret)); 112 memset(&ret, 0, sizeof(ret));
107 SHOW_PAX(64) 131 SHOW_PAX(64)
108 } 132 }
109 133
110 /* fall back to EI_PAX if no PT_PAX was found */ 134 /* fall back to EI_PAX if no PT_PAX was found */
111 if (!*ret) { 135 if (!*ret) {
136 static char *paxflags;
112 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 137 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
113 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 138 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
114 *found_pax = 1; 139 *found_pax = 1;
115 return paxflags; 140 return (be_wewy_wewy_quiet ? NULL : paxflags);
116 } 141 }
117 strncpy(ret, paxflags, sizeof(ret)); 142 strncpy(ret, paxflags, sizeof(ret));
118 // ++shown;
119 } 143 }
120 144
121 if (be_quiet && !shown) 145 if (be_wewy_wewy_quiet || (be_quiet && !shown))
122 return NULL;
123 return ret;
124
125}
126static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
127{
128 static char ret[8] = "--- ---";
129 char *found;
130 unsigned long i, off, shown;
131
132 if (!show_stack) return NULL;
133
134 shown = 0;
135
136 if (elf->phdr) {
137#define SHOW_STACK(B) \
138 if (elf->elf_class == ELFCLASS ## B) { \
139 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
140 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
141 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
142 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
143 found = found_stack; \
144 off = 0; \
145 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
146 found = found_relro; \
147 off = 4; \
148 } else \
149 continue; \
150 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
151 continue; \
152 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
153 *found = 1; \
154 ++shown; \
155 } \
156 }
157 SHOW_STACK(32)
158 SHOW_STACK(64)
159 }
160
161 if (be_quiet && !shown)
162 return NULL; 146 return NULL;
163 else 147 else
164 return ret; 148 return ret;
165} 149}
150
151static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
152{
153 static char ret[12];
154 char *found;
155 unsigned long i, shown;
156 unsigned char multi_stack, multi_relro, multi_load;
157
158 if (!show_phdr) return NULL;
159
160 memcpy(ret, "--- --- ---\0", 12);
161
162 shown = 0;
163 multi_stack = multi_relro = multi_load = 0;
164
165#define SHOW_PHDR(B) \
166 if (elf->elf_class == ELFCLASS ## B) { \
167 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
168 Elf ## B ## _Off offset; \
169 uint32_t flags, check_flags; \
170 if (elf->phdr != NULL) { \
171 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
172 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
173 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
174 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
175 found = found_phdr; \
176 offset = 0; \
177 check_flags = PF_X; \
178 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
179 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
180 found = found_relro; \
181 offset = 4; \
182 check_flags = PF_X; \
183 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
184 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
185 found = found_load; \
186 offset = 8; \
187 check_flags = PF_W|PF_X; \
188 } else \
189 continue; \
190 flags = EGET(phdr[i].p_flags); \
191 if (be_quiet && ((flags & check_flags) != check_flags)) \
192 continue; \
193 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
194 *found = 1; \
195 ++shown; \
196 } \
197 } else if (elf->shdr != NULL) { \
198 /* no program headers which means this is prob an object file */ \
199 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
200 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
201 check_flags = SHF_WRITE|SHF_EXECINSTR; \
202 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
203 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
204 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
205 if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \
206 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
207 flags = EGET(shdr[i].sh_flags); \
208 if (be_quiet && ((flags & check_flags) != check_flags)) \
209 continue; \
210 ++*found_phdr; \
211 shown = 1; \
212 if (flags & SHF_WRITE) ret[0] = 'W'; \
213 if (flags & SHF_ALLOC) ret[1] = 'A'; \
214 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
215 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
216 break; \
217 } \
218 } \
219 if (!multi_stack) { \
220 *found_phdr = 1; \
221 shown = 1; \
222 memcpy(ret, "!WX", 3); \
223 } \
224 } \
225 }
226 SHOW_PHDR(32)
227 SHOW_PHDR(64)
228
229 if (be_wewy_wewy_quiet || (be_quiet && !shown))
230 return NULL;
231 else
232 return ret;
233}
166static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 234static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
167{ 235{
168 static char *ret = "TEXTREL"; 236 static const char *ret = "TEXTREL";
169 unsigned long i; 237 unsigned long i;
170 238
171 if (!show_textrel) return NULL; 239 if (!show_textrel && !show_textrels) return NULL;
172 240
173 if (elf->phdr) { 241 if (elf->phdr) {
174#define SHOW_TEXTREL(B) \ 242#define SHOW_TEXTREL(B) \
175 if (elf->elf_class == ELFCLASS ## B) { \ 243 if (elf->elf_class == ELFCLASS ## B) { \
176 Elf ## B ## _Dyn *dyn; \ 244 Elf ## B ## _Dyn *dyn; \
184 dyn = DYN ## B (elf->data + offset); \ 252 dyn = DYN ## B (elf->data + offset); \
185 while (EGET(dyn->d_tag) != DT_NULL) { \ 253 while (EGET(dyn->d_tag) != DT_NULL) { \
186 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 254 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
187 *found_textrel = 1; \ 255 *found_textrel = 1; \
188 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 256 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
189 return ret; \ 257 return (be_wewy_wewy_quiet ? NULL : ret); \
190 } \ 258 } \
191 ++dyn; \ 259 ++dyn; \
192 } \ 260 } \
193 } } 261 } }
194 SHOW_TEXTREL(32) 262 SHOW_TEXTREL(32)
195 SHOW_TEXTREL(64) 263 SHOW_TEXTREL(64)
196 } 264 }
197 265
198 if (be_quiet) 266 if (be_quiet || be_wewy_wewy_quiet)
199 return NULL; 267 return NULL;
200 else 268 else
201 return " - "; 269 return " - ";
202} 270}
271static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
272{
273 unsigned long s, r, rmax;
274 void *symtab_void, *strtab_void, *text_void;
275
276 if (!show_textrels) return NULL;
277
278 /* don't search for TEXTREL's if the ELF doesn't have any */
279 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
280 if (!*found_textrel) return NULL;
281
282 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
283 text_void = elf_findsecbyname(elf, ".text");
284
285 if (symtab_void && strtab_void && text_void && elf->shdr) {
286#define SHOW_TEXTRELS(B) \
287 if (elf->elf_class == ELFCLASS ## B) { \
288 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
289 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
290 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
291 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
292 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
293 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
294 uint ## B ## _t memsz = EGET(text->sh_size); \
295 Elf ## B ## _Rel *rel; \
296 Elf ## B ## _Rela *rela; \
297 /* search the section headers for relocations */ \
298 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
299 uint32_t sh_type = EGET(shdr[s].sh_type); \
300 if (sh_type == SHT_REL) { \
301 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
302 rela = NULL; \
303 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
304 } else if (sh_type == SHT_RELA) { \
305 rel = NULL; \
306 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
307 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
308 } else \
309 continue; \
310 /* now see if any of the relocs are in the .text */ \
311 for (r = 0; r < rmax; ++r) { \
312 unsigned long sym_max; \
313 Elf ## B ## _Addr offset_tmp; \
314 Elf ## B ## _Sym *func; \
315 Elf ## B ## _Sym *sym; \
316 Elf ## B ## _Addr r_offset; \
317 uint ## B ## _t r_info; \
318 if (sh_type == SHT_REL) { \
319 r_offset = EGET(rel[r].r_offset); \
320 r_info = EGET(rel[r].r_info); \
321 } else { \
322 r_offset = EGET(rela[r].r_offset); \
323 r_info = EGET(rela[r].r_info); \
324 } \
325 /* make sure this relocation is inside of the .text */ \
326 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
327 if (be_verbose <= 2) continue; \
328 } else \
329 *found_textrels = 1; \
330 /* locate this relocation symbol name */ \
331 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
332 sym_max = ELF ## B ## _R_SYM(r_info); \
333 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
334 sym += sym_max; \
335 else \
336 sym = NULL; \
337 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
338 /* show the raw details about this reloc */ \
339 printf(" %s: ", elf->base_filename); \
340 if (sym && sym->st_name) \
341 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
342 else \
343 printf("(memory/fake?)"); \
344 printf(" [0x%lX]", (unsigned long)r_offset); \
345 /* now try to find the closest symbol that this rel is probably in */ \
346 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
347 func = NULL; \
348 offset_tmp = 0; \
349 while (sym_max--) { \
350 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
351 func = sym; \
352 offset_tmp = EGET(sym->st_value); \
353 } \
354 ++sym; \
355 } \
356 printf(" in "); \
357 if (func && func->st_name) \
358 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
359 else \
360 printf("(NULL: fake?)"); \
361 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
362 } \
363 } }
364 SHOW_TEXTRELS(32)
365 SHOW_TEXTRELS(64)
366 }
367 if (!*found_textrels)
368 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
369
370 return NULL;
371}
372
373static void rpath_security_checks(elfobj *, char *);
374static void rpath_security_checks(elfobj *elf, char *item) {
375 struct stat st;
376 switch (*item) {
377 case '/': break;
378 case '.':
379 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename);
380 break;
381 case '\0':
382 warnf("Security problem NULL RPATH in %s", elf->filename);
383 break;
384 case '$':
385 if (fstat(elf->fd, &st) != -1)
386 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
387 warnf("Security problem with RPATH='%s' in %s with mode set of %o",
388 item, elf->filename, st.st_mode & 07777);
389 break;
390 default:
391 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename);
392 break;
393 }
394}
203static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 395static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
204{ 396{
205 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
206 unsigned long i, s; 397 unsigned long i, s;
207 char *rpath, *runpath, **r; 398 char *rpath, *runpath, **r;
208 void *strtbl_void; 399 void *strtbl_void;
209 400
210 if (!show_rpath) return; 401 if (!show_rpath) return;
238 ++dyn; \ 429 ++dyn; \
239 continue; \ 430 continue; \
240 } \ 431 } \
241 /* Verify the memory is somewhat sane */ \ 432 /* Verify the memory is somewhat sane */ \
242 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 433 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
243 if (offset < elf->len) { \ 434 if (offset < (Elf ## B ## _Off)elf->len) { \
244 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 435 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
245 *r = (char*)(elf->data + offset); \ 436 *r = (char*)(elf->data + offset); \
246 /* If quiet, don't output paths in ld.so.conf */ \ 437 /* If quiet, don't output paths in ld.so.conf */ \
247 if (be_quiet) \ 438 if (be_quiet) { \
439 size_t len; \
440 char *start, *end; \
441 /* note that we only 'chop' off leading known paths. */ \
442 /* since *r is read-only memory, we can only move the ptr forward. */ \
443 start = *r; \
444 /* scan each path in : delimited list */ \
445 while (start) { \
446 rpath_security_checks(elf, start); \
447 end = strchr(start, ':'); \
448 len = (end ? abs(end - start) : strlen(start)); \
248 for (s = 0; ldpaths[s]; ++s) \ 449 for (s = 0; ldpaths[s]; ++s) { \
249 if (!strcmp(ldpaths[s], *r)) { \ 450 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
250 *r = NULL; \ 451 *r = (end ? end + 1 : NULL); \
251 break; \ 452 break; \
453 } \
252 } \ 454 } \
455 if (!*r || !ldpaths[s] || !end) \
456 start = NULL; \
457 else \
458 start = start + len + 1; \
459 } \
460 } \
253 if (*r) *found_rpath = 1; \ 461 if (*r) *found_rpath = 1; \
254 } \ 462 } \
255 ++dyn; \ 463 ++dyn; \
256 } \ 464 } \
257 } } 465 } }
258 SHOW_RPATH(32) 466 SHOW_RPATH(32)
259 SHOW_RPATH(64) 467 SHOW_RPATH(64)
260 } 468 }
469
470 if (be_wewy_wewy_quiet) return;
261 471
262 if (rpath && runpath) { 472 if (rpath && runpath) {
263 if (!strcmp(rpath, runpath)) { 473 if (!strcmp(rpath, runpath)) {
264 xstrcat(ret, runpath, ret_len); 474 xstrcat(ret, runpath, ret_len);
265 } else { 475 } else {
273 } else if (rpath || runpath) 483 } else if (rpath || runpath)
274 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 484 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
275 else if (!be_quiet) 485 else if (!be_quiet)
276 xstrcat(ret, " - ", ret_len); 486 xstrcat(ret, " - ", ret_len);
277} 487}
488
489#define LDSO_CACHE_MAGIC "ld.so-"
490#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
491#define LDSO_CACHE_VER "1.7.0"
492#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
493#define FLAG_ANY -1
494#define FLAG_TYPE_MASK 0x00ff
495#define FLAG_LIBC4 0x0000
496#define FLAG_ELF 0x0001
497#define FLAG_ELF_LIBC5 0x0002
498#define FLAG_ELF_LIBC6 0x0003
499#define FLAG_REQUIRED_MASK 0xff00
500#define FLAG_SPARC_LIB64 0x0100
501#define FLAG_IA64_LIB64 0x0200
502#define FLAG_X8664_LIB64 0x0300
503#define FLAG_S390_LIB64 0x0400
504#define FLAG_POWERPC_LIB64 0x0500
505#define FLAG_MIPS64_LIBN32 0x0600
506#define FLAG_MIPS64_LIBN64 0x0700
507
508static char *lookup_cache_lib(elfobj *, char *);
509static char *lookup_cache_lib(elfobj *elf, char *fname)
510{
511 int fd = 0;
512 char *strs;
513 static char buf[_POSIX_PATH_MAX] = "";
514 const char *cachefile = "/etc/ld.so.cache";
515 struct stat st;
516
517 typedef struct {
518 char magic[LDSO_CACHE_MAGIC_LEN];
519 char version[LDSO_CACHE_VER_LEN];
520 int nlibs;
521 } header_t;
522 header_t *header;
523
524 typedef struct {
525 int flags;
526 int sooffset;
527 int liboffset;
528 } libentry_t;
529 libentry_t *libent;
530
531 if (fname == NULL)
532 return NULL;
533
534 if (ldcache == 0) {
535 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
536 return NULL;
537
538 /* cache these values so we only map/unmap the cache file once */
539 ldcache_size = st.st_size;
540 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
541
542 close(fd);
543
544 if (ldcache == (caddr_t)-1)
545 return NULL;
546
547 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
548 return NULL;
549 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
550 return NULL;
551 }
552
553 header = (header_t *) ldcache;
554 libent = (libentry_t *) (ldcache + sizeof(header_t));
555 strs = (char *) &libent[header->nlibs];
556
557 for (fd = 0; fd < header->nlibs; fd++) {
558 /* this should be more fine grained, but for now we assume that
559 * diff arches will not be cached together. and we ignore the
560 * the different multilib mips cases. */
561 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
562 continue;
563 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
564 continue;
565
566 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
567 continue;
568 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
569 }
570 return buf;
571}
572
573
278static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 574static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
279{ 575{
280 unsigned long i; 576 unsigned long i;
281 char *needed; 577 char *needed;
282 void *strtbl_void; 578 void *strtbl_void;
579 char *p;
283 580
284 if (!show_needed) return; 581 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
285 582
286 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 583 strtbl_void = elf_findsecbyname(elf, ".dynstr");
287 584
288 if (elf->phdr && strtbl_void) { 585 if (elf->phdr && strtbl_void) {
289#define SHOW_NEEDED(B) \ 586#define SHOW_NEEDED(B) \
299 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 596 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
300 dyn = DYN ## B (elf->data + offset); \ 597 dyn = DYN ## B (elf->data + offset); \
301 while (EGET(dyn->d_tag) != DT_NULL) { \ 598 while (EGET(dyn->d_tag) != DT_NULL) { \
302 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 599 if (EGET(dyn->d_tag) == DT_NEEDED) { \
303 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 600 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
304 if (offset >= elf->len) { \ 601 if (offset >= (Elf ## B ## _Off)elf->len) { \
305 ++dyn; \ 602 ++dyn; \
306 continue; \ 603 continue; \
307 } \ 604 } \
308 needed = (char*)(elf->data + offset); \ 605 needed = (char*)(elf->data + offset); \
606 if (op == 0) { \
607 if (!be_wewy_wewy_quiet) { \
309 if (*found_needed) xchrcat(ret, ',', ret_len); \ 608 if (*found_needed) xchrcat(ret, ',', ret_len); \
609 if (printcache) \
610 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
611 needed = p; \
310 xstrcat(ret, needed, ret_len); \ 612 xstrcat(ret, needed, ret_len); \
613 } \
311 *found_needed = 1; \ 614 *found_needed = 1; \
615 } else { \
616 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
617 *found_lib = 1; \
618 return (be_wewy_wewy_quiet ? NULL : needed); \
619 } \
620 } \
312 } \ 621 } \
313 ++dyn; \ 622 ++dyn; \
314 } \ 623 } \
315 } } 624 } }
316 SHOW_NEEDED(32) 625 SHOW_NEEDED(32)
317 SHOW_NEEDED(64) 626 SHOW_NEEDED(64)
627 if (op == 0 && !*found_needed && be_verbose)
628 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
318 } 629 }
630
631 return NULL;
319} 632}
320static char *scanelf_file_interp(elfobj *elf, char *found_interp) 633static char *scanelf_file_interp(elfobj *elf, char *found_interp)
321{ 634{
322 void *strtbl_void; 635 void *strtbl_void;
323 636
328 if (strtbl_void) { 641 if (strtbl_void) {
329#define SHOW_INTERP(B) \ 642#define SHOW_INTERP(B) \
330 if (elf->elf_class == ELFCLASS ## B) { \ 643 if (elf->elf_class == ELFCLASS ## B) { \
331 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 644 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
332 *found_interp = 1; \ 645 *found_interp = 1; \
333 return elf->data + EGET(strtbl->sh_offset); \ 646 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
334 } 647 }
335 SHOW_INTERP(32) 648 SHOW_INTERP(32)
336 SHOW_INTERP(64) 649 SHOW_INTERP(64)
337 } 650 }
338 return NULL; 651 return NULL;
360 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 673 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
361 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \ 674 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
362 { \ 675 { \
363 if (be_quiet) return NULL; \ 676 if (be_quiet) return NULL; \
364 *found_bind = 1; \ 677 *found_bind = 1; \
365 return "NOW"; \ 678 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
366 } \ 679 } \
367 ++dyn; \ 680 ++dyn; \
368 } \ 681 } \
369 } \ 682 } \
370 } 683 }
371 SHOW_BIND(32) 684 SHOW_BIND(32)
372 SHOW_BIND(64) 685 SHOW_BIND(64)
373 686
687 if (be_wewy_wewy_quiet) return NULL;
688
374 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 689 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
375 return NULL; 690 return NULL;
376 } else { 691 } else {
377 *found_bind = 1; 692 *found_bind = 1;
378 return "LAZY"; 693 return (char *) "LAZY";
379 } 694 }
380} 695}
381static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 696static char *scanelf_file_soname(elfobj *elf, char *found_soname)
382{ 697{
383 unsigned long i; 698 unsigned long i;
699 char *soname;
700 void *strtbl_void;
701
702 if (!show_soname) return NULL;
703
704 strtbl_void = elf_findsecbyname(elf, ".dynstr");
705
706 if (elf->phdr && strtbl_void) {
707#define SHOW_SONAME(B) \
708 if (elf->elf_class == ELFCLASS ## B) { \
709 Elf ## B ## _Dyn *dyn; \
710 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
711 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
712 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
713 Elf ## B ## _Off offset; \
714 /* only look for soname in shared objects */ \
715 if (ehdr->e_type != ET_DYN) \
716 return NULL; \
717 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
718 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
719 offset = EGET(phdr[i].p_offset); \
720 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
721 dyn = DYN ## B (elf->data + offset); \
722 while (EGET(dyn->d_tag) != DT_NULL) { \
723 if (EGET(dyn->d_tag) == DT_SONAME) { \
724 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
725 if (offset >= (Elf ## B ## _Off)elf->len) { \
726 ++dyn; \
727 continue; \
728 } \
729 soname = (char*)(elf->data + offset); \
730 *found_soname = 1; \
731 return (be_wewy_wewy_quiet ? NULL : soname); \
732 } \
733 ++dyn; \
734 } \
735 } }
736 SHOW_SONAME(32)
737 SHOW_SONAME(64)
738 }
739
740 return NULL;
741}
742static char *scanelf_file_sym(elfobj *elf, char *found_sym)
743{
744 unsigned long i;
745 char *ret;
384 void *symtab_void, *strtab_void; 746 void *symtab_void, *strtab_void;
385 747
386 if (!find_sym) return NULL; 748 if (!find_sym) return NULL;
749 ret = find_sym;
387 750
388 symtab_void = elf_findsecbyname(elf, ".symtab"); 751 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
389 strtab_void = elf_findsecbyname(elf, ".strtab");
390 752
391 if (symtab_void && strtab_void) { 753 if (symtab_void && strtab_void) {
392 char *base, *basemem;
393 basemem = xstrdup(filename);
394 base = basename(basemem);
395#define FIND_SYM(B) \ 754#define FIND_SYM(B) \
396 if (elf->elf_class == ELFCLASS ## B) { \ 755 if (elf->elf_class == ELFCLASS ## B) { \
397 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 756 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
398 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 757 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
399 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 758 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
403 if (sym->st_name) { \ 762 if (sym->st_name) { \
404 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 763 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
405 if (*find_sym == '*') { \ 764 if (*find_sym == '*') { \
406 printf("%s(%s) %5lX %15s %s\n", \ 765 printf("%s(%s) %5lX %15s %s\n", \
407 ((*found_sym == 0) ? "\n\t" : "\t"), \ 766 ((*found_sym == 0) ? "\n\t" : "\t"), \
408 base, \ 767 elf->base_filename, \
409 (long)sym->st_size, \ 768 (unsigned long)sym->st_size, \
410 (char *)get_elfstttype(sym->st_info), \ 769 get_elfstttype(sym->st_info), \
411 symname); \ 770 symname); \
412 *found_sym = 1; \ 771 *found_sym = 1; \
413 } else if ((strcmp(find_sym, symname) == 0) || \ 772 } else { \
773 char *this_sym, *next_sym; \
774 this_sym = find_sym; \
775 do { \
776 next_sym = strchr(this_sym, ','); \
777 if (next_sym == NULL) \
778 next_sym = this_sym + strlen(this_sym); \
779 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
414 (strcmp(symname, versioned_symname) == 0)) \ 780 (strcmp(symname, versioned_symname) == 0)) { \
781 ret = this_sym; \
415 (*found_sym)++; \ 782 (*found_sym)++; \
783 goto break_out; \
784 } \
785 this_sym = next_sym + 1; \
786 } while (*next_sym != '\0'); \
787 } \
416 } \ 788 } \
417 ++sym; \ 789 ++sym; \
418 } } 790 } }
419 FIND_SYM(32) 791 FIND_SYM(32)
420 FIND_SYM(64) 792 FIND_SYM(64)
421 free(basemem);
422 } 793 }
794
795break_out:
796 if (be_wewy_wewy_quiet) return NULL;
797
423 if (*find_sym != '*' && *found_sym) 798 if (*find_sym != '*' && *found_sym)
424 return find_sym; 799 return ret;
425 if (be_quiet) 800 if (be_quiet)
426 return NULL; 801 return NULL;
427 else 802 else
428 return " - "; 803 return (char *)" - ";
429} 804}
430/* scan an elf file and show all the fun stuff */ 805/* 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)) 806#define prints(str) write(fileno(stdout), str, strlen(str))
433static void scanelf_file(const char *filename) 807static void scanelf_file(const char *filename)
434{ 808{
435 unsigned long i; 809 unsigned long i;
436 char found_pax, found_stack, found_relro, found_textrel, 810 char found_pax, found_phdr, found_relro, found_load, found_textrel,
437 found_rpath, found_needed, found_interp, found_bind, 811 found_rpath, found_needed, found_interp, found_bind, found_soname,
438 found_sym, found_file; 812 found_sym, found_lib, found_file, found_textrels;
439 elfobj *elf; 813 elfobj *elf;
440 struct stat st; 814 struct stat st;
441 static char *out_buffer = NULL; 815 static char *out_buffer = NULL;
442 static size_t out_len; 816 static size_t out_len;
443 817
454 if (!S_ISREG(st.st_mode)) { 828 if (!S_ISREG(st.st_mode)) {
455 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 829 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
456 return; 830 return;
457 } 831 }
458 832
459 found_pax = found_stack = found_relro = found_textrel = \ 833 found_pax = found_phdr = found_relro = found_load = found_textrel = \
460 found_rpath = found_needed = found_interp = found_bind = \ 834 found_rpath = found_needed = found_interp = found_bind = found_soname = \
461 found_sym = found_file = 0; 835 found_sym = found_lib = found_file = found_textrels = 0;
462 836
463 /* verify this is real ELF */ 837 /* verify this is real ELF */
464 if ((elf = readelf(filename)) == NULL) { 838 if ((elf = readelf(filename)) == NULL) {
465 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 839 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
466 return; 840 return;
467 } 841 }
468 842
469 if (be_verbose > 1) 843 if (be_verbose > 1)
470 printf("%s: scanning file {%s,%s}\n", filename, 844 printf("%s: scanning file {%s,%s}\n", filename,
471 get_elfeitype(elf, EI_CLASS, elf->elf_class), 845 get_elfeitype(EI_CLASS, elf->elf_class),
472 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 846 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
473 else if (be_verbose) 847 else if (be_verbose)
474 printf("%s: scanning file\n", filename); 848 printf("%s: scanning file\n", filename);
475 849
476 /* init output buffer */ 850 /* init output buffer */
477 if (!out_buffer) { 851 if (!out_buffer) {
481 *out_buffer = '\0'; 855 *out_buffer = '\0';
482 856
483 /* show the header */ 857 /* show the header */
484 if (!be_quiet && show_banner) { 858 if (!be_quiet && show_banner) {
485 for (i = 0; out_format[i]; ++i) { 859 for (i = 0; out_format[i]; ++i) {
486 if (out_format[i] != '%') continue; 860 if (!IS_MODIFIER(out_format[i])) continue;
487 861
488 switch (out_format[++i]) { 862 switch (out_format[++i]) {
489 case '%': break; 863 case '%': break;
864 case '#': break;
865 case 'F':
866 case 'p':
490 case 'F': prints("FILE "); found_file = 1; break; 867 case 'f': prints("FILE "); found_file = 1; break;
491 case 'o': prints(" TYPE "); break; 868 case 'o': prints(" TYPE "); break;
492 case 'x': prints(" PAX "); break; 869 case 'x': prints(" PAX "); break;
493 case 'e': prints("STK/REL "); break; 870 case 'e': prints("STK/REL/PTL "); break;
494 case 't': prints("TEXTREL "); break; 871 case 't': prints("TEXTREL "); break;
495 case 'r': prints("RPATH "); break; 872 case 'r': prints("RPATH "); break;
496 case 'n': prints("NEEDED "); break; 873 case 'n': prints("NEEDED "); break;
497 case 'i': prints("INTERP "); break; 874 case 'i': prints("INTERP "); break;
498 case 'b': prints("BIND "); break; 875 case 'b': prints("BIND "); break;
876 case 'S': prints("SONAME "); break;
499 case 's': prints("SYM "); break; 877 case 's': prints("SYM "); break;
878 case 'N': prints("LIB "); break;
879 case 'T': prints("TEXTRELS "); break;
880 default: warnf("'%c' has no title ?", out_format[i]);
500 } 881 }
501 } 882 }
502 if (!found_file) prints("FILE "); 883 if (!found_file) prints("FILE ");
503 prints("\n"); 884 prints("\n");
504 found_file = 0; 885 found_file = 0;
506 } 887 }
507 888
508 /* dump all the good stuff */ 889 /* dump all the good stuff */
509 for (i = 0; out_format[i]; ++i) { 890 for (i = 0; out_format[i]; ++i) {
510 const char *out; 891 const char *out;
892 const char *tmp;
511 893
512 /* make sure we trim leading spaces in quiet mode */ 894 /* make sure we trim leading spaces in quiet mode */
513 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 895 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
514 *out_buffer = '\0'; 896 *out_buffer = '\0';
515 897
516 if (out_format[i] != '%') { 898 if (!IS_MODIFIER(out_format[i])) {
517 xchrcat(&out_buffer, out_format[i], &out_len); 899 xchrcat(&out_buffer, out_format[i], &out_len);
518 continue; 900 continue;
519 } 901 }
520 902
521 out = NULL; 903 out = NULL;
904 be_wewy_wewy_quiet = (out_format[i] == '#');
522 switch (out_format[++i]) { 905 switch (out_format[++i]) {
906 case '%':
907 case '#':
523 case '%': xchrcat(&out_buffer, '%', &out_len); break; 908 xchrcat(&out_buffer, out_format[i], &out_len); break;
524 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 909 case 'F':
910 found_file = 1;
911 if (be_wewy_wewy_quiet) break;
912 xstrcat(&out_buffer, filename, &out_len);
913 break;
914 case 'p':
915 found_file = 1;
916 if (be_wewy_wewy_quiet) break;
917 tmp = filename;
918 if (search_path) {
919 ssize_t len_search = strlen(search_path);
920 ssize_t len_file = strlen(filename);
921 if (!strncmp(filename, search_path, len_search) && \
922 len_file > len_search)
923 tmp += len_search;
924 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
925 }
926 xstrcat(&out_buffer, tmp, &out_len);
927 break;
928 case 'f':
929 found_file = 1;
930 if (be_wewy_wewy_quiet) break;
931 tmp = strrchr(filename, '/');
932 tmp = (tmp == NULL ? filename : tmp+1);
933 xstrcat(&out_buffer, tmp, &out_len);
934 break;
525 case 'o': out = get_elfetype(elf); break; 935 case 'o': out = get_elfetype(elf); break;
526 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 936 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
527 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 937 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; 938 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
939 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; 940 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
941 case 'n':
530 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 942 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; 943 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
532 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 944 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
945 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
533 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 946 case 's': out = scanelf_file_sym(elf, &found_sym); break;
947 default: warnf("'%c' has no scan code?", out_format[i]);
534 } 948 }
949 if (out) {
950 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
951 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
952 xstrncat(&out_buffer, out, &out_len, (tmp-out));
953 else
535 if (out) xstrcat(&out_buffer, out, &out_len); 954 xstrcat(&out_buffer, out, &out_len);
955 }
536 } 956 }
537 957
538#define FOUND_SOMETHING() \ 958#define FOUND_SOMETHING() \
539 (found_pax || found_stack || found_textrel || found_rpath || \ 959 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
540 found_needed || found_interp || found_bind || found_sym) 960 found_rpath || found_needed || found_interp || found_bind || \
961 found_soname || found_sym || found_lib || found_textrels)
541 962
542 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 963 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
543 xchrcat(&out_buffer, ' ', &out_len); 964 xchrcat(&out_buffer, ' ', &out_len);
544 xstrcat(&out_buffer, filename, &out_len); 965 xstrcat(&out_buffer, filename, &out_len);
545 } 966 }
546 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) 967 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
547 puts(out_buffer); 968 puts(out_buffer);
969 fflush(stdout);
970 }
548 971
549 unreadelf(elf); 972 unreadelf(elf);
550} 973}
551 974
552/* scan a directory for ET_EXEC files and print when we find one */ 975/* scan a directory for ET_EXEC files and print when we find one */
581 while ((dentry = readdir(dir))) { 1004 while ((dentry = readdir(dir))) {
582 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1005 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
583 continue; 1006 continue;
584 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1007 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
585 if (len >= sizeof(buf)) { 1008 if (len >= sizeof(buf)) {
586 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 1009 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1010 (unsigned long)len, (unsigned long)sizeof(buf));
587 continue; 1011 continue;
588 } 1012 }
589 sprintf(buf, "%s/%s", path, dentry->d_name); 1013 sprintf(buf, "%s/%s", path, dentry->d_name);
590 if (lstat(buf, &st) != -1) { 1014 if (lstat(buf, &st) != -1) {
591 if (S_ISREG(st.st_mode)) 1015 if (S_ISREG(st.st_mode))
611 return 1; 1035 return 1;
612 1036
613 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1037 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
614 if ((p = strchr(path, '\n')) != NULL) 1038 if ((p = strchr(path, '\n')) != NULL)
615 *p = 0; 1039 *p = 0;
1040 search_path = path;
616 scanelf_dir(path); 1041 scanelf_dir(path);
617 } 1042 }
618 if (fp != stdin) 1043 if (fp != stdin)
619 fclose(fp); 1044 fclose(fp);
620 return 0; 1045 return 0;
690 1115
691 free(path); 1116 free(path);
692} 1117}
693 1118
694 1119
695
696/* usage / invocation handling functions */ 1120/* usage / invocation handling functions */
697#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV" 1121#define PARSE_FLAGS "plRmyxetrnLibSs:gN:TaqvF:f:o:BhV"
698#define a_argument required_argument 1122#define a_argument required_argument
699static struct option const long_opts[] = { 1123static struct option const long_opts[] = {
700 {"path", no_argument, NULL, 'p'}, 1124 {"path", no_argument, NULL, 'p'},
701 {"ldpath", no_argument, NULL, 'l'}, 1125 {"ldpath", no_argument, NULL, 'l'},
702 {"recursive", no_argument, NULL, 'R'}, 1126 {"recursive", no_argument, NULL, 'R'},
705 {"pax", no_argument, NULL, 'x'}, 1129 {"pax", no_argument, NULL, 'x'},
706 {"header", no_argument, NULL, 'e'}, 1130 {"header", no_argument, NULL, 'e'},
707 {"textrel", no_argument, NULL, 't'}, 1131 {"textrel", no_argument, NULL, 't'},
708 {"rpath", no_argument, NULL, 'r'}, 1132 {"rpath", no_argument, NULL, 'r'},
709 {"needed", no_argument, NULL, 'n'}, 1133 {"needed", no_argument, NULL, 'n'},
1134 {"ldcache", no_argument, NULL, 'L'},
710 {"interp", no_argument, NULL, 'i'}, 1135 {"interp", no_argument, NULL, 'i'},
711 {"bind", no_argument, NULL, 'b'}, 1136 {"bind", no_argument, NULL, 'b'},
1137 {"soname", no_argument, NULL, 'S'},
712 {"symbol", a_argument, NULL, 's'}, 1138 {"symbol", a_argument, NULL, 's'},
1139 {"lib", a_argument, NULL, 'N'},
1140 {"gmatch", no_argument, NULL, 'g'},
1141 {"textrels", no_argument, NULL, 'T'},
713 {"all", no_argument, NULL, 'a'}, 1142 {"all", no_argument, NULL, 'a'},
714 {"quiet", no_argument, NULL, 'q'}, 1143 {"quiet", no_argument, NULL, 'q'},
715 {"verbose", no_argument, NULL, 'v'}, 1144 {"verbose", no_argument, NULL, 'v'},
716 {"format", a_argument, NULL, 'F'}, 1145 {"format", a_argument, NULL, 'F'},
717 {"from", a_argument, NULL, 'f'}, 1146 {"from", a_argument, NULL, 'f'},
718 {"file", a_argument, NULL, 'o'}, 1147 {"file", a_argument, NULL, 'o'},
719 {"nobanner", no_argument, NULL, 'B'}, 1148 {"nobanner", no_argument, NULL, 'B'},
720 {"help", no_argument, NULL, 'h'}, 1149 {"help", no_argument, NULL, 'h'},
721 {"version", no_argument, NULL, 'V'}, 1150 {"version", no_argument, NULL, 'V'},
722 {NULL, no_argument, NULL, 0x0} 1151 {NULL, no_argument, NULL, 0x0}
723}; 1152};
724 1153
725static char *opts_help[] = { 1154static const char *opts_help[] = {
726 "Scan all directories in PATH environment", 1155 "Scan all directories in PATH environment",
727 "Scan all directories in /etc/ld.so.conf", 1156 "Scan all directories in /etc/ld.so.conf",
728 "Scan directories recursively", 1157 "Scan directories recursively",
729 "Don't recursively cross mount points", 1158 "Don't recursively cross mount points",
730 "Don't scan symlinks\n", 1159 "Don't scan symlinks\n",
731 "Print PaX markings", 1160 "Print PaX markings",
732 "Print GNU_STACK markings", 1161 "Print GNU_STACK/PT_LOAD markings",
733 "Print TEXTREL information", 1162 "Print TEXTREL information",
734 "Print RPATH information", 1163 "Print RPATH information",
735 "Print NEEDED information", 1164 "Print NEEDED information",
1165 "Resolve NEEDED information (use with -n)",
736 "Print INTERP information", 1166 "Print INTERP information",
737 "Print BIND information", 1167 "Print BIND information",
1168 "Print SONAME information",
738 "Find a specified symbol", 1169 "Find a specified symbol",
1170 "Find a specified library",
1171 "Use strncmp to match libraries. (use with -N)",
1172 "Locate cause of TEXTREL",
739 "Print all scanned info (-x -e -t -r -n -i -b)\n", 1173 "Print all scanned info (-x -e -t -r -b)\n",
740 "Only output 'bad' things", 1174 "Only output 'bad' things",
741 "Be verbose (can be specified more than once)", 1175 "Be verbose (can be specified more than once)",
742 "Use specified format for output", 1176 "Use specified format for output",
743 "Read input stream from a filename", 1177 "Read input stream from a filename",
744 "Write output stream to a filename", 1178 "Write output stream to a filename",
765 1199
766 if (status != EXIT_SUCCESS) 1200 if (status != EXIT_SUCCESS)
767 exit(status); 1201 exit(status);
768 1202
769 puts("\nThe format modifiers for the -F option are:"); 1203 puts("\nThe format modifiers for the -F option are:");
770 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO"); 1204 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
771 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED"); 1205 puts(" t TEXTREL \tr RPATH \tn NEEDED");
772 puts(" %i INTERP \t%b BIND \t%s symbol"); 1206 puts(" i INTERP \tb BIND \ts symbol");
1207 puts(" N library \to Type \tT TEXTRELs");
1208 puts(" S SONAME");
1209 puts(" p filename (with search path removed)");
1210 puts(" f filename (short name/basename)");
1211 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
773 1212
774 exit(status); 1213 exit(status);
775} 1214}
776 1215
777/* parse command line arguments and preform needed actions */ 1216/* parse command line arguments and preform needed actions */
783 opterr = 0; 1222 opterr = 0;
784 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1223 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
785 switch (i) { 1224 switch (i) {
786 1225
787 case 'V': 1226 case 'V':
788 printf("%s compiled %s\n%s\n" 1227 printf("pax-utils-%s: %s compiled %s\n%s\n"
789 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1228 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
790 __FILE__, __DATE__, rcsid, argv0); 1229 VERSION, __FILE__, __DATE__, rcsid, argv0);
791 exit(EXIT_SUCCESS); 1230 exit(EXIT_SUCCESS);
792 break; 1231 break;
793 case 'h': usage(EXIT_SUCCESS); break; 1232 case 'h': usage(EXIT_SUCCESS); break;
794 case 'f': 1233 case 'f':
795 if (from_file == NULL) 1234 if (from_file) err("Don't specify -f twice");
796 from_file = xstrdup(optarg); 1235 from_file = xstrdup(optarg);
797 break; 1236 break;
798 case 'o': { 1237 case 'o': {
799 FILE *fp = NULL; 1238 FILE *fp = NULL;
800 fp = freopen(optarg, "w", stdout); 1239 if ((fp = freopen(optarg, "w", stdout)) == NULL)
801 if (fp == NULL)
802 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1240 err("Could not open output stream '%s': %s", optarg, strerror(errno));
803 stdout = fp; 1241 SET_STDOUT(fp);
804 break; 1242 break;
805 } 1243 }
806 1244
807 case 's': { 1245 case 's': {
808 size_t len; 1246 if (find_sym) warn("You prob don't want to specify -s twice");
809 find_sym = xstrdup(optarg); 1247 find_sym = optarg;
810 len = strlen(find_sym) + 1;
811 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1248 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
812 sprintf(versioned_symname, "%s@", find_sym); 1249 sprintf(versioned_symname, "%s@", find_sym);
813 break; 1250 break;
814 } 1251 }
815
816 case 'F': { 1252 case 'N': {
817 if (!out_format) 1253 if (find_lib) warn("You prob don't want to specify -N twice");
818 out_format = xstrdup(optarg); 1254 find_lib = optarg;
819 break; 1255 break;
820 } 1256 }
821 1257
1258 case 'F': {
1259 if (out_format) warn("You prob don't want to specify -F twice");
1260 out_format = optarg;
1261 break;
1262 }
1263
1264 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */
1265 case 'L': printcache = 1; break;
822 case 'y': scan_symlink = 0; break; 1266 case 'y': scan_symlink = 0; break;
823 case 'B': show_banner = 0; break; 1267 case 'B': show_banner = 0; break;
824 case 'l': scan_ldpath = 1; break; 1268 case 'l': scan_ldpath = 1; break;
825 case 'p': scan_envpath = 1; break; 1269 case 'p': scan_envpath = 1; break;
826 case 'R': dir_recurse = 1; break; 1270 case 'R': dir_recurse = 1; break;
827 case 'm': dir_crossmount = 0; break; 1271 case 'm': dir_crossmount = 0; break;
828 case 'x': show_pax = 1; break; 1272 case 'x': show_pax = 1; break;
829 case 'e': show_stack = 1; break; 1273 case 'e': show_phdr = 1; break;
830 case 't': show_textrel = 1; break; 1274 case 't': show_textrel = 1; break;
831 case 'r': show_rpath = 1; break; 1275 case 'r': show_rpath = 1; break;
832 case 'n': show_needed = 1; break; 1276 case 'n': show_needed = 1; break;
833 case 'i': show_interp = 1; break; 1277 case 'i': show_interp = 1; break;
834 case 'b': show_bind = 1; break; 1278 case 'b': show_bind = 1; break;
1279 case 'S': show_soname = 1; break;
1280 case 'T': show_textrels = 1; break;
835 case 'q': be_quiet = 1; break; 1281 case 'q': be_quiet = 1; break;
836 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1282 case 'v': be_verbose = (be_verbose % 20) + 1; break;
837 case 'a': show_pax = show_stack = show_textrel = show_rpath = \ 1283 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
838 show_needed = show_interp = show_bind = 1; break;
839 1284
840 case ':': 1285 case ':':
841 err("Option missing parameter\n"); 1286 err("Option missing parameter\n");
842 case '?': 1287 case '?':
843 err("Unknown option\n"); 1288 err("Unknown option\n");
846 } 1291 }
847 } 1292 }
848 1293
849 /* let the format option override all other options */ 1294 /* let the format option override all other options */
850 if (out_format) { 1295 if (out_format) {
851 show_pax = show_stack = show_textrel = show_rpath = \ 1296 show_pax = show_phdr = show_textrel = show_rpath = \
852 show_needed = show_interp = show_bind = 0; 1297 show_needed = show_interp = show_bind = show_soname = \
1298 show_textrels = 0;
853 for (i = 0; out_format[i]; ++i) { 1299 for (i = 0; out_format[i]; ++i) {
854 if (out_format[i] != '%') continue; 1300 if (!IS_MODIFIER(out_format[i])) continue;
855 1301
856 switch (out_format[++i]) { 1302 switch (out_format[++i]) {
857 case '%': break; 1303 case '%': break;
1304 case '#': break;
858 case 'F': break; 1305 case 'F': break;
1306 case 'p': break;
1307 case 'f': break;
859 case 's': break; 1308 case 's': break;
1309 case 'N': break;
860 case 'o': break; 1310 case 'o': break;
861 case 'x': show_pax = 1; break; 1311 case 'x': show_pax = 1; break;
862 case 'e': show_stack = 1; break; 1312 case 'e': show_phdr = 1; break;
863 case 't': show_textrel = 1; break; 1313 case 't': show_textrel = 1; break;
864 case 'r': show_rpath = 1; break; 1314 case 'r': show_rpath = 1; break;
865 case 'n': show_needed = 1; break; 1315 case 'n': show_needed = 1; break;
866 case 'i': show_interp = 1; break; 1316 case 'i': show_interp = 1; break;
867 case 'b': show_bind = 1; break; 1317 case 'b': show_bind = 1; break;
1318 case 'S': show_soname = 1; break;
1319 case 'T': show_textrels = 1; break;
868 default: 1320 default:
869 err("Invalid format specifier '%c' (byte %i)", 1321 err("Invalid format specifier '%c' (byte %i)",
870 out_format[i], i+1); 1322 out_format[i], i+1);
871 } 1323 }
872 } 1324 }
873 1325
874 /* construct our default format */ 1326 /* construct our default format */
875 } else { 1327 } else {
876 size_t fmt_len = 30; 1328 size_t fmt_len = 30;
877 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1329 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
878 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1330 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
879 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1331 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
880 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1332 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
881 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1333 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
882 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1334 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
883 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1335 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
884 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1336 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
885 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1337 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1338 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1339 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
886 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1340 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1341 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
887 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1342 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
888 } 1343 }
889 if (be_verbose > 2) printf("Format: %s\n", out_format); 1344 if (be_verbose > 2) printf("Format: %s\n", out_format);
890 1345
891 /* now lets actually do the scanning */ 1346 /* now lets actually do the scanning */
892 if (scan_ldpath || (show_rpath && be_quiet)) 1347 if (scan_ldpath || (show_rpath && be_quiet))
898 free(from_file); 1353 free(from_file);
899 from_file = *argv; 1354 from_file = *argv;
900 } 1355 }
901 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1356 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
902 err("Nothing to scan !?"); 1357 err("Nothing to scan !?");
903 while (optind < argc) 1358 while (optind < argc) {
904 scanelf_dir(argv[optind++]); 1359 search_path = argv[optind++];
1360 scanelf_dir(search_path);
1361 }
905 1362
906 /* clean up */ 1363 /* clean up */
907 if (find_sym) { 1364 if (versioned_symname) free(versioned_symname);
908 free(find_sym);
909 free(versioned_symname);
910 }
911 if (out_format) free(out_format);
912 for (i = 0; ldpaths[i]; ++i) 1365 for (i = 0; ldpaths[i]; ++i)
913 free(ldpaths[i]); 1366 free(ldpaths[i]);
1367
1368 if (ldcache != 0)
1369 munmap(ldcache, ldcache_size);
914} 1370}
915 1371
916 1372
917 1373
918/* utility funcs */ 1374/* utility funcs */
920{ 1376{
921 char *ret = strdup(s); 1377 char *ret = strdup(s);
922 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1378 if (!ret) err("Could not strdup(): %s", strerror(errno));
923 return ret; 1379 return ret;
924} 1380}
925
926static void *xmalloc(size_t size) 1381static void *xmalloc(size_t size)
927{ 1382{
928 void *ret = malloc(size); 1383 void *ret = malloc(size);
929 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1384 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
930 return ret; 1385 return ret;
931} 1386}
932
933static void xstrcat(char **dst, const char *src, size_t *curr_len) 1387static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
934{ 1388{
935 long new_len; 1389 size_t new_len;
936 1390
937 new_len = strlen(*dst) + strlen(src); 1391 new_len = strlen(*dst) + strlen(src);
938 if (*curr_len <= new_len) { 1392 if (*curr_len <= new_len) {
939 *curr_len = new_len + (*curr_len / 2); 1393 *curr_len = new_len + (*curr_len / 2);
940 *dst = realloc(*dst, *curr_len); 1394 *dst = realloc(*dst, *curr_len);
941 if (!*dst) 1395 if (!*dst)
942 err("could not realloc %li bytes", (unsigned long)*curr_len); 1396 err("could not realloc() %li bytes", (unsigned long)*curr_len);
943 } 1397 }
944 1398
1399 if (n)
1400 strncat(*dst, src, n);
1401 else
945 strcat(*dst, src); 1402 strcat(*dst, src);
946} 1403}
947
948static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1404static inline void xchrcat(char **dst, const char append, size_t *curr_len)
949{ 1405{
950 static char my_app[2]; 1406 static char my_app[2];
951 my_app[0] = append; 1407 my_app[0] = append;
952 my_app[1] = '\0'; 1408 my_app[1] = '\0';
953 xstrcat(dst, my_app, curr_len); 1409 xstrcat(dst, my_app, curr_len);
954} 1410}
1411
955 1412
956 1413
957int main(int argc, char *argv[]) 1414int main(int argc, char *argv[])
958{ 1415{
959 if (argc < 2) 1416 if (argc < 2)
960 usage(EXIT_FAILURE); 1417 usage(EXIT_FAILURE);
961 parseargs(argc, argv); 1418 parseargs(argc, argv);
962 fclose(stdout); 1419 fclose(stdout);
963#ifdef __BOUNDS_CHECKING_ON 1420#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()"); 1421 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 1422#endif
966 return EXIT_SUCCESS; 1423 return EXIT_SUCCESS;
967} 1424}

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

  ViewVC Help
Powered by ViewVC 1.1.20