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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.104

  ViewVC Help
Powered by ViewVC 1.1.20