/[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.78 Revision 1.119
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2006 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.78 2005/06/08 22:23:16 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.119 2006/02/05 02:25:58 solar Exp $
5 * 5 *
6 ******************************************************************** 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
21 */ 8 */
22 9
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <libgen.h>
27#include <limits.h>
28#define __USE_GNU
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/stat.h>
33#include <dirent.h>
34#include <getopt.h>
35#include <assert.h>
36#include "paxelf.h" 10#include "paxinc.h"
37 11
38static const char *rcsid = "$Id: scanelf.c,v 1.78 2005/06/08 22:23:16 vapier Exp $"; 12static const char *rcsid = "$Id: scanelf.c,v 1.119 2006/02/05 02:25:58 solar Exp $";
39#define argv0 "scanelf" 13#define argv0 "scanelf"
40 14
41#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#')
42 16
43 17
44 18
45/* prototypes */ 19/* prototypes */
20static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len);
46static void scanelf_file(const char *filename); 23static void scanelf_file(const char *filename);
47static void scanelf_dir(const char *path); 24static void scanelf_dir(const char *path);
48static void scanelf_ldpath(); 25static void scanelf_ldpath(void);
49static void scanelf_envpath(); 26static void scanelf_envpath(void);
50static void usage(int status); 27static void usage(int status);
51static void parseargs(int argc, char *argv[]); 28static void parseargs(int argc, char *argv[]);
52static char *xstrdup(const char *s); 29static char *xstrdup(const char *s);
53static void *xmalloc(size_t size); 30static void *xmalloc(size_t size);
54static void xstrcat(char **dst, const char *src, size_t *curr_len); 31static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
55static inline void xchrcat(char **dst, const char append, size_t *curr_len); 33static inline void xchrcat(char **dst, const char append, size_t *curr_len);
56 34
57/* variables to control behavior */ 35/* variables to control behavior */
36static char match_etypes[126] = "";
58static char *ldpaths[256]; 37static char *ldpaths[256];
59static char scan_ldpath = 0; 38static char scan_ldpath = 0;
60static char scan_envpath = 0; 39static char scan_envpath = 0;
61static char scan_symlink = 1; 40static char scan_symlink = 1;
41static char scan_archives = 0;
62static char dir_recurse = 0; 42static char dir_recurse = 0;
63static char dir_crossmount = 1; 43static char dir_crossmount = 1;
64static char show_pax = 0; 44static char show_pax = 0;
65static char show_phdr = 0; 45static char show_phdr = 0;
66static char show_textrel = 0; 46static char show_textrel = 0;
67static char show_rpath = 0; 47static char show_rpath = 0;
68static char show_needed = 0; 48static char show_needed = 0;
69static char show_interp = 0; 49static char show_interp = 0;
70static char show_bind = 0; 50static char show_bind = 0;
51static char show_soname = 0;
71static char show_textrels = 0; 52static char show_textrels = 0;
72static char show_banner = 1; 53static char show_banner = 1;
73static char be_quiet = 0; 54static char be_quiet = 0;
74static char be_verbose = 0; 55static char be_verbose = 0;
75static char be_wewy_wewy_quiet = 0; 56static char be_wewy_wewy_quiet = 0;
76static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL; 58static char *find_lib = NULL;
78static char *out_format = NULL; 59static char *out_format = NULL;
79static char *search_path = NULL; 60static char *search_path = NULL;
61static char fix_elf = 0;
62static char gmatch = 0;
63static char use_ldcache = 0;
80 64
81 65
66caddr_t ldcache = 0;
67size_t ldcache_size = 0;
82 68
83/* sub-funcs for scanelf_file() */ 69/* sub-funcs for scanelf_file() */
84static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 70static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
85{ 71{
86 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 72 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
107 GET_SYMTABS(32) 93 GET_SYMTABS(32)
108 GET_SYMTABS(64) 94 GET_SYMTABS(64)
109} 95}
110static char *scanelf_file_pax(elfobj *elf, char *found_pax) 96static char *scanelf_file_pax(elfobj *elf, char *found_pax)
111{ 97{
112 static char *paxflags;
113 static char ret[7]; 98 static char ret[7];
114 unsigned long i, shown; 99 unsigned long i, shown;
115
116 100
117 if (!show_pax) return NULL; 101 if (!show_pax) return NULL;
118 102
119 shown = 0; 103 shown = 0;
120 memset(&ret, 0, sizeof(ret)); 104 memset(&ret, 0, sizeof(ret));
139 SHOW_PAX(64) 123 SHOW_PAX(64)
140 } 124 }
141 125
142 /* fall back to EI_PAX if no PT_PAX was found */ 126 /* fall back to EI_PAX if no PT_PAX was found */
143 if (!*ret) { 127 if (!*ret) {
128 static char *paxflags;
144 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 129 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
145 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 130 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
146 *found_pax = 1; 131 *found_pax = 1;
147 return paxflags; 132 return (be_wewy_wewy_quiet ? NULL : paxflags);
148 } 133 }
149 strncpy(ret, paxflags, sizeof(ret)); 134 strncpy(ret, paxflags, sizeof(ret));
150 // ++shown;
151 } 135 }
152 136
153 if (be_quiet && !shown) 137 if (be_wewy_wewy_quiet || (be_quiet && !shown))
154 return NULL; 138 return NULL;
139 else
155 return ret; 140 return ret;
156
157} 141}
142
158static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 143static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
159{ 144{
160 static char ret[12]; 145 static char ret[12];
161 char *found; 146 char *found;
162 unsigned long i, off, shown, check_flags;
163 unsigned char multi_stack, multi_relro, multi_load; 147 unsigned long i, shown, multi_stack, multi_relro, multi_load;
148 int max_pt_load;
164 149
165 if (!show_phdr) return NULL; 150 if (!show_phdr) return NULL;
166 151
167 memcpy(ret, "--- --- ---\0", 12); 152 memcpy(ret, "--- --- ---\0", 12);
168 153
169 shown = 0; 154 shown = 0;
170 multi_stack = multi_relro = multi_load = 0; 155 multi_stack = multi_relro = multi_load = 0;
156 max_pt_load = elf_max_pt_load(elf);
171 157
172 if (elf->phdr) { 158#define NOTE_GNU_STACK ".note.GNU-stack"
173#define SHOW_PHDR(B) \ 159#define SHOW_PHDR(B) \
174 if (elf->elf_class == ELFCLASS ## B) { \ 160 if (elf->elf_class == ELFCLASS ## B) { \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 161 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
162 Elf ## B ## _Off offset; \
163 uint32_t flags, check_flags; \
164 if (elf->phdr != NULL) { \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 165 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 uint32_t flags; \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 166 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
179 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 167 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
180 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 168 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
181 found = found_phdr; \ 169 found = found_phdr; \
182 off = 0; \ 170 offset = 0; \
183 check_flags = PF_X; \ 171 check_flags = PF_X; \
184 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 172 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
185 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 173 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
186 found = found_relro; \ 174 found = found_relro; \
187 off = 4; \ 175 offset = 4; \
188 check_flags = PF_X; \ 176 check_flags = PF_X; \
189 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 177 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
178 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
190 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 179 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
191 found = found_load; \ 180 found = found_load; \
192 off = 8; \ 181 offset = 8; \
193 check_flags = PF_W|PF_X; \ 182 check_flags = PF_W|PF_X; \
194 } else \ 183 } else \
195 continue; \ 184 continue; \
196 flags = EGET(phdr[i].p_flags); \ 185 flags = EGET(phdr[i].p_flags); \
197 if (be_quiet && ((flags & check_flags) != check_flags)) \ 186 if (be_quiet && ((flags & check_flags) != check_flags)) \
198 continue; \ 187 continue; \
188 if (fix_elf && ((flags & PF_X) != flags)) { \
189 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
190 ret[3] = ret[7] = '!'; \
191 flags = EGET(phdr[i].p_flags); \
192 } \
199 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \ 193 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
200 *found = 1; \ 194 *found = 1; \
201 ++shown; \ 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 char *str; \
202 if ((void*)strtbl > (void*)elf->data_end) \
203 goto skip_this_shdr##B; \
204 check_flags = SHF_WRITE|SHF_EXECINSTR; \
205 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
206 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
207 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
208 str = elf->data + offset; \
209 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
210 if (!strcmp(str, NOTE_GNU_STACK)) { \
211 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
212 flags = EGET(shdr[i].sh_flags); \
213 if (be_quiet && ((flags & check_flags) != check_flags)) \
214 continue; \
215 ++*found_phdr; \
216 shown = 1; \
217 if (flags & SHF_WRITE) ret[0] = 'W'; \
218 if (flags & SHF_ALLOC) ret[1] = 'A'; \
219 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
220 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
221 break; \
222 } \
223 } \
224 skip_this_shdr##B: \
225 if (!multi_stack) { \
226 *found_phdr = 1; \
227 shown = 1; \
228 memcpy(ret, "!WX", 3); \
229 } \
202 } \ 230 } \
203 } 231 }
204 SHOW_PHDR(32) 232 SHOW_PHDR(32)
205 SHOW_PHDR(64) 233 SHOW_PHDR(64)
206 }
207 234
208 if (be_quiet && !shown) 235 if (be_wewy_wewy_quiet || (be_quiet && !shown))
209 return NULL; 236 return NULL;
210 else 237 else
211 return ret; 238 return ret;
212} 239}
213static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 240static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
214{ 241{
215 static char ret[] = "TEXTREL"; 242 static const char *ret = "TEXTREL";
216 unsigned long i; 243 unsigned long i;
217 244
218 if (!show_textrel) return NULL; 245 if (!show_textrel && !show_textrels) return NULL;
219 246
220 if (elf->phdr) { 247 if (elf->phdr) {
221#define SHOW_TEXTREL(B) \ 248#define SHOW_TEXTREL(B) \
222 if (elf->elf_class == ELFCLASS ## B) { \ 249 if (elf->elf_class == ELFCLASS ## B) { \
223 Elf ## B ## _Dyn *dyn; \ 250 Elf ## B ## _Dyn *dyn; \
243 } 270 }
244 271
245 if (be_quiet || be_wewy_wewy_quiet) 272 if (be_quiet || be_wewy_wewy_quiet)
246 return NULL; 273 return NULL;
247 else 274 else
248 return (char *)" - "; 275 return " - ";
249} 276}
250static char *scanelf_file_textrels(elfobj *elf, char *found_textrels) 277static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
251{ 278{
252 unsigned long p, s, r, rmax; 279 unsigned long s, r, rmax;
253 void *symtab_void, *strtab_void; 280 void *symtab_void, *strtab_void, *text_void;
254 281
255 if (!show_textrels) return NULL; 282 if (!show_textrels) return NULL;
256 283
284 /* don't search for TEXTREL's if the ELF doesn't have any */
285 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
286 if (!*found_textrel) return NULL;
287
257 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 288 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
289 text_void = elf_findsecbyname(elf, ".text");
258 290
259 if (symtab_void && strtab_void && elf->phdr && elf->shdr) { 291 if (symtab_void && strtab_void && text_void && elf->shdr) {
260#define SHOW_TEXTRELS(B) \ 292#define SHOW_TEXTRELS(B) \
261 if (elf->elf_class == ELFCLASS ## B) { \ 293 if (elf->elf_class == ELFCLASS ## B) { \
262 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 294 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
263 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
264 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 295 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
265 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 296 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
266 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 297 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
298 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
299 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
300 uint ## B ## _t memsz = EGET(text->sh_size); \
267 Elf ## B ## _Rel *rel; \ 301 Elf ## B ## _Rel *rel; \
268 Elf ## B ## _Rela *rela; \ 302 Elf ## B ## _Rela *rela; \
269 /* search the section headers for relocations */ \ 303 /* search the section headers for relocations */ \
270 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ 304 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
271 uint32_t sh_type = EGET(shdr[s].sh_type); \ 305 uint32_t sh_type = EGET(shdr[s].sh_type); \
277 rel = NULL; \ 311 rel = NULL; \
278 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ 312 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
279 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ 313 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
280 } else \ 314 } else \
281 continue; \ 315 continue; \
282 /* search the program headers for PT_LOAD headers */ \
283 for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
284 Elf ## B ## _Addr vaddr; \
285 uint ## B ## _t memsz; \
286 if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
287 if (EGET(phdr[p].p_flags) & PF_W) continue; \
288 vaddr = EGET(phdr[p].p_vaddr); \
289 memsz = EGET(phdr[p].p_memsz); \
290 /* now see if any of the relocs are in the PT_LOAD */ \ 316 /* now see if any of the relocs are in the .text */ \
291 for (r = 0; r < rmax; ++r) { \ 317 for (r = 0; r < rmax; ++r) { \
292 unsigned long sym_max; \ 318 unsigned long sym_max; \
293 Elf ## B ## _Addr offset_tmp; \ 319 Elf ## B ## _Addr offset_tmp; \
294 Elf ## B ## _Sym *func; \ 320 Elf ## B ## _Sym *func; \
295 Elf ## B ## _Sym *sym; \ 321 Elf ## B ## _Sym *sym; \
296 Elf ## B ## _Addr r_offset; \ 322 Elf ## B ## _Addr r_offset; \
297 uint ## B ## _t r_info; \ 323 uint ## B ## _t r_info; \
298 if (sh_type == SHT_REL) { \ 324 if (sh_type == SHT_REL) { \
299 r_offset = EGET(rel[r].r_offset); \ 325 r_offset = EGET(rel[r].r_offset); \
300 r_info = EGET(rel[r].r_info); \ 326 r_info = EGET(rel[r].r_info); \
301 } else { \ 327 } else { \
302 r_offset = EGET(rela[r].r_offset); \ 328 r_offset = EGET(rela[r].r_offset); \
303 r_info = EGET(rela[r].r_info); \ 329 r_info = EGET(rela[r].r_info); \
330 } \
331 /* make sure this relocation is inside of the .text */ \
332 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
333 if (be_verbose <= 2) continue; \
334 } else \
335 *found_textrels = 1; \
336 /* locate this relocation symbol name */ \
337 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
338 if ((void*)sym > (void*)elf->data_end) { \
339 warn("%s: corrupt ELF symbol", elf->filename); \
340 continue; \
341 } \
342 sym_max = ELF ## B ## _R_SYM(r_info); \
343 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
344 sym += sym_max; \
345 else \
346 sym = NULL; \
347 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
348 /* show the raw details about this reloc */ \
349 printf(" %s: ", elf->base_filename); \
350 if (sym && sym->st_name) \
351 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
352 else \
353 printf("(memory/fake?)"); \
354 printf(" [0x%lX]", (unsigned long)r_offset); \
355 /* now try to find the closest symbol that this rel is probably in */ \
356 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
357 func = NULL; \
358 offset_tmp = 0; \
359 while (sym_max--) { \
360 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
361 func = sym; \
362 offset_tmp = EGET(sym->st_value); \
304 } \ 363 } \
305 /* make sure this relocation is inside of the .text */ \
306 if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \
307 *found_textrels = 1; \
308 /* locate this relocation symbol name */ \
309 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
310 sym_max = ELF ## B ## _R_SYM(r_info); \
311 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
312 sym += sym_max; \
313 else \
314 sym = NULL; \
315 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
316 /* show the raw details about this reloc */ \
317 printf("\tTEXTREL %s: ", elf->base_filename); \
318 if (sym && sym->st_name) \
319 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
320 else \
321 printf("(NULL: fake?)"); \
322 printf(" [0x%lX]", (unsigned long)r_offset); \
323 /* now try to find the closest symbol that this rel is probably in */ \
324 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
325 func = NULL; \
326 offset_tmp = 0; \
327 while (sym_max--) { \
328 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
329 func = sym; \
330 offset_tmp = EGET(sym->st_value); \
331 } \
332 ++sym; \ 364 ++sym; \
333 } \
334 printf(" in "); \
335 if (func && func->st_name) \
336 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
337 else \
338 printf("(NULL: fake?)"); \
339 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
340 } \ 365 } \
366 printf(" in "); \
367 if (func && func->st_name) \
368 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
369 else \
370 printf("(NULL: fake?)"); \
371 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
341 } \ 372 } \
342 } } 373 } }
343 SHOW_TEXTRELS(32) 374 SHOW_TEXTRELS(32)
344 SHOW_TEXTRELS(64) 375 SHOW_TEXTRELS(64)
345 } 376 }
377 if (!*found_textrels)
378 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
346 379
347 return NULL; 380 return NULL;
381}
382
383static void rpath_security_checks(elfobj *, char *, const char *);
384static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
385{
386 struct stat st;
387 switch (*item) {
388 case '/': break;
389 case '.':
390 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
391 break;
392 case ':':
393 case '\0':
394 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
395 break;
396 case '$':
397 if (fstat(elf->fd, &st) != -1)
398 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
399 warnf("Security problem with %s='%s' in %s with mode set of %o",
400 dt_type, item, elf->filename, st.st_mode & 07777);
401 break;
402 default:
403 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
404 break;
405 }
348} 406}
349static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 407static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
350{ 408{
351 unsigned long i, s; 409 unsigned long i, s;
352 char *rpath, *runpath, **r; 410 char *rpath, *runpath, **r;
386 /* Verify the memory is somewhat sane */ \ 444 /* Verify the memory is somewhat sane */ \
387 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 445 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
388 if (offset < (Elf ## B ## _Off)elf->len) { \ 446 if (offset < (Elf ## B ## _Off)elf->len) { \
389 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 447 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
390 *r = (char*)(elf->data + offset); \ 448 *r = (char*)(elf->data + offset); \
449 /* cache the length in case we need to nuke this section later on */ \
450 if (fix_elf) \
451 offset = strlen(*r); \
391 /* If quiet, don't output paths in ld.so.conf */ \ 452 /* If quiet, don't output paths in ld.so.conf */ \
392 if (be_quiet) { \ 453 if (be_quiet) { \
393 size_t len; \ 454 size_t len; \
394 char *start, *end; \ 455 char *start, *end; \
395 /* note that we only 'chop' off leading known paths. */ \ 456 /* note that we only 'chop' off leading known paths. */ \
396 /* since *r is read-only memory, we can only move the ptr forward. */ \ 457 /* since *r is read-only memory, we can only move the ptr forward. */ \
397 start = *r; \ 458 start = *r; \
398 /* scan each path in : delimited list */ \ 459 /* scan each path in : delimited list */ \
399 while (start) { \ 460 while (start) { \
461 rpath_security_checks(elf, start, get_elfdtype(word)); \
400 end = strchr(start, ':'); \ 462 end = strchr(start, ':'); \
401 len = (end ? abs(end - start) : strlen(start)); \ 463 len = (end ? abs(end - start) : strlen(start)); \
464 if (use_ldcache) \
402 for (s = 0; ldpaths[s]; ++s) { \ 465 for (s = 0; ldpaths[s]; ++s) \
403 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 466 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
404 *r = (end ? end + 1 : NULL); \ 467 *r = end; \
468 /* corner case ... if RPATH reads "/usr/lib:", we want \
469 * to show ':' rather than '' */ \
470 if (end && end[1] != '\0') \
471 (*r)++; \
405 break; \ 472 break; \
406 } \ 473 } \
407 } \
408 if (!*r || !ldpaths[s] || !end) \ 474 if (!*r || !end) \
409 start = NULL; \ 475 break; \
410 else \ 476 else \
411 start = start + len + 1; \ 477 start = start + len + 1; \
412 } \ 478 } \
413 } \ 479 } \
480 if (*r) { \
481 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
482 /* just nuke it */ \
483 nuke_it##B: \
484 memset(*r, 0x00, offset); \
485 *r = NULL; \
486 ESET(dyn->d_tag, DT_DEBUG); \
487 ESET(dyn->d_un.d_ptr, 0); \
488 } else if (fix_elf) { \
489 /* try to clean "bad" paths */ \
490 size_t len, tmpdir_len; \
491 char *start, *end; \
492 const char *tmpdir; \
493 start = *r; \
494 tmpdir = (getenv("TMPDIR") ? : "."); \
495 tmpdir_len = strlen(tmpdir); \
496 while (1) { \
497 end = strchr(start, ':'); \
498 if (start == end) { \
499 eat_this_path##B: \
500 len = strlen(end); \
501 memmove(start, end+1, len); \
502 start[len-1] = '\0'; \
503 end = start - 1; \
504 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
505 if (!end) { \
506 if (start == *r) \
507 goto nuke_it##B; \
508 *--start = '\0'; \
509 } else \
510 goto eat_this_path##B; \
511 } \
512 if (!end) \
513 break; \
514 start = end + 1; \
515 } \
516 if (**r == '\0') \
517 goto nuke_it##B; \
518 } \
519 if (*r) \
414 if (*r) *found_rpath = 1; \ 520 *found_rpath = 1; \
521 } \
415 } \ 522 } \
416 ++dyn; \ 523 ++dyn; \
417 } \ 524 } \
418 } } 525 } }
419 SHOW_RPATH(32) 526 SHOW_RPATH(32)
436 } else if (rpath || runpath) 543 } else if (rpath || runpath)
437 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 544 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
438 else if (!be_quiet) 545 else if (!be_quiet)
439 xstrcat(ret, " - ", ret_len); 546 xstrcat(ret, " - ", ret_len);
440} 547}
548
549#define LDSO_CACHE_MAGIC "ld.so-"
550#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
551#define LDSO_CACHE_VER "1.7.0"
552#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
553#define FLAG_ANY -1
554#define FLAG_TYPE_MASK 0x00ff
555#define FLAG_LIBC4 0x0000
556#define FLAG_ELF 0x0001
557#define FLAG_ELF_LIBC5 0x0002
558#define FLAG_ELF_LIBC6 0x0003
559#define FLAG_REQUIRED_MASK 0xff00
560#define FLAG_SPARC_LIB64 0x0100
561#define FLAG_IA64_LIB64 0x0200
562#define FLAG_X8664_LIB64 0x0300
563#define FLAG_S390_LIB64 0x0400
564#define FLAG_POWERPC_LIB64 0x0500
565#define FLAG_MIPS64_LIBN32 0x0600
566#define FLAG_MIPS64_LIBN64 0x0700
567
568static char *lookup_cache_lib(elfobj *, char *);
569static char *lookup_cache_lib(elfobj *elf, char *fname)
570{
571 int fd = 0;
572 char *strs;
573 static char buf[__PAX_UTILS_PATH_MAX] = "";
574 const char *cachefile = "/etc/ld.so.cache";
575 struct stat st;
576
577 typedef struct {
578 char magic[LDSO_CACHE_MAGIC_LEN];
579 char version[LDSO_CACHE_VER_LEN];
580 int nlibs;
581 } header_t;
582 header_t *header;
583
584 typedef struct {
585 int flags;
586 int sooffset;
587 int liboffset;
588 } libentry_t;
589 libentry_t *libent;
590
591 if (fname == NULL)
592 return NULL;
593
594 if (ldcache == 0) {
595 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
596 return NULL;
597
598 /* cache these values so we only map/unmap the cache file once */
599 ldcache_size = st.st_size;
600 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
601
602 close(fd);
603
604 if (ldcache == (caddr_t)-1) {
605 ldcache = 0;
606 return NULL;
607 }
608
609 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
610 return NULL;
611 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
612 return NULL;
613 }
614
615 header = (header_t *) ldcache;
616 libent = (libentry_t *) (ldcache + sizeof(header_t));
617 strs = (char *) &libent[header->nlibs];
618
619 for (fd = 0; fd < header->nlibs; fd++) {
620 /* this should be more fine grained, but for now we assume that
621 * diff arches will not be cached together. and we ignore the
622 * the different multilib mips cases. */
623 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
624 continue;
625 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
626 continue;
627
628 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
629 continue;
630 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
631 }
632 return buf;
633}
634
635
441static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 636static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
442{ 637{
443 unsigned long i; 638 unsigned long i;
444 char *needed; 639 char *needed;
445 void *strtbl_void; 640 void *strtbl_void;
641 char *p;
446 642
447 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 643 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
448 644
449 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 645 strtbl_void = elf_findsecbyname(elf, ".dynstr");
450 646
470 } \ 666 } \
471 needed = (char*)(elf->data + offset); \ 667 needed = (char*)(elf->data + offset); \
472 if (op == 0) { \ 668 if (op == 0) { \
473 if (!be_wewy_wewy_quiet) { \ 669 if (!be_wewy_wewy_quiet) { \
474 if (*found_needed) xchrcat(ret, ',', ret_len); \ 670 if (*found_needed) xchrcat(ret, ',', ret_len); \
671 if (use_ldcache) \
672 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
673 needed = p; \
475 xstrcat(ret, needed, ret_len); \ 674 xstrcat(ret, needed, ret_len); \
476 } \ 675 } \
477 *found_needed = 1; \ 676 *found_needed = 1; \
478 } else { \ 677 } else { \
479 if (strcmp(find_lib, needed)) return NULL; \ 678 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
480 *found_lib = 1; \ 679 *found_lib = 1; \
481 return (be_wewy_wewy_quiet ? NULL : find_lib); \ 680 return (be_wewy_wewy_quiet ? NULL : needed); \
681 } \
482 } \ 682 } \
483 } \ 683 } \
484 ++dyn; \ 684 ++dyn; \
485 } \ 685 } \
486 } } 686 } }
487 SHOW_NEEDED(32) 687 SHOW_NEEDED(32)
488 SHOW_NEEDED(64) 688 SHOW_NEEDED(64)
689 if (op == 0 && !*found_needed && be_verbose)
690 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
489 } 691 }
490 692
491 return NULL; 693 return NULL;
492} 694}
493static char *scanelf_file_interp(elfobj *elf, char *found_interp) 695static char *scanelf_file_interp(elfobj *elf, char *found_interp)
551 } else { 753 } else {
552 *found_bind = 1; 754 *found_bind = 1;
553 return (char *) "LAZY"; 755 return (char *) "LAZY";
554 } 756 }
555} 757}
758static char *scanelf_file_soname(elfobj *elf, char *found_soname)
759{
760 unsigned long i;
761 char *soname;
762 void *strtbl_void;
763
764 if (!show_soname) return NULL;
765
766 strtbl_void = elf_findsecbyname(elf, ".dynstr");
767
768 if (elf->phdr && strtbl_void) {
769#define SHOW_SONAME(B) \
770 if (elf->elf_class == ELFCLASS ## B) { \
771 Elf ## B ## _Dyn *dyn; \
772 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
773 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
774 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
775 Elf ## B ## _Off offset; \
776 /* only look for soname in shared objects */ \
777 if (ehdr->e_type != ET_DYN) \
778 return NULL; \
779 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
780 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
781 offset = EGET(phdr[i].p_offset); \
782 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
783 dyn = DYN ## B (elf->data + offset); \
784 while (EGET(dyn->d_tag) != DT_NULL) { \
785 if (EGET(dyn->d_tag) == DT_SONAME) { \
786 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
787 if (offset >= (Elf ## B ## _Off)elf->len) { \
788 ++dyn; \
789 continue; \
790 } \
791 soname = (char*)(elf->data + offset); \
792 *found_soname = 1; \
793 return (be_wewy_wewy_quiet ? NULL : soname); \
794 } \
795 ++dyn; \
796 } \
797 } }
798 SHOW_SONAME(32)
799 SHOW_SONAME(64)
800 }
801
802 return NULL;
803}
556static char *scanelf_file_sym(elfobj *elf, char *found_sym) 804static char *scanelf_file_sym(elfobj *elf, char *found_sym)
557{ 805{
558 unsigned long i; 806 unsigned long i;
807 char *ret;
559 void *symtab_void, *strtab_void; 808 void *symtab_void, *strtab_void;
560 809
561 if (!find_sym) return NULL; 810 if (!find_sym) return NULL;
811 ret = find_sym;
562 812
563 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 813 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
564 814
565 if (symtab_void && strtab_void) { 815 if (symtab_void && strtab_void) {
566#define FIND_SYM(B) \ 816#define FIND_SYM(B) \
567 if (elf->elf_class == ELFCLASS ## B) { \ 817 if (elf->elf_class == ELFCLASS ## B) { \
568 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 818 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
569 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 819 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
570 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 820 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
571 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 821 unsigned long cnt = EGET(symtab->sh_entsize); \
572 char *symname; \ 822 char *symname; \
823 if (cnt) \
824 cnt = EGET(symtab->sh_size) / cnt; \
573 for (i = 0; i < cnt; ++i) { \ 825 for (i = 0; i < cnt; ++i) { \
574 if (sym->st_name) { \ 826 if (sym->st_name) { \
575 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 827 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
828 if ((void*)symname > (void*)elf->data_end) { \
829 warnf("%s: corrupt ELF symbols", elf->filename); \
830 continue; \
831 } \
576 if (*find_sym == '*') { \ 832 if (*find_sym == '*') { \
577 printf("%s(%s) %5lX %15s %s\n", \ 833 printf("%s(%s) %5lX %15s %s\n", \
578 ((*found_sym == 0) ? "\n\t" : "\t"), \ 834 ((*found_sym == 0) ? "\n\t" : "\t"), \
579 elf->base_filename, \ 835 elf->base_filename, \
580 (long)sym->st_size, \ 836 (unsigned long)sym->st_size, \
581 (char *)get_elfstttype(sym->st_info), \ 837 get_elfstttype(sym->st_info), \
582 symname); \ 838 symname); \
583 *found_sym = 1; \ 839 *found_sym = 1; \
584 } else if ((strcmp(find_sym, symname) == 0) || \ 840 } else { \
841 char *this_sym, *next_sym; \
842 this_sym = find_sym; \
843 do { \
844 next_sym = strchr(this_sym, ','); \
845 if (next_sym == NULL) \
846 next_sym = this_sym + strlen(this_sym); \
847 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
585 (strcmp(symname, versioned_symname) == 0)) \ 848 (strcmp(symname, versioned_symname) == 0)) { \
849 ret = this_sym; \
586 (*found_sym)++; \ 850 (*found_sym)++; \
851 goto break_out; \
852 } \
853 this_sym = next_sym + 1; \
854 } while (*next_sym != '\0'); \
855 } \
587 } \ 856 } \
588 ++sym; \ 857 ++sym; \
589 } } 858 } }
590 FIND_SYM(32) 859 FIND_SYM(32)
591 FIND_SYM(64) 860 FIND_SYM(64)
592 } 861 }
593 862
863break_out:
594 if (be_wewy_wewy_quiet) return NULL; 864 if (be_wewy_wewy_quiet) return NULL;
595 865
596 if (*find_sym != '*' && *found_sym) 866 if (*find_sym != '*' && *found_sym)
597 return find_sym; 867 return ret;
598 if (be_quiet) 868 if (be_quiet)
599 return NULL; 869 return NULL;
600 else 870 else
601 return (char *)" - "; 871 return (char *)" - ";
602} 872}
873
874
603/* scan an elf file and show all the fun stuff */ 875/* scan an elf file and show all the fun stuff */
604#define prints(str) write(fileno(stdout), str, strlen(str)) 876#define prints(str) write(fileno(stdout), str, strlen(str))
605static void scanelf_file(const char *filename) 877static int scanelf_elfobj(elfobj *elf)
606{ 878{
607 unsigned long i; 879 unsigned long i;
608 char found_pax, found_phdr, found_relro, found_load, found_textrel, 880 char found_pax, found_phdr, found_relro, found_load, found_textrel,
609 found_rpath, found_needed, found_interp, found_bind, 881 found_rpath, found_needed, found_interp, found_bind, found_soname,
610 found_sym, found_lib, found_file, found_textrels; 882 found_sym, found_lib, found_file, found_textrels;
611 elfobj *elf;
612 struct stat st;
613 static char *out_buffer = NULL; 883 static char *out_buffer = NULL;
614 static size_t out_len; 884 static size_t out_len;
615 885
616 /* make sure 'filename' exists */
617 if (lstat(filename, &st) == -1) {
618 if (be_verbose > 2) printf("%s: does not exist\n", filename);
619 return;
620 }
621 /* always handle regular files and handle symlinked files if no -y */
622 if (S_ISLNK(st.st_mode)) {
623 if (!scan_symlink) return;
624 stat(filename, &st);
625 }
626 if (!S_ISREG(st.st_mode)) {
627 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
628 return;
629 }
630
631 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 886 found_pax = found_phdr = found_relro = found_load = found_textrel = \
632 found_rpath = found_needed = found_interp = found_bind = \ 887 found_rpath = found_needed = found_interp = found_bind = found_soname = \
633 found_sym = found_lib = found_file = found_textrels = 0; 888 found_sym = found_lib = found_file = found_textrels = 0;
634 889
635 /* verify this is real ELF */
636 if ((elf = readelf(filename)) == NULL) {
637 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
638 return;
639 }
640
641 if (be_verbose > 1) 890 if (be_verbose > 2)
642 printf("%s: scanning file {%s,%s}\n", filename, 891 printf("%s: scanning file {%s,%s}\n", elf->filename,
643 get_elfeitype(EI_CLASS, elf->elf_class), 892 get_elfeitype(EI_CLASS, elf->elf_class),
644 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 893 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
645 else if (be_verbose) 894 else if (be_verbose > 1)
646 printf("%s: scanning file\n", filename); 895 printf("%s: scanning file\n", elf->filename);
647 896
648 /* init output buffer */ 897 /* init output buffer */
649 if (!out_buffer) { 898 if (!out_buffer) {
650 out_len = sizeof(char) * 80; 899 out_len = sizeof(char) * 80;
651 out_buffer = (char*)xmalloc(out_len); 900 out_buffer = (char*)xmalloc(out_len);
669 case 't': prints("TEXTREL "); break; 918 case 't': prints("TEXTREL "); break;
670 case 'r': prints("RPATH "); break; 919 case 'r': prints("RPATH "); break;
671 case 'n': prints("NEEDED "); break; 920 case 'n': prints("NEEDED "); break;
672 case 'i': prints("INTERP "); break; 921 case 'i': prints("INTERP "); break;
673 case 'b': prints("BIND "); break; 922 case 'b': prints("BIND "); break;
923 case 'S': prints("SONAME "); break;
674 case 's': prints("SYM "); break; 924 case 's': prints("SYM "); break;
675 case 'N': prints("LIB "); break; 925 case 'N': prints("LIB "); break;
676 case 'T': prints("TEXTRELS "); break; 926 case 'T': prints("TEXTRELS "); break;
677 default: warnf("'%c' has no title ?", out_format[i]); 927 default: warnf("'%c' has no title ?", out_format[i]);
678 } 928 }
704 case '#': 954 case '#':
705 xchrcat(&out_buffer, out_format[i], &out_len); break; 955 xchrcat(&out_buffer, out_format[i], &out_len); break;
706 case 'F': 956 case 'F':
707 found_file = 1; 957 found_file = 1;
708 if (be_wewy_wewy_quiet) break; 958 if (be_wewy_wewy_quiet) break;
709 xstrcat(&out_buffer, filename, &out_len); 959 xstrcat(&out_buffer, elf->filename, &out_len);
710 break; 960 break;
711 case 'p': 961 case 'p':
712 found_file = 1; 962 found_file = 1;
713 if (be_wewy_wewy_quiet) break; 963 if (be_wewy_wewy_quiet) break;
714 tmp = filename; 964 tmp = elf->filename;
715 if (search_path) { 965 if (search_path) {
716 ssize_t len_search = strlen(search_path); 966 ssize_t len_search = strlen(search_path);
717 ssize_t len_file = strlen(filename); 967 ssize_t len_file = strlen(elf->filename);
718 if (!strncmp(filename, search_path, len_search) && \ 968 if (!strncmp(elf->filename, search_path, len_search) && \
719 len_file > len_search) 969 len_file > len_search)
720 tmp += len_search; 970 tmp += len_search;
721 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 971 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
722 } 972 }
723 xstrcat(&out_buffer, tmp, &out_len); 973 xstrcat(&out_buffer, tmp, &out_len);
724 break; 974 break;
725 case 'f': 975 case 'f':
726 found_file = 1; 976 found_file = 1;
727 if (be_wewy_wewy_quiet) break; 977 if (be_wewy_wewy_quiet) break;
728 tmp = strrchr(filename, '/'); 978 tmp = strrchr(elf->filename, '/');
729 tmp = (tmp == NULL ? filename : tmp+1); 979 tmp = (tmp == NULL ? elf->filename : tmp+1);
730 xstrcat(&out_buffer, tmp, &out_len); 980 xstrcat(&out_buffer, tmp, &out_len);
731 break; 981 break;
732 case 'o': out = get_elfetype(elf); break; 982 case 'o': out = get_elfetype(elf); break;
733 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 983 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
734 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 984 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
735 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 985 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
736 case 'T': out = scanelf_file_textrels(elf, &found_textrels); break; 986 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
737 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 987 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
738 case 'n': 988 case 'n':
739 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 989 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
740 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 990 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
741 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 991 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
992 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
742 case 's': out = scanelf_file_sym(elf, &found_sym); break; 993 case 's': out = scanelf_file_sym(elf, &found_sym); break;
743 default: warnf("'%c' has no scan code?", out_format[i]); 994 default: warnf("'%c' has no scan code?", out_format[i]);
744 } 995 }
996 if (out) {
997 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
998 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
999 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1000 else
745 if (out) xstrcat(&out_buffer, out, &out_len); 1001 xstrcat(&out_buffer, out, &out_len);
1002 }
746 } 1003 }
747 1004
748#define FOUND_SOMETHING() \ 1005#define FOUND_SOMETHING() \
749 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1006 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
750 found_rpath || found_needed || found_interp || found_bind || \ 1007 found_rpath || found_needed || found_interp || found_bind || \
751 found_sym || found_lib || found_textrels) 1008 found_soname || found_sym || found_lib || found_textrels)
752 1009
753 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1010 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
754 xchrcat(&out_buffer, ' ', &out_len); 1011 xchrcat(&out_buffer, ' ', &out_len);
755 xstrcat(&out_buffer, filename, &out_len); 1012 xstrcat(&out_buffer, elf->filename, &out_len);
756 } 1013 }
757 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) 1014 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
758 puts(out_buffer); 1015 puts(out_buffer);
1016 fflush(stdout);
1017 }
759 1018
1019 return 0;
1020}
1021
1022/* scan a single elf */
1023static int scanelf_elf(const char *filename, int fd, size_t len)
1024{
1025 int ret;
1026 elfobj *elf;
1027
1028 /* verify this is real ELF */
1029 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1030 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1031 return 1;
1032 }
1033
1034 if (strlen(match_etypes)) {
1035 char sbuf[126];
1036 strncpy(sbuf, match_etypes, sizeof(sbuf));
1037 if (strchr(match_etypes, ',') != NULL) {
1038 char *p;
1039 while((p = strrchr(sbuf, ',')) != NULL) {
1040 *p = 0;
1041 if (atoi(p+1) == get_etype(elf))
1042 goto label_ret;
1043 }
1044 }
1045 if (atoi(sbuf) != get_etype(elf)) {
1046 ret = 1;
1047 goto label_done;
1048 }
1049 }
1050
1051label_ret:
1052 ret = scanelf_elfobj(elf);
1053
1054label_done:
760 unreadelf(elf); 1055 unreadelf(elf);
1056 return ret;
1057}
1058
1059/* scan an archive of elfs */
1060static int scanelf_archive(const char *filename, int fd, size_t len)
1061{
1062 archive_handle *ar;
1063 archive_member *m;
1064 char *ar_buffer;
1065 elfobj *elf;
1066
1067 ar = ar_open_fd(filename, fd);
1068 if (ar == NULL)
1069 return 1;
1070
1071 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1072 while ((m=ar_next(ar)) != NULL) {
1073 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1074 if (elf) {
1075 scanelf_elfobj(elf);
1076 unreadelf(elf);
1077 }
1078 }
1079 munmap(ar_buffer, len);
1080
1081 return 0;
1082}
1083/* scan a file which may be an elf or an archive or some other magical beast */
1084static void scanelf_file(const char *filename)
1085{
1086 struct stat st;
1087 int fd;
1088
1089 /* make sure 'filename' exists */
1090 if (lstat(filename, &st) == -1) {
1091 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1092 return;
1093 }
1094
1095 /* always handle regular files and handle symlinked files if no -y */
1096 if (S_ISLNK(st.st_mode)) {
1097 if (!scan_symlink) return;
1098 stat(filename, &st);
1099 }
1100 if (!S_ISREG(st.st_mode)) {
1101 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1102 return;
1103 }
1104
1105 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1106 return;
1107
1108 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1109 /* if it isn't an ELF, maybe it's an .a archive */
1110 scanelf_archive(filename, fd, st.st_size);
1111
1112 close(fd);
761} 1113}
762 1114
763/* scan a directory for ET_EXEC files and print when we find one */ 1115/* scan a directory for ET_EXEC files and print when we find one */
764static void scanelf_dir(const char *path) 1116static void scanelf_dir(const char *path)
765{ 1117{
766 register DIR *dir; 1118 register DIR *dir;
767 register struct dirent *dentry; 1119 register struct dirent *dentry;
768 struct stat st_top, st; 1120 struct stat st_top, st;
769 char buf[_POSIX_PATH_MAX]; 1121 char buf[__PAX_UTILS_PATH_MAX];
770 size_t pathlen = 0, len = 0; 1122 size_t pathlen = 0, len = 0;
771 1123
772 /* make sure path exists */ 1124 /* make sure path exists */
773 if (lstat(path, &st_top) == -1) { 1125 if (lstat(path, &st_top) == -1) {
774 if (be_verbose > 2) printf("%s: does not exist\n", path); 1126 if (be_verbose > 2) printf("%s: does not exist\n", path);
784 /* now scan the dir looking for fun stuff */ 1136 /* now scan the dir looking for fun stuff */
785 if ((dir = opendir(path)) == NULL) { 1137 if ((dir = opendir(path)) == NULL) {
786 warnf("could not opendir %s: %s", path, strerror(errno)); 1138 warnf("could not opendir %s: %s", path, strerror(errno));
787 return; 1139 return;
788 } 1140 }
789 if (be_verbose) printf("%s: scanning dir\n", path); 1141 if (be_verbose > 1) printf("%s: scanning dir\n", path);
790 1142
791 pathlen = strlen(path); 1143 pathlen = strlen(path);
792 while ((dentry = readdir(dir))) { 1144 while ((dentry = readdir(dir))) {
793 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1145 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
794 continue; 1146 continue;
813 1165
814static int scanelf_from_file(char *filename) 1166static int scanelf_from_file(char *filename)
815{ 1167{
816 FILE *fp = NULL; 1168 FILE *fp = NULL;
817 char *p; 1169 char *p;
818 char path[_POSIX_PATH_MAX]; 1170 char path[__PAX_UTILS_PATH_MAX];
819 1171
820 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1172 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
821 fp = stdin; 1173 fp = stdin;
822 else if ((fp = fopen(filename, "r")) == NULL) 1174 else if ((fp = fopen(filename, "r")) == NULL)
823 return 1; 1175 return 1;
824 1176
825 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1177 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
826 if ((p = strchr(path, '\n')) != NULL) 1178 if ((p = strchr(path, '\n')) != NULL)
827 *p = 0; 1179 *p = 0;
828 search_path = path; 1180 search_path = path;
829 scanelf_dir(path); 1181 scanelf_dir(path);
830 } 1182 }
835 1187
836static void load_ld_so_conf() 1188static void load_ld_so_conf()
837{ 1189{
838 FILE *fp = NULL; 1190 FILE *fp = NULL;
839 char *p; 1191 char *p;
840 char path[_POSIX_PATH_MAX]; 1192 char path[__PAX_UTILS_PATH_MAX];
841 int i = 0; 1193 int i = 0;
842 1194
843 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1195 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
844 return; 1196 return;
845 1197
846 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1198 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
847 if (*path != '/') 1199 if (*path != '/')
848 continue; 1200 continue;
849 1201
850 if ((p = strrchr(path, '\r')) != NULL) 1202 if ((p = strrchr(path, '\r')) != NULL)
851 *p = 0; 1203 *p = 0;
903 1255
904 free(path); 1256 free(path);
905} 1257}
906 1258
907 1259
908
909/* usage / invocation handling functions */ 1260/* usage / invocation handling functions */
910#define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV" 1261#define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:E:BhV"
911#define a_argument required_argument 1262#define a_argument required_argument
912static struct option const long_opts[] = { 1263static struct option const long_opts[] = {
913 {"path", no_argument, NULL, 'p'}, 1264 {"path", no_argument, NULL, 'p'},
914 {"ldpath", no_argument, NULL, 'l'}, 1265 {"ldpath", no_argument, NULL, 'l'},
915 {"recursive", no_argument, NULL, 'R'}, 1266 {"recursive", no_argument, NULL, 'R'},
916 {"mount", no_argument, NULL, 'm'}, 1267 {"mount", no_argument, NULL, 'm'},
917 {"symlink", no_argument, NULL, 'y'}, 1268 {"symlink", no_argument, NULL, 'y'},
1269 {"archives", no_argument, NULL, 'A'},
1270 {"ldcache", no_argument, NULL, 'L'},
1271 {"fix", no_argument, NULL, 'X'},
918 {"pax", no_argument, NULL, 'x'}, 1272 {"pax", no_argument, NULL, 'x'},
919 {"header", no_argument, NULL, 'e'}, 1273 {"header", no_argument, NULL, 'e'},
920 {"textrel", no_argument, NULL, 't'}, 1274 {"textrel", no_argument, NULL, 't'},
921 {"rpath", no_argument, NULL, 'r'}, 1275 {"rpath", no_argument, NULL, 'r'},
922 {"needed", no_argument, NULL, 'n'}, 1276 {"needed", no_argument, NULL, 'n'},
923 {"interp", no_argument, NULL, 'i'}, 1277 {"interp", no_argument, NULL, 'i'},
924 {"bind", no_argument, NULL, 'b'}, 1278 {"bind", no_argument, NULL, 'b'},
1279 {"soname", no_argument, NULL, 'S'},
925 {"symbol", a_argument, NULL, 's'}, 1280 {"symbol", a_argument, NULL, 's'},
926 {"lib", a_argument, NULL, 'N'}, 1281 {"lib", a_argument, NULL, 'N'},
1282 {"gmatch", no_argument, NULL, 'g'},
927 {"textrels", no_argument, NULL, 'T'}, 1283 {"textrels", no_argument, NULL, 'T'},
1284 {"etype", a_argument, NULL, 'E'},
928 {"all", no_argument, NULL, 'a'}, 1285 {"all", no_argument, NULL, 'a'},
929 {"quiet", no_argument, NULL, 'q'}, 1286 {"quiet", no_argument, NULL, 'q'},
930 {"verbose", no_argument, NULL, 'v'}, 1287 {"verbose", no_argument, NULL, 'v'},
931 {"format", a_argument, NULL, 'F'}, 1288 {"format", a_argument, NULL, 'F'},
932 {"from", a_argument, NULL, 'f'}, 1289 {"from", a_argument, NULL, 'f'},
940static const char *opts_help[] = { 1297static const char *opts_help[] = {
941 "Scan all directories in PATH environment", 1298 "Scan all directories in PATH environment",
942 "Scan all directories in /etc/ld.so.conf", 1299 "Scan all directories in /etc/ld.so.conf",
943 "Scan directories recursively", 1300 "Scan directories recursively",
944 "Don't recursively cross mount points", 1301 "Don't recursively cross mount points",
945 "Don't scan symlinks\n", 1302 "Don't scan symlinks",
1303 "Scan archives (.a files)",
1304 "Utilize ld.so.cache information (use with -r/-n)",
1305 "Try and 'fix' bad things (use with -r/-e)\n",
946 "Print PaX markings", 1306 "Print PaX markings",
947 "Print GNU_STACK/PT_LOAD markings", 1307 "Print GNU_STACK/PT_LOAD markings",
948 "Print TEXTREL information", 1308 "Print TEXTREL information",
949 "Print RPATH information", 1309 "Print RPATH information",
950 "Print NEEDED information", 1310 "Print NEEDED information",
951 "Print INTERP information", 1311 "Print INTERP information",
952 "Print BIND information", 1312 "Print BIND information",
1313 "Print SONAME information",
953 "Find a specified symbol", 1314 "Find a specified symbol",
954 "Find a specified library", 1315 "Find a specified library",
1316 "Use strncmp to match libraries. (use with -N)",
955 "Locate cause of TEXTREL", 1317 "Locate cause of TEXTREL",
1318 "Print only ELF files matching numeric constant",
956 "Print all scanned info (-x -e -t -r -n -i -b)\n", 1319 "Print all scanned info (-x -e -t -r -b)\n",
957 "Only output 'bad' things", 1320 "Only output 'bad' things",
958 "Be verbose (can be specified more than once)", 1321 "Be verbose (can be specified more than once)",
959 "Use specified format for output", 1322 "Use specified format for output",
960 "Read input stream from a filename", 1323 "Read input stream from a filename",
961 "Write output stream to a filename", 1324 "Write output stream to a filename",
968/* display usage and exit */ 1331/* display usage and exit */
969static void usage(int status) 1332static void usage(int status)
970{ 1333{
971 unsigned long i; 1334 unsigned long i;
972 printf("* Scan ELF binaries for stuff\n\n" 1335 printf("* Scan ELF binaries for stuff\n\n"
973 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1336 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
974 printf("Options: -[%s]\n", PARSE_FLAGS); 1337 printf("Options: -[%s]\n", PARSE_FLAGS);
975 for (i = 0; long_opts[i].name; ++i) 1338 for (i = 0; long_opts[i].name; ++i)
976 if (long_opts[i].has_arg == no_argument) 1339 if (long_opts[i].has_arg == no_argument)
977 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1340 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
978 long_opts[i].name, opts_help[i]); 1341 long_opts[i].name, opts_help[i]);
986 puts("\nThe format modifiers for the -F option are:"); 1349 puts("\nThe format modifiers for the -F option are:");
987 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1350 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
988 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1351 puts(" t TEXTREL \tr RPATH \tn NEEDED");
989 puts(" i INTERP \tb BIND \ts symbol"); 1352 puts(" i INTERP \tb BIND \ts symbol");
990 puts(" N library \to Type \tT TEXTRELs"); 1353 puts(" N library \to Type \tT TEXTRELs");
1354 puts(" S SONAME");
991 puts(" p filename (with search path removed)"); 1355 puts(" p filename (with search path removed)");
992 puts(" f base filename"); 1356 puts(" f filename (short name/basename)");
993 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1357 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
994 1358
995 exit(status); 1359 exit(status);
996} 1360}
997 1361
1004 opterr = 0; 1368 opterr = 0;
1005 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1369 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1006 switch (i) { 1370 switch (i) {
1007 1371
1008 case 'V': 1372 case 'V':
1009 printf("%s compiled %s\n%s\n" 1373 printf("pax-utils-%s: %s compiled %s\n%s\n"
1010 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1374 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1011 __FILE__, __DATE__, rcsid, argv0); 1375 VERSION, __FILE__, __DATE__, rcsid, argv0);
1012 exit(EXIT_SUCCESS); 1376 exit(EXIT_SUCCESS);
1013 break; 1377 break;
1014 case 'h': usage(EXIT_SUCCESS); break; 1378 case 'h': usage(EXIT_SUCCESS); break;
1015 case 'f': 1379 case 'f':
1016 if (from_file) err("Don't specify -f twice"); 1380 if (from_file) warn("You prob don't want to specify -f twice");
1017 from_file = xstrdup(optarg); 1381 from_file = optarg;
1382 break;
1383 case 'E':
1384 strncpy(match_etypes, optarg, sizeof(match_etypes));
1018 break; 1385 break;
1019 case 'o': { 1386 case 'o': {
1020 FILE *fp = NULL; 1387 FILE *fp = NULL;
1021 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1388 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1022 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1389 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1023 SET_STDOUT(fp); 1390 SET_STDOUT(fp);
1024 break; 1391 break;
1025 } 1392 }
1026 1393
1027 case 's': { 1394 case 's': {
1028 size_t len;
1029 if (find_sym) err("Don't specify -s twice"); 1395 if (find_sym) warn("You prob don't want to specify -s twice");
1030 find_sym = xstrdup(optarg); 1396 find_sym = optarg;
1031 len = strlen(find_sym) + 1;
1032 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1397 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1033 sprintf(versioned_symname, "%s@", find_sym); 1398 sprintf(versioned_symname, "%s@", find_sym);
1034 break; 1399 break;
1035 } 1400 }
1036 case 'N': { 1401 case 'N': {
1037 if (find_lib) err("Don't specify -N twice"); 1402 if (find_lib) warn("You prob don't want to specify -N twice");
1038 find_lib = xstrdup(optarg); 1403 find_lib = optarg;
1039 break; 1404 break;
1040 } 1405 }
1041 1406
1042 case 'F': { 1407 case 'F': {
1043 if (out_format) err("Don't specify -F twice"); 1408 if (out_format) warn("You prob don't want to specify -F twice");
1044 out_format = xstrdup(optarg); 1409 out_format = optarg;
1045 break; 1410 break;
1046 } 1411 }
1047 1412
1413 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */
1414 case 'L': use_ldcache = 1; break;
1048 case 'y': scan_symlink = 0; break; 1415 case 'y': scan_symlink = 0; break;
1416 case 'A': scan_archives = 1; break;
1049 case 'B': show_banner = 0; break; 1417 case 'B': show_banner = 0; break;
1050 case 'l': scan_ldpath = 1; break; 1418 case 'l': scan_ldpath = 1; break;
1051 case 'p': scan_envpath = 1; break; 1419 case 'p': scan_envpath = 1; break;
1052 case 'R': dir_recurse = 1; break; 1420 case 'R': dir_recurse = 1; break;
1053 case 'm': dir_crossmount = 0; break; 1421 case 'm': dir_crossmount = 0; break;
1422 case 'X': ++fix_elf; break;
1054 case 'x': show_pax = 1; break; 1423 case 'x': show_pax = 1; break;
1055 case 'e': show_phdr = 1; break; 1424 case 'e': show_phdr = 1; break;
1056 case 't': show_textrel = 1; break; 1425 case 't': show_textrel = 1; break;
1057 case 'r': show_rpath = 1; break; 1426 case 'r': show_rpath = 1; break;
1058 case 'n': show_needed = 1; break; 1427 case 'n': show_needed = 1; break;
1059 case 'i': show_interp = 1; break; 1428 case 'i': show_interp = 1; break;
1060 case 'b': show_bind = 1; break; 1429 case 'b': show_bind = 1; break;
1430 case 'S': show_soname = 1; break;
1061 case 'T': show_textrels = 1; break; 1431 case 'T': show_textrels = 1; break;
1062 case 'q': be_quiet = 1; break; 1432 case 'q': be_quiet = 1; break;
1063 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1433 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1064 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \ 1434 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1065 show_needed = show_interp = show_bind = 1; break;
1066 1435
1067 case ':': 1436 case ':':
1068 err("Option missing parameter\n"); 1437 err("Option '%c' is missing parameter", optopt);
1069 case '?': 1438 case '?':
1070 err("Unknown option\n"); 1439 err("Unknown option '%c' or argument missing", optopt);
1071 default: 1440 default:
1072 err("Unhandled option '%c'", i); 1441 err("Unhandled option '%c'; please report this", i);
1073 } 1442 }
1074 } 1443 }
1075 1444
1076 /* let the format option override all other options */ 1445 /* let the format option override all other options */
1077 if (out_format) { 1446 if (out_format) {
1078 show_pax = show_phdr = show_textrel = show_rpath = \ 1447 show_pax = show_phdr = show_textrel = show_rpath = \
1079 show_needed = show_interp = show_bind = show_textrels = 0; 1448 show_needed = show_interp = show_bind = show_soname = \
1449 show_textrels = 0;
1080 for (i = 0; out_format[i]; ++i) { 1450 for (i = 0; out_format[i]; ++i) {
1081 if (!IS_MODIFIER(out_format[i])) continue; 1451 if (!IS_MODIFIER(out_format[i])) continue;
1082 1452
1083 switch (out_format[++i]) { 1453 switch (out_format[++i]) {
1084 case '%': break; 1454 case '%': break;
1094 case 't': show_textrel = 1; break; 1464 case 't': show_textrel = 1; break;
1095 case 'r': show_rpath = 1; break; 1465 case 'r': show_rpath = 1; break;
1096 case 'n': show_needed = 1; break; 1466 case 'n': show_needed = 1; break;
1097 case 'i': show_interp = 1; break; 1467 case 'i': show_interp = 1; break;
1098 case 'b': show_bind = 1; break; 1468 case 'b': show_bind = 1; break;
1469 case 'S': show_soname = 1; break;
1099 case 'T': show_textrels = 1; break; 1470 case 'T': show_textrels = 1; break;
1100 default: 1471 default:
1101 err("Invalid format specifier '%c' (byte %i)", 1472 err("Invalid format specifier '%c' (byte %i)",
1102 out_format[i], i+1); 1473 out_format[i], i+1);
1103 } 1474 }
1113 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1484 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1114 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1485 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1115 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1486 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1116 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1487 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1117 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1488 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1489 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1118 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1490 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1119 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1491 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1120 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1492 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1121 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1493 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1122 } 1494 }
1123 if (be_verbose > 2) printf("Format: %s\n", out_format); 1495 if (be_verbose > 2) printf("Format: %s\n", out_format);
1124 1496
1125 /* now lets actually do the scanning */ 1497 /* now lets actually do the scanning */
1126 if (scan_ldpath || (show_rpath && be_quiet)) 1498 if (scan_ldpath || use_ldcache)
1127 load_ld_so_conf(); 1499 load_ld_so_conf();
1128 if (scan_ldpath) scanelf_ldpath(); 1500 if (scan_ldpath) scanelf_ldpath();
1129 if (scan_envpath) scanelf_envpath(); 1501 if (scan_envpath) scanelf_envpath();
1130 if (from_file) { 1502 if (from_file) {
1131 scanelf_from_file(from_file); 1503 scanelf_from_file(from_file);
1132 free(from_file);
1133 from_file = *argv; 1504 from_file = *argv;
1134 } 1505 }
1135 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1506 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1136 err("Nothing to scan !?"); 1507 err("Nothing to scan !?");
1137 while (optind < argc) { 1508 while (optind < argc) {
1138 search_path = argv[optind++]; 1509 search_path = argv[optind++];
1139 scanelf_dir(search_path); 1510 scanelf_dir(search_path);
1140 } 1511 }
1141 1512
1142 /* clean up */ 1513 /* clean up */
1143 if (find_sym) { 1514 if (versioned_symname) free(versioned_symname);
1144 free(find_sym);
1145 free(versioned_symname);
1146 }
1147 if (find_lib) free(find_lib);
1148 if (out_format) free(out_format);
1149 for (i = 0; ldpaths[i]; ++i) 1515 for (i = 0; ldpaths[i]; ++i)
1150 free(ldpaths[i]); 1516 free(ldpaths[i]);
1517
1518 if (ldcache != 0)
1519 munmap(ldcache, ldcache_size);
1151} 1520}
1152 1521
1153 1522
1154 1523
1155/* utility funcs */ 1524/* utility funcs */
1157{ 1526{
1158 char *ret = strdup(s); 1527 char *ret = strdup(s);
1159 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1528 if (!ret) err("Could not strdup(): %s", strerror(errno));
1160 return ret; 1529 return ret;
1161} 1530}
1162
1163static void *xmalloc(size_t size) 1531static void *xmalloc(size_t size)
1164{ 1532{
1165 void *ret = malloc(size); 1533 void *ret = malloc(size);
1166 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1534 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1167 return ret; 1535 return ret;
1168} 1536}
1169
1170static void xstrcat(char **dst, const char *src, size_t *curr_len) 1537static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1171{ 1538{
1172 size_t new_len; 1539 size_t new_len;
1173 1540
1174 new_len = strlen(*dst) + strlen(src); 1541 new_len = strlen(*dst) + strlen(src);
1175 if (*curr_len <= new_len) { 1542 if (*curr_len <= new_len) {
1176 *curr_len = new_len + (*curr_len / 2); 1543 *curr_len = new_len + (*curr_len / 2);
1177 *dst = realloc(*dst, *curr_len); 1544 *dst = realloc(*dst, *curr_len);
1178 if (!*dst) 1545 if (!*dst)
1179 err("could not realloc %li bytes", (unsigned long)*curr_len); 1546 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1180 } 1547 }
1181 1548
1549 if (n)
1550 strncat(*dst, src, n);
1551 else
1182 strcat(*dst, src); 1552 strcat(*dst, src);
1183} 1553}
1184
1185static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1554static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1186{ 1555{
1187 static char my_app[2]; 1556 static char my_app[2];
1188 my_app[0] = append; 1557 my_app[0] = append;
1189 my_app[1] = '\0'; 1558 my_app[1] = '\0';

Legend:
Removed from v.1.78  
changed lines
  Added in v.1.119

  ViewVC Help
Powered by ViewVC 1.1.20