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

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

  ViewVC Help
Powered by ViewVC 1.1.20