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

Legend:
Removed from v.1.46  
changed lines
  Added in v.1.91

  ViewVC Help
Powered by ViewVC 1.1.20