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

Legend:
Removed from v.1.34  
changed lines
  Added in v.1.127

  ViewVC Help
Powered by ViewVC 1.1.20