/[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.81 Revision 1.127
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2006 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.81 2005/06/13 03:35:41 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.127 2006/02/17 07:13:54 solar Exp $
5 * 5 *
6 ******************************************************************** 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
21 */ 8 */
22 9
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <libgen.h>
27#include <limits.h>
28#define __USE_GNU
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/stat.h>
33#include <dirent.h>
34#include <getopt.h>
35#include <assert.h>
36#include "paxelf.h" 10#include "paxinc.h"
37 11
38static const char *rcsid = "$Id: scanelf.c,v 1.81 2005/06/13 03:35:41 vapier Exp $"; 12static const char *rcsid = "$Id: scanelf.c,v 1.127 2006/02/17 07:13:54 solar Exp $";
39#define argv0 "scanelf" 13#define argv0 "scanelf"
40 14
41#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#')
42 16
43 17
44 18
45/* prototypes */ 19/* prototypes */
20static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len);
46static void scanelf_file(const char *filename); 23static void scanelf_file(const char *filename);
47static void scanelf_dir(const char *path); 24static void scanelf_dir(const char *path);
48static void scanelf_ldpath(); 25static void scanelf_ldpath(void);
49static void scanelf_envpath(); 26static void scanelf_envpath(void);
50static void usage(int status); 27static void usage(int status);
51static void parseargs(int argc, char *argv[]); 28static void parseargs(int argc, char *argv[]);
52static char *xstrdup(const char *s); 29static char *xstrdup(const char *s);
53static void *xmalloc(size_t size); 30static void *xmalloc(size_t size);
54static void xstrcat(char **dst, const char *src, size_t *curr_len); 31static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
55static inline void xchrcat(char **dst, const char append, size_t *curr_len); 33static inline void xchrcat(char **dst, const char append, size_t *curr_len);
56 34
57/* variables to control behavior */ 35/* variables to control behavior */
36static char match_etypes[126] = "";
58static char *ldpaths[256]; 37static char *ldpaths[256];
59static char scan_ldpath = 0; 38static char scan_ldpath = 0;
60static char scan_envpath = 0; 39static char scan_envpath = 0;
61static char scan_symlink = 1; 40static char scan_symlink = 1;
41static char scan_archives = 0;
62static char dir_recurse = 0; 42static char dir_recurse = 0;
63static char dir_crossmount = 1; 43static char dir_crossmount = 1;
64static char show_pax = 0; 44static char show_pax = 0;
65static char show_phdr = 0; 45static char show_phdr = 0;
66static char show_textrel = 0; 46static char show_textrel = 0;
67static char show_rpath = 0; 47static char show_rpath = 0;
68static char show_needed = 0; 48static char show_needed = 0;
69static char show_interp = 0; 49static char show_interp = 0;
70static char show_bind = 0; 50static char show_bind = 0;
51static char show_soname = 0;
71static char show_textrels = 0; 52static char show_textrels = 0;
72static char show_banner = 1; 53static char show_banner = 1;
73static char be_quiet = 0; 54static char be_quiet = 0;
74static char be_verbose = 0; 55static char be_verbose = 0;
75static char be_wewy_wewy_quiet = 0; 56static char be_wewy_wewy_quiet = 0;
76static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL; 58static char *find_lib = NULL;
59static char *find_section = NULL;
78static char *out_format = NULL; 60static char *out_format = NULL;
79static char *search_path = NULL; 61static char *search_path = NULL;
62static char fix_elf = 0;
63static char gmatch = 0;
64static char use_ldcache = 0;
80 65
81 66int match_bits = 0;
67caddr_t ldcache = 0;
68size_t ldcache_size = 0;
69unsigned long setpax = 0UL;
82 70
83/* sub-funcs for scanelf_file() */ 71/* sub-funcs for scanelf_file() */
84static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
85{ 73{
86 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
105 } \ 93 } \
106 } 94 }
107 GET_SYMTABS(32) 95 GET_SYMTABS(32)
108 GET_SYMTABS(64) 96 GET_SYMTABS(64)
109} 97}
98
110static char *scanelf_file_pax(elfobj *elf, char *found_pax) 99static char *scanelf_file_pax(elfobj *elf, char *found_pax)
111{ 100{
112 static char *paxflags;
113 static char ret[7]; 101 static char ret[7];
114 unsigned long i, shown; 102 unsigned long i, shown;
115
116 103
117 if (!show_pax) return NULL; 104 if (!show_pax) return NULL;
118 105
119 shown = 0; 106 shown = 0;
120 memset(&ret, 0, sizeof(ret)); 107 memset(&ret, 0, sizeof(ret));
125 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 112 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
126 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 113 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
127 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 114 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
128 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 115 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
129 continue; \ 116 continue; \
117 if (fix_elf && setpax) { \
118 /* set the paxctl flags */ \
119 ESET(phdr[i].p_flags, setpax); \
120 } \
130 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 121 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
131 continue; \ 122 continue; \
132 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 123 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
133 *found_pax = 1; \ 124 *found_pax = 1; \
134 ++shown; \ 125 ++shown; \
139 SHOW_PAX(64) 130 SHOW_PAX(64)
140 } 131 }
141 132
142 /* fall back to EI_PAX if no PT_PAX was found */ 133 /* fall back to EI_PAX if no PT_PAX was found */
143 if (!*ret) { 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
144 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 142 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
145 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 143 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
146 *found_pax = 1; 144 *found_pax = 1;
147 return paxflags; 145 return (be_wewy_wewy_quiet ? NULL : paxflags);
148 } 146 }
149 strncpy(ret, paxflags, sizeof(ret)); 147 strncpy(ret, paxflags, sizeof(ret));
150 // ++shown;
151 } 148 }
152 149
153 if (be_quiet && !shown) 150 if (be_wewy_wewy_quiet || (be_quiet && !shown))
154 return NULL; 151 return NULL;
152 else
155 return ret; 153 return ret;
156
157} 154}
155
158static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 156static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
159{ 157{
160 static char ret[12]; 158 static char ret[12];
161 char *found; 159 char *found;
162 unsigned long i, off, shown, check_flags;
163 unsigned char multi_stack, multi_relro, multi_load; 160 unsigned long i, shown, multi_stack, multi_relro, multi_load;
161 int max_pt_load;
164 162
165 if (!show_phdr) return NULL; 163 if (!show_phdr) return NULL;
166 164
167 memcpy(ret, "--- --- ---\0", 12); 165 memcpy(ret, "--- --- ---\0", 12);
168 166
169 shown = 0; 167 shown = 0;
170 multi_stack = multi_relro = multi_load = 0; 168 multi_stack = multi_relro = multi_load = 0;
169 max_pt_load = elf_max_pt_load(elf);
171 170
172 if (elf->phdr) { 171#define NOTE_GNU_STACK ".note.GNU-stack"
173#define SHOW_PHDR(B) \ 172#define SHOW_PHDR(B) \
174 if (elf->elf_class == ELFCLASS ## B) { \ 173 if (elf->elf_class == ELFCLASS ## B) { \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 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) { \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 178 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 uint32_t flags; \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 179 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
179 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 180 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
180 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 181 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
181 found = found_phdr; \ 182 found = found_phdr; \
182 off = 0; \ 183 offset = 0; \
183 check_flags = PF_X; \ 184 check_flags = PF_X; \
184 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 185 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
185 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 186 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
186 found = found_relro; \ 187 found = found_relro; \
187 off = 4; \ 188 offset = 4; \
188 check_flags = PF_X; \ 189 check_flags = PF_X; \
189 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 190 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
191 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
190 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 192 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
191 found = found_load; \ 193 found = found_load; \
192 off = 8; \ 194 offset = 8; \
193 check_flags = PF_W|PF_X; \ 195 check_flags = PF_W|PF_X; \
194 } else \ 196 } else \
195 continue; \ 197 continue; \
196 flags = EGET(phdr[i].p_flags); \ 198 flags = EGET(phdr[i].p_flags); \
197 if (be_quiet && ((flags & check_flags) != check_flags)) \ 199 if (be_quiet && ((flags & check_flags) != check_flags)) \
198 continue; \ 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 } \
199 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \ 206 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
200 *found = 1; \ 207 *found = 1; \
201 ++shown; \ 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 } \
202 } \ 243 } \
203 } 244 }
204 SHOW_PHDR(32) 245 SHOW_PHDR(32)
205 SHOW_PHDR(64) 246 SHOW_PHDR(64)
206 }
207 247
208 if (be_quiet && !shown) 248 if (be_wewy_wewy_quiet || (be_quiet && !shown))
209 return NULL; 249 return NULL;
210 else 250 else
211 return ret; 251 return ret;
212} 252}
213static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 253static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
214{ 254{
215 static char ret[] = "TEXTREL"; 255 static const char *ret = "TEXTREL";
216 unsigned long i; 256 unsigned long i;
217 257
218 if (!show_textrel && !show_textrels) return NULL; 258 if (!show_textrel && !show_textrels) return NULL;
219 259
220 if (elf->phdr) { 260 if (elf->phdr) {
243 } 283 }
244 284
245 if (be_quiet || be_wewy_wewy_quiet) 285 if (be_quiet || be_wewy_wewy_quiet)
246 return NULL; 286 return NULL;
247 else 287 else
248 return (char *)" - "; 288 return " - ";
249} 289}
250static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 290static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
251{ 291{
252 unsigned long p, s, r, rmax; 292 unsigned long s, r, rmax;
253 void *symtab_void, *strtab_void; 293 void *symtab_void, *strtab_void, *text_void;
254 294
255 if (!show_textrels) return NULL; 295 if (!show_textrels) return NULL;
256 296
257 /* don't search for TEXTREL's if the ELF doesn't have any */ 297 /* don't search for TEXTREL's if the ELF doesn't have any */
258 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel); 298 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
259 if (!*found_textrel) return NULL; 299 if (!*found_textrel) return NULL;
260 300
261 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 301 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
302 text_void = elf_findsecbyname(elf, ".text");
262 303
263 if (symtab_void && strtab_void && elf->phdr && elf->shdr) { 304 if (symtab_void && strtab_void && text_void && elf->shdr) {
264#define SHOW_TEXTRELS(B) \ 305#define SHOW_TEXTRELS(B) \
265 if (elf->elf_class == ELFCLASS ## B) { \ 306 if (elf->elf_class == ELFCLASS ## B) { \
266 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 307 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
267 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
268 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 308 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
269 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 309 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
270 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_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); \
271 Elf ## B ## _Rel *rel; \ 314 Elf ## B ## _Rel *rel; \
272 Elf ## B ## _Rela *rela; \ 315 Elf ## B ## _Rela *rela; \
273 /* search the section headers for relocations */ \ 316 /* search the section headers for relocations */ \
274 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ 317 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
275 uint32_t sh_type = EGET(shdr[s].sh_type); \ 318 uint32_t sh_type = EGET(shdr[s].sh_type); \
281 rel = NULL; \ 324 rel = NULL; \
282 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ 325 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
283 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ 326 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
284 } else \ 327 } else \
285 continue; \ 328 continue; \
286 /* search the program headers for PT_LOAD headers */ \
287 for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
288 Elf ## B ## _Addr vaddr; \
289 uint ## B ## _t memsz; \
290 if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
291 if (EGET(phdr[p].p_flags) & PF_W) continue; \
292 vaddr = EGET(phdr[p].p_vaddr); \
293 memsz = EGET(phdr[p].p_memsz); \
294 /* now see if any of the relocs are in the PT_LOAD */ \ 329 /* now see if any of the relocs are in the .text */ \
295 for (r = 0; r < rmax; ++r) { \ 330 for (r = 0; r < rmax; ++r) { \
296 unsigned long sym_max; \ 331 unsigned long sym_max; \
297 Elf ## B ## _Addr offset_tmp; \ 332 Elf ## B ## _Addr offset_tmp; \
298 Elf ## B ## _Sym *func; \ 333 Elf ## B ## _Sym *func; \
299 Elf ## B ## _Sym *sym; \ 334 Elf ## B ## _Sym *sym; \
300 Elf ## B ## _Addr r_offset; \ 335 Elf ## B ## _Addr r_offset; \
301 uint ## B ## _t r_info; \ 336 uint ## B ## _t r_info; \
302 if (sh_type == SHT_REL) { \ 337 if (sh_type == SHT_REL) { \
303 r_offset = EGET(rel[r].r_offset); \ 338 r_offset = EGET(rel[r].r_offset); \
304 r_info = EGET(rel[r].r_info); \ 339 r_info = EGET(rel[r].r_info); \
305 } else { \ 340 } else { \
306 r_offset = EGET(rela[r].r_offset); \ 341 r_offset = EGET(rela[r].r_offset); \
307 r_info = EGET(rela[r].r_info); \ 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); \
308 } \ 376 } \
309 /* make sure this relocation is inside of the .text */ \
310 if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \
311 *found_textrels = 1; \
312 /* locate this relocation symbol name */ \
313 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
314 sym_max = ELF ## B ## _R_SYM(r_info); \
315 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
316 sym += sym_max; \
317 else \
318 sym = NULL; \
319 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
320 /* show the raw details about this reloc */ \
321 printf("\tTEXTREL %s: ", elf->base_filename); \
322 if (sym && sym->st_name) \
323 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
324 else \
325 printf("(NULL: fake?)"); \
326 printf(" [0x%lX]", (unsigned long)r_offset); \
327 /* now try to find the closest symbol that this rel is probably in */ \
328 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
329 func = NULL; \
330 offset_tmp = 0; \
331 while (sym_max--) { \
332 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
333 func = sym; \
334 offset_tmp = EGET(sym->st_value); \
335 } \
336 ++sym; \ 377 ++sym; \
337 } \
338 printf(" in "); \
339 if (func && func->st_name) \
340 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
341 else \
342 printf("(NULL: fake?)"); \
343 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
344 } \ 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); \
345 } \ 385 } \
346 } } 386 } }
347 SHOW_TEXTRELS(32) 387 SHOW_TEXTRELS(32)
348 SHOW_TEXTRELS(64) 388 SHOW_TEXTRELS(64)
349 } 389 }
390 if (!*found_textrels)
391 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
350 392
351 return NULL; 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{
399 struct stat st;
400 switch (*item) {
401 case '/': break;
402 case '.':
403 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
404 break;
405 case ':':
406 case '\0':
407 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
408 break;
409 case '$':
410 if (fstat(elf->fd, &st) != -1)
411 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
412 warnf("Security problem with %s='%s' in %s with mode set of %o",
413 dt_type, item, elf->filename, st.st_mode & 07777);
414 break;
415 default:
416 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
417 break;
418 }
352} 419}
353static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 420static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
354{ 421{
355 unsigned long i, s; 422 unsigned long i, s;
356 char *rpath, *runpath, **r; 423 char *rpath, *runpath, **r;
390 /* Verify the memory is somewhat sane */ \ 457 /* Verify the memory is somewhat sane */ \
391 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 458 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
392 if (offset < (Elf ## B ## _Off)elf->len) { \ 459 if (offset < (Elf ## B ## _Off)elf->len) { \
393 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 460 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
394 *r = (char*)(elf->data + offset); \ 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); \
395 /* If quiet, don't output paths in ld.so.conf */ \ 465 /* If quiet, don't output paths in ld.so.conf */ \
396 if (be_quiet) { \ 466 if (be_quiet) { \
397 size_t len; \ 467 size_t len; \
398 char *start, *end; \ 468 char *start, *end; \
399 /* note that we only 'chop' off leading known paths. */ \ 469 /* note that we only 'chop' off leading known paths. */ \
400 /* since *r is read-only memory, we can only move the ptr forward. */ \ 470 /* since *r is read-only memory, we can only move the ptr forward. */ \
401 start = *r; \ 471 start = *r; \
402 /* scan each path in : delimited list */ \ 472 /* scan each path in : delimited list */ \
403 while (start) { \ 473 while (start) { \
474 rpath_security_checks(elf, start, get_elfdtype(word)); \
404 end = strchr(start, ':'); \ 475 end = strchr(start, ':'); \
405 len = (end ? abs(end - start) : strlen(start)); \ 476 len = (end ? abs(end - start) : strlen(start)); \
477 if (use_ldcache) \
406 for (s = 0; ldpaths[s]; ++s) { \ 478 for (s = 0; ldpaths[s]; ++s) \
407 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 479 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
408 *r = (end ? end + 1 : NULL); \ 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)++; \
409 break; \ 485 break; \
410 } \ 486 } \
411 } \
412 if (!*r || !ldpaths[s] || !end) \ 487 if (!*r || !end) \
413 start = NULL; \ 488 break; \
414 else \ 489 else \
415 start = start + len + 1; \ 490 start = start + len + 1; \
416 } \ 491 } \
417 } \ 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) \
418 if (*r) *found_rpath = 1; \ 533 *found_rpath = 1; \
534 } \
419 } \ 535 } \
420 ++dyn; \ 536 ++dyn; \
421 } \ 537 } \
422 } } 538 } }
423 SHOW_RPATH(32) 539 SHOW_RPATH(32)
440 } else if (rpath || runpath) 556 } else if (rpath || runpath)
441 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 557 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
442 else if (!be_quiet) 558 else if (!be_quiet)
443 xstrcat(ret, " - ", ret_len); 559 xstrcat(ret, " - ", ret_len);
444} 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;
620 }
621
622 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
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
445static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 649static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
446{ 650{
447 unsigned long i; 651 unsigned long i;
448 char *needed; 652 char *needed;
449 void *strtbl_void; 653 void *strtbl_void;
654 char *p;
450 655
451 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 656 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
452 657
453 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 658 strtbl_void = elf_findsecbyname(elf, ".dynstr");
454 659
474 } \ 679 } \
475 needed = (char*)(elf->data + offset); \ 680 needed = (char*)(elf->data + offset); \
476 if (op == 0) { \ 681 if (op == 0) { \
477 if (!be_wewy_wewy_quiet) { \ 682 if (!be_wewy_wewy_quiet) { \
478 if (*found_needed) xchrcat(ret, ',', ret_len); \ 683 if (*found_needed) xchrcat(ret, ',', ret_len); \
684 if (use_ldcache) \
685 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
686 needed = p; \
479 xstrcat(ret, needed, ret_len); \ 687 xstrcat(ret, needed, ret_len); \
480 } \ 688 } \
481 *found_needed = 1; \ 689 *found_needed = 1; \
482 } else { \ 690 } else { \
483 if (!strcmp(find_lib, needed)) { \ 691 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
484 *found_lib = 1; \ 692 *found_lib = 1; \
485 return (be_wewy_wewy_quiet ? NULL : find_lib); \ 693 return (be_wewy_wewy_quiet ? NULL : needed); \
486 } \ 694 } \
487 } \ 695 } \
488 } \ 696 } \
489 ++dyn; \ 697 ++dyn; \
490 } \ 698 } \
491 } } 699 } }
492 SHOW_NEEDED(32) 700 SHOW_NEEDED(32)
493 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);
494 } 704 }
495 705
496 return NULL; 706 return NULL;
497} 707}
498static char *scanelf_file_interp(elfobj *elf, char *found_interp) 708static char *scanelf_file_interp(elfobj *elf, char *found_interp)
556 } else { 766 } else {
557 *found_bind = 1; 767 *found_bind = 1;
558 return (char *) "LAZY"; 768 return (char *) "LAZY";
559 } 769 }
560} 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}
561static char *scanelf_file_sym(elfobj *elf, char *found_sym) 817static char *scanelf_file_sym(elfobj *elf, char *found_sym)
562{ 818{
563 unsigned long i; 819 unsigned long i;
820 char *ret;
564 void *symtab_void, *strtab_void; 821 void *symtab_void, *strtab_void;
565 822
566 if (!find_sym) return NULL; 823 if (!find_sym) return NULL;
824 ret = find_sym;
567 825
568 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 826 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
569 827
570 if (symtab_void && strtab_void) { 828 if (symtab_void && strtab_void) {
571#define FIND_SYM(B) \ 829#define FIND_SYM(B) \
572 if (elf->elf_class == ELFCLASS ## B) { \ 830 if (elf->elf_class == ELFCLASS ## B) { \
573 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 831 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
574 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 832 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
575 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)); \
576 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 834 unsigned long cnt = EGET(symtab->sh_entsize); \
577 char *symname; \ 835 char *symname; \
836 if (cnt) \
837 cnt = EGET(symtab->sh_size) / cnt; \
578 for (i = 0; i < cnt; ++i) { \ 838 for (i = 0; i < cnt; ++i) { \
579 if (sym->st_name) { \ 839 if (sym->st_name) { \
580 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 } \
581 if (*find_sym == '*') { \ 845 if (*find_sym == '*') { \
582 printf("%s(%s) %5lX %15s %s\n", \ 846 printf("%s(%s) %5lX %15s %s\n", \
583 ((*found_sym == 0) ? "\n\t" : "\t"), \ 847 ((*found_sym == 0) ? "\n\t" : "\t"), \
584 elf->base_filename, \ 848 elf->base_filename, \
585 (long)sym->st_size, \ 849 (unsigned long)sym->st_size, \
586 (char *)get_elfstttype(sym->st_info), \ 850 get_elfstttype(sym->st_info), \
587 symname); \ 851 symname); \
588 *found_sym = 1; \ 852 *found_sym = 1; \
589 } 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') || \
590 (strcmp(symname, versioned_symname) == 0)) \ 861 (strcmp(symname, versioned_symname) == 0)) { \
862 ret = this_sym; \
591 (*found_sym)++; \ 863 (*found_sym)++; \
864 goto break_out; \
865 } \
866 this_sym = next_sym + 1; \
867 } while (*next_sym != '\0'); \
868 } \
592 } \ 869 } \
593 ++sym; \ 870 ++sym; \
594 } } 871 } }
595 FIND_SYM(32) 872 FIND_SYM(32)
596 FIND_SYM(64) 873 FIND_SYM(64)
597 } 874 }
598 875
876break_out:
599 if (be_wewy_wewy_quiet) return NULL; 877 if (be_wewy_wewy_quiet) return NULL;
600 878
601 if (*find_sym != '*' && *found_sym) 879 if (*find_sym != '*' && *found_sym)
602 return find_sym; 880 return ret;
603 if (be_quiet) 881 if (be_quiet)
604 return NULL; 882 return NULL;
605 else 883 else
606 return (char *)" - "; 884 return (char *)" - ";
607} 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
608/* scan an elf file and show all the fun stuff */ 915/* scan an elf file and show all the fun stuff */
609#define prints(str) write(fileno(stdout), str, strlen(str)) 916#define prints(str) write(fileno(stdout), str, strlen(str))
610static void scanelf_file(const char *filename) 917static int scanelf_elfobj(elfobj *elf)
611{ 918{
612 unsigned long i; 919 unsigned long i;
613 char found_pax, found_phdr, found_relro, found_load, found_textrel, 920 char found_pax, found_phdr, found_relro, found_load, found_textrel,
614 found_rpath, found_needed, found_interp, found_bind, 921 found_rpath, found_needed, found_interp, found_bind, found_soname,
615 found_sym, found_lib, found_file, found_textrels; 922 found_sym, found_lib, found_file, found_textrels, found_section;
616 elfobj *elf;
617 struct stat st;
618 static char *out_buffer = NULL; 923 static char *out_buffer = NULL;
619 static size_t out_len; 924 static size_t out_len;
620 925
621 /* make sure 'filename' exists */
622 if (lstat(filename, &st) == -1) {
623 if (be_verbose > 2) printf("%s: does not exist\n", filename);
624 return;
625 }
626 /* always handle regular files and handle symlinked files if no -y */
627 if (S_ISLNK(st.st_mode)) {
628 if (!scan_symlink) return;
629 stat(filename, &st);
630 }
631 if (!S_ISREG(st.st_mode)) {
632 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
633 return;
634 }
635
636 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 926 found_pax = found_phdr = found_relro = found_load = found_textrel = \
637 found_rpath = found_needed = found_interp = found_bind = \ 927 found_rpath = found_needed = found_interp = found_bind = found_soname = \
638 found_sym = found_lib = found_file = found_textrels = 0; 928 found_sym = found_lib = found_file = found_textrels = found_section = 0;
639 929
640 /* verify this is real ELF */
641 if ((elf = readelf(filename)) == NULL) {
642 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
643 return;
644 }
645
646 if (be_verbose > 1) 930 if (be_verbose > 2)
647 printf("%s: scanning file {%s,%s}\n", filename, 931 printf("%s: scanning file {%s,%s}\n", elf->filename,
648 get_elfeitype(EI_CLASS, elf->elf_class), 932 get_elfeitype(EI_CLASS, elf->elf_class),
649 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 933 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
650 else if (be_verbose) 934 else if (be_verbose > 1)
651 printf("%s: scanning file\n", filename); 935 printf("%s: scanning file\n", elf->filename);
652 936
653 /* init output buffer */ 937 /* init output buffer */
654 if (!out_buffer) { 938 if (!out_buffer) {
655 out_len = sizeof(char) * 80; 939 out_len = sizeof(char) * 80;
656 out_buffer = (char*)xmalloc(out_len); 940 out_buffer = (char*)xmalloc(out_len);
674 case 't': prints("TEXTREL "); break; 958 case 't': prints("TEXTREL "); break;
675 case 'r': prints("RPATH "); break; 959 case 'r': prints("RPATH "); break;
676 case 'n': prints("NEEDED "); break; 960 case 'n': prints("NEEDED "); break;
677 case 'i': prints("INTERP "); break; 961 case 'i': prints("INTERP "); break;
678 case 'b': prints("BIND "); break; 962 case 'b': prints("BIND "); break;
963 case 'S': prints("SONAME "); break;
679 case 's': prints("SYM "); break; 964 case 's': prints("SYM "); break;
680 case 'N': prints("LIB "); break; 965 case 'N': prints("LIB "); break;
681 case 'T': prints("TEXTRELS "); break; 966 case 'T': prints("TEXTRELS "); break;
967 case 'k': prints("SECTION "); break;
682 default: warnf("'%c' has no title ?", out_format[i]); 968 default: warnf("'%c' has no title ?", out_format[i]);
683 } 969 }
684 } 970 }
685 if (!found_file) prints("FILE "); 971 if (!found_file) prints("FILE ");
686 prints("\n"); 972 prints("\n");
690 976
691 /* dump all the good stuff */ 977 /* dump all the good stuff */
692 for (i = 0; out_format[i]; ++i) { 978 for (i = 0; out_format[i]; ++i) {
693 const char *out; 979 const char *out;
694 const char *tmp; 980 const char *tmp;
695
696 /* make sure we trim leading spaces in quiet mode */
697 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
698 *out_buffer = '\0';
699 981
700 if (!IS_MODIFIER(out_format[i])) { 982 if (!IS_MODIFIER(out_format[i])) {
701 xchrcat(&out_buffer, out_format[i], &out_len); 983 xchrcat(&out_buffer, out_format[i], &out_len);
702 continue; 984 continue;
703 } 985 }
709 case '#': 991 case '#':
710 xchrcat(&out_buffer, out_format[i], &out_len); break; 992 xchrcat(&out_buffer, out_format[i], &out_len); break;
711 case 'F': 993 case 'F':
712 found_file = 1; 994 found_file = 1;
713 if (be_wewy_wewy_quiet) break; 995 if (be_wewy_wewy_quiet) break;
714 xstrcat(&out_buffer, filename, &out_len); 996 xstrcat(&out_buffer, elf->filename, &out_len);
715 break; 997 break;
716 case 'p': 998 case 'p':
717 found_file = 1; 999 found_file = 1;
718 if (be_wewy_wewy_quiet) break; 1000 if (be_wewy_wewy_quiet) break;
719 tmp = filename; 1001 tmp = elf->filename;
720 if (search_path) { 1002 if (search_path) {
721 ssize_t len_search = strlen(search_path); 1003 ssize_t len_search = strlen(search_path);
722 ssize_t len_file = strlen(filename); 1004 ssize_t len_file = strlen(elf->filename);
723 if (!strncmp(filename, search_path, len_search) && \ 1005 if (!strncmp(elf->filename, search_path, len_search) && \
724 len_file > len_search) 1006 len_file > len_search)
725 tmp += len_search; 1007 tmp += len_search;
726 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1008 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
727 } 1009 }
728 xstrcat(&out_buffer, tmp, &out_len); 1010 xstrcat(&out_buffer, tmp, &out_len);
729 break; 1011 break;
730 case 'f': 1012 case 'f':
731 found_file = 1; 1013 found_file = 1;
732 if (be_wewy_wewy_quiet) break; 1014 if (be_wewy_wewy_quiet) break;
733 tmp = strrchr(filename, '/'); 1015 tmp = strrchr(elf->filename, '/');
734 tmp = (tmp == NULL ? filename : tmp+1); 1016 tmp = (tmp == NULL ? elf->filename : tmp+1);
735 xstrcat(&out_buffer, tmp, &out_len); 1017 xstrcat(&out_buffer, tmp, &out_len);
736 break; 1018 break;
737 case 'o': out = get_elfetype(elf); break; 1019 case 'o': out = get_elfetype(elf); break;
738 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1020 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
739 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1021 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
742 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1024 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
743 case 'n': 1025 case 'n':
744 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1026 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
745 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1027 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
746 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1028 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1029 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
747 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1030 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1031 case 'k': out = scanelf_file_sections(elf, &found_section); break;
748 default: warnf("'%c' has no scan code?", out_format[i]); 1032 default: warnf("'%c' has no scan code?", out_format[i]);
749 } 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
750 if (out) xstrcat(&out_buffer, out, &out_len); 1039 xstrcat(&out_buffer, out, &out_len);
1040 }
751 } 1041 }
752 1042
753#define FOUND_SOMETHING() \ 1043#define FOUND_SOMETHING() \
754 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1044 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
755 found_rpath || found_needed || found_interp || found_bind || \ 1045 found_rpath || found_needed || found_interp || found_bind || \
756 found_sym || found_lib || found_textrels) 1046 found_soname || found_sym || found_lib || found_textrels || found_section )
757 1047
758 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1048 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
759 xchrcat(&out_buffer, ' ', &out_len); 1049 xchrcat(&out_buffer, ' ', &out_len);
760 xstrcat(&out_buffer, filename, &out_len); 1050 xstrcat(&out_buffer, elf->filename, &out_len);
761 } 1051 }
762 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1052 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
763 puts(out_buffer); 1053 puts(out_buffer);
764 fflush(stdout); 1054 fflush(stdout);
765 } 1055 }
766 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:
767 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);
768} 1159}
769 1160
770/* 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 */
771static void scanelf_dir(const char *path) 1162static void scanelf_dir(const char *path)
772{ 1163{
773 register DIR *dir; 1164 register DIR *dir;
774 register struct dirent *dentry; 1165 register struct dirent *dentry;
775 struct stat st_top, st; 1166 struct stat st_top, st;
776 char buf[_POSIX_PATH_MAX]; 1167 char buf[__PAX_UTILS_PATH_MAX];
777 size_t pathlen = 0, len = 0; 1168 size_t pathlen = 0, len = 0;
778 1169
779 /* make sure path exists */ 1170 /* make sure path exists */
780 if (lstat(path, &st_top) == -1) { 1171 if (lstat(path, &st_top) == -1) {
781 if (be_verbose > 2) printf("%s: does not exist\n", path); 1172 if (be_verbose > 2) printf("%s: does not exist\n", path);
791 /* now scan the dir looking for fun stuff */ 1182 /* now scan the dir looking for fun stuff */
792 if ((dir = opendir(path)) == NULL) { 1183 if ((dir = opendir(path)) == NULL) {
793 warnf("could not opendir %s: %s", path, strerror(errno)); 1184 warnf("could not opendir %s: %s", path, strerror(errno));
794 return; 1185 return;
795 } 1186 }
796 if (be_verbose) printf("%s: scanning dir\n", path); 1187 if (be_verbose > 1) printf("%s: scanning dir\n", path);
797 1188
798 pathlen = strlen(path); 1189 pathlen = strlen(path);
799 while ((dentry = readdir(dir))) { 1190 while ((dentry = readdir(dir))) {
800 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1191 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
801 continue; 1192 continue;
820 1211
821static int scanelf_from_file(char *filename) 1212static int scanelf_from_file(char *filename)
822{ 1213{
823 FILE *fp = NULL; 1214 FILE *fp = NULL;
824 char *p; 1215 char *p;
825 char path[_POSIX_PATH_MAX]; 1216 char path[__PAX_UTILS_PATH_MAX];
826 1217
827 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1218 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
828 fp = stdin; 1219 fp = stdin;
829 else if ((fp = fopen(filename, "r")) == NULL) 1220 else if ((fp = fopen(filename, "r")) == NULL)
830 return 1; 1221 return 1;
831 1222
832 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1223 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
833 if ((p = strchr(path, '\n')) != NULL) 1224 if ((p = strchr(path, '\n')) != NULL)
834 *p = 0; 1225 *p = 0;
835 search_path = path; 1226 search_path = path;
836 scanelf_dir(path); 1227 scanelf_dir(path);
837 } 1228 }
838 if (fp != stdin) 1229 if (fp != stdin)
839 fclose(fp); 1230 fclose(fp);
840 return 0; 1231 return 0;
841} 1232}
842 1233
843static void load_ld_so_conf() 1234static int load_ld_so_conf(int i, const char *fname)
844{ 1235{
845 FILE *fp = NULL; 1236 FILE *fp = NULL;
846 char *p; 1237 char *p;
847 char path[_POSIX_PATH_MAX]; 1238 char path[__PAX_UTILS_PATH_MAX];
848 int i = 0;
849 1239
850 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1240 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
851 return; 1241 return i;
852 1242
1243 if ((fp = fopen(fname, "r")) == NULL)
1244 return i;
1245
853 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1246 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
854 if (*path != '/')
855 continue;
856
857 if ((p = strrchr(path, '\r')) != NULL) 1247 if ((p = strrchr(path, '\r')) != NULL)
858 *p = 0; 1248 *p = 0;
859 if ((p = strchr(path, '\n')) != NULL) 1249 if ((p = strchr(path, '\n')) != NULL)
860 *p = 0; 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;
861 1284
862 ldpaths[i++] = xstrdup(path); 1285 ldpaths[i++] = xstrdup(path);
863 1286
864 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1287 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
865 break; 1288 break;
866 } 1289 }
867 ldpaths[i] = NULL; 1290 ldpaths[i] = NULL;
868 1291
869 fclose(fp); 1292 fclose(fp);
1293 return i;
870} 1294}
871 1295
872/* scan /etc/ld.so.conf for paths */ 1296/* scan /etc/ld.so.conf for paths */
873static void scanelf_ldpath() 1297static void scanelf_ldpath()
874{ 1298{
909 } 1333 }
910 1334
911 free(path); 1335 free(path);
912} 1336}
913 1337
914
915
916/* usage / invocation handling functions */ 1338/* usage / invocation handling functions */
917#define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV" 1339#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
918#define a_argument required_argument 1340#define a_argument required_argument
919static struct option const long_opts[] = { 1341static struct option const long_opts[] = {
920 {"path", no_argument, NULL, 'p'}, 1342 {"path", no_argument, NULL, 'p'},
921 {"ldpath", no_argument, NULL, 'l'}, 1343 {"ldpath", no_argument, NULL, 'l'},
922 {"recursive", no_argument, NULL, 'R'}, 1344 {"recursive", no_argument, NULL, 'R'},
923 {"mount", no_argument, NULL, 'm'}, 1345 {"mount", no_argument, NULL, 'm'},
924 {"symlink", no_argument, NULL, 'y'}, 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'},
925 {"pax", no_argument, NULL, 'x'}, 1351 {"pax", no_argument, NULL, 'x'},
926 {"header", no_argument, NULL, 'e'}, 1352 {"header", no_argument, NULL, 'e'},
927 {"textrel", no_argument, NULL, 't'}, 1353 {"textrel", no_argument, NULL, 't'},
928 {"rpath", no_argument, NULL, 'r'}, 1354 {"rpath", no_argument, NULL, 'r'},
929 {"needed", no_argument, NULL, 'n'}, 1355 {"needed", no_argument, NULL, 'n'},
930 {"interp", no_argument, NULL, 'i'}, 1356 {"interp", no_argument, NULL, 'i'},
931 {"bind", no_argument, NULL, 'b'}, 1357 {"bind", no_argument, NULL, 'b'},
1358 {"soname", no_argument, NULL, 'S'},
932 {"symbol", a_argument, NULL, 's'}, 1359 {"symbol", a_argument, NULL, 's'},
1360 {"section", a_argument, NULL, 'k'},
933 {"lib", a_argument, NULL, 'N'}, 1361 {"lib", a_argument, NULL, 'N'},
1362 {"gmatch", no_argument, NULL, 'g'},
934 {"textrels", no_argument, NULL, 'T'}, 1363 {"textrels", no_argument, NULL, 'T'},
1364 {"etype", a_argument, NULL, 'E'},
1365 {"bits", a_argument, NULL, 'M'},
935 {"all", no_argument, NULL, 'a'}, 1366 {"all", no_argument, NULL, 'a'},
936 {"quiet", no_argument, NULL, 'q'}, 1367 {"quiet", no_argument, NULL, 'q'},
937 {"verbose", no_argument, NULL, 'v'}, 1368 {"verbose", no_argument, NULL, 'v'},
938 {"format", a_argument, NULL, 'F'}, 1369 {"format", a_argument, NULL, 'F'},
939 {"from", a_argument, NULL, 'f'}, 1370 {"from", a_argument, NULL, 'f'},
947static const char *opts_help[] = { 1378static const char *opts_help[] = {
948 "Scan all directories in PATH environment", 1379 "Scan all directories in PATH environment",
949 "Scan all directories in /etc/ld.so.conf", 1380 "Scan all directories in /etc/ld.so.conf",
950 "Scan directories recursively", 1381 "Scan directories recursively",
951 "Don't recursively cross mount points", 1382 "Don't recursively cross mount points",
952 "Don't scan symlinks\n", 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",
953 "Print PaX markings", 1388 "Print PaX markings",
954 "Print GNU_STACK/PT_LOAD markings", 1389 "Print GNU_STACK/PT_LOAD markings",
955 "Print TEXTREL information", 1390 "Print TEXTREL information",
956 "Print RPATH information", 1391 "Print RPATH information",
957 "Print NEEDED information", 1392 "Print NEEDED information",
958 "Print INTERP information", 1393 "Print INTERP information",
959 "Print BIND information", 1394 "Print BIND information",
1395 "Print SONAME information",
960 "Find a specified symbol", 1396 "Find a specified symbol",
1397 "Find a specified section",
961 "Find a specified library", 1398 "Find a specified library",
1399 "Use strncmp to match libraries. (use with -N)",
962 "Locate cause of TEXTREL", 1400 "Locate cause of TEXTREL",
1401 "Print only ELF files matching numeric constant type",
1402 "Print only ELF files matching numeric bits",
963 "Print all scanned info (-x -e -t -r -n -i -b)\n", 1403 "Print all scanned info (-x -e -t -r -b)\n",
964 "Only output 'bad' things", 1404 "Only output 'bad' things",
965 "Be verbose (can be specified more than once)", 1405 "Be verbose (can be specified more than once)",
966 "Use specified format for output", 1406 "Use specified format for output",
967 "Read input stream from a filename", 1407 "Read input stream from a filename",
968 "Write output stream to a filename", 1408 "Write output stream to a filename",
975/* display usage and exit */ 1415/* display usage and exit */
976static void usage(int status) 1416static void usage(int status)
977{ 1417{
978 unsigned long i; 1418 unsigned long i;
979 printf("* Scan ELF binaries for stuff\n\n" 1419 printf("* Scan ELF binaries for stuff\n\n"
980 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1420 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
981 printf("Options: -[%s]\n", PARSE_FLAGS); 1421 printf("Options: -[%s]\n", PARSE_FLAGS);
982 for (i = 0; long_opts[i].name; ++i) 1422 for (i = 0; long_opts[i].name; ++i)
983 if (long_opts[i].has_arg == no_argument) 1423 if (long_opts[i].has_arg == no_argument)
984 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1424 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
985 long_opts[i].name, opts_help[i]); 1425 long_opts[i].name, opts_help[i]);
986 else 1426 else
987 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1427 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
988 long_opts[i].name, opts_help[i]); 1428 long_opts[i].name, opts_help[i]);
989 1429
990 if (status != EXIT_SUCCESS) 1430 if (status != EXIT_SUCCESS)
991 exit(status); 1431 exit(status);
992 1432
993 puts("\nThe format modifiers for the -F option are:"); 1433 puts("\nThe format modifiers for the -F option are:");
994 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1434 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
995 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1435 puts(" t TEXTREL \tr RPATH \tn NEEDED");
996 puts(" i INTERP \tb BIND \ts symbol"); 1436 puts(" i INTERP \tb BIND \ts symbol");
997 puts(" N library \to Type \tT TEXTRELs"); 1437 puts(" N library \to Type \tT TEXTRELs");
1438 puts(" S SONAME \tk section");
998 puts(" p filename (with search path removed)"); 1439 puts(" p filename (with search path removed)");
999 puts(" f base filename"); 1440 puts(" f filename (short name/basename)");
1000 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1441 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1442
1443 puts("\nELF Etypes:");
1444 print_etypes(stdout);
1001 1445
1002 exit(status); 1446 exit(status);
1003} 1447}
1004 1448
1005/* parse command line arguments and preform needed actions */ 1449/* parse command line arguments and preform needed actions */
1018 VERSION, __FILE__, __DATE__, rcsid, argv0); 1462 VERSION, __FILE__, __DATE__, rcsid, argv0);
1019 exit(EXIT_SUCCESS); 1463 exit(EXIT_SUCCESS);
1020 break; 1464 break;
1021 case 'h': usage(EXIT_SUCCESS); break; 1465 case 'h': usage(EXIT_SUCCESS); break;
1022 case 'f': 1466 case 'f':
1023 if (from_file) err("Don't specify -f twice"); 1467 if (from_file) warn("You prob don't want to specify -f twice");
1024 from_file = xstrdup(optarg); 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);
1025 break; 1475 break;
1026 case 'o': { 1476 case 'o': {
1027 FILE *fp = NULL; 1477 FILE *fp = NULL;
1028 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1478 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1029 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1479 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1030 SET_STDOUT(fp); 1480 SET_STDOUT(fp);
1031 break; 1481 break;
1032 } 1482 }
1033 1483 case 'k':
1484 if (find_section) warn("You prob don't want to specify -k twice");
1485 find_section = optarg;
1486 break;
1034 case 's': { 1487 case 's': {
1035 size_t len;
1036 if (find_sym) err("Don't specify -s twice"); 1488 if (find_sym) warn("You prob don't want to specify -s twice");
1037 find_sym = xstrdup(optarg); 1489 find_sym = optarg;
1038 len = strlen(find_sym) + 1;
1039 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1490 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1040 sprintf(versioned_symname, "%s@", find_sym); 1491 sprintf(versioned_symname, "%s@", find_sym);
1041 break; 1492 break;
1042 } 1493 }
1043 case 'N': { 1494 case 'N': {
1044 if (find_lib) err("Don't specify -N twice"); 1495 if (find_lib) warn("You prob don't want to specify -N twice");
1045 find_lib = xstrdup(optarg); 1496 find_lib = optarg;
1046 break; 1497 break;
1047 } 1498 }
1048 1499
1049 case 'F': { 1500 case 'F': {
1050 if (out_format) err("Don't specify -F twice"); 1501 if (out_format) warn("You prob don't want to specify -F twice");
1051 out_format = xstrdup(optarg); 1502 out_format = optarg;
1052 break; 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; \
1053 } 1516 }
1054 1517
1518 for (x = 0 ; x < strlen(optarg); x++) {
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;
1055 case 'y': scan_symlink = 0; break; 1559 case 'y': scan_symlink = 0; break;
1560 case 'A': scan_archives = 1; break;
1056 case 'B': show_banner = 0; break; 1561 case 'B': show_banner = 0; break;
1057 case 'l': scan_ldpath = 1; break; 1562 case 'l': scan_ldpath = 1; break;
1058 case 'p': scan_envpath = 1; break; 1563 case 'p': scan_envpath = 1; break;
1059 case 'R': dir_recurse = 1; break; 1564 case 'R': dir_recurse = 1; break;
1060 case 'm': dir_crossmount = 0; break; 1565 case 'm': dir_crossmount = 0; break;
1566 case 'X': ++fix_elf; break;
1061 case 'x': show_pax = 1; break; 1567 case 'x': show_pax = 1; break;
1062 case 'e': show_phdr = 1; break; 1568 case 'e': show_phdr = 1; break;
1063 case 't': show_textrel = 1; break; 1569 case 't': show_textrel = 1; break;
1064 case 'r': show_rpath = 1; break; 1570 case 'r': show_rpath = 1; break;
1065 case 'n': show_needed = 1; break; 1571 case 'n': show_needed = 1; break;
1066 case 'i': show_interp = 1; break; 1572 case 'i': show_interp = 1; break;
1067 case 'b': show_bind = 1; break; 1573 case 'b': show_bind = 1; break;
1574 case 'S': show_soname = 1; break;
1068 case 'T': show_textrels = 1; break; 1575 case 'T': show_textrels = 1; break;
1069 case 'q': be_quiet = 1; break; 1576 case 'q': be_quiet = 1; break;
1070 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1577 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1071 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \ 1578 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1072 show_needed = show_interp = show_bind = 1; break;
1073 1579
1074 case ':': 1580 case ':':
1075 err("Option missing parameter\n"); 1581 err("Option '%c' is missing parameter", optopt);
1076 case '?': 1582 case '?':
1077 err("Unknown option\n"); 1583 err("Unknown option '%c' or argument missing", optopt);
1078 default: 1584 default:
1079 err("Unhandled option '%c'", i); 1585 err("Unhandled option '%c'; please report this", i);
1080 } 1586 }
1081 } 1587 }
1082 1588
1083 /* let the format option override all other options */ 1589 /* let the format option override all other options */
1084 if (out_format) { 1590 if (out_format) {
1085 show_pax = show_phdr = show_textrel = show_rpath = \ 1591 show_pax = show_phdr = show_textrel = show_rpath = \
1086 show_needed = show_interp = show_bind = show_textrels = 0; 1592 show_needed = show_interp = show_bind = show_soname = \
1593 show_textrels = 0;
1087 for (i = 0; out_format[i]; ++i) { 1594 for (i = 0; out_format[i]; ++i) {
1088 if (!IS_MODIFIER(out_format[i])) continue; 1595 if (!IS_MODIFIER(out_format[i])) continue;
1089 1596
1090 switch (out_format[++i]) { 1597 switch (out_format[++i]) {
1091 case '%': break; 1598 case '%': break;
1092 case '#': break; 1599 case '#': break;
1093 case 'F': break; 1600 case 'F': break;
1094 case 'p': break; 1601 case 'p': break;
1095 case 'f': break; 1602 case 'f': break;
1603 case 'k': break;
1096 case 's': break; 1604 case 's': break;
1097 case 'N': break; 1605 case 'N': break;
1098 case 'o': break; 1606 case 'o': break;
1099 case 'x': show_pax = 1; break; 1607 case 'x': show_pax = 1; break;
1100 case 'e': show_phdr = 1; break; 1608 case 'e': show_phdr = 1; break;
1101 case 't': show_textrel = 1; break; 1609 case 't': show_textrel = 1; break;
1102 case 'r': show_rpath = 1; break; 1610 case 'r': show_rpath = 1; break;
1103 case 'n': show_needed = 1; break; 1611 case 'n': show_needed = 1; break;
1104 case 'i': show_interp = 1; break; 1612 case 'i': show_interp = 1; break;
1105 case 'b': show_bind = 1; break; 1613 case 'b': show_bind = 1; break;
1614 case 'S': show_soname = 1; break;
1106 case 'T': show_textrels = 1; break; 1615 case 'T': show_textrels = 1; break;
1107 default: 1616 default:
1108 err("Invalid format specifier '%c' (byte %i)", 1617 err("Invalid format specifier '%c' (byte %i)",
1109 out_format[i], i+1); 1618 out_format[i], i+1);
1110 } 1619 }
1120 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1629 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1121 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1630 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1122 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1631 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1123 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1632 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1124 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1633 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1634 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1125 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1635 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1126 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1636 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1637 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1127 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1638 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1128 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1639 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1129 } 1640 }
1130 if (be_verbose > 2) printf("Format: %s\n", out_format); 1641 if (be_verbose > 2) printf("Format: %s\n", out_format);
1131 1642
1132 /* now lets actually do the scanning */ 1643 /* now lets actually do the scanning */
1133 if (scan_ldpath || (show_rpath && be_quiet)) 1644 if (scan_ldpath || use_ldcache)
1134 load_ld_so_conf(); 1645 load_ld_so_conf(0, "/etc/ld.so.conf");
1135 if (scan_ldpath) scanelf_ldpath(); 1646 if (scan_ldpath) scanelf_ldpath();
1136 if (scan_envpath) scanelf_envpath(); 1647 if (scan_envpath) scanelf_envpath();
1137 if (from_file) { 1648 if (from_file) {
1138 scanelf_from_file(from_file); 1649 scanelf_from_file(from_file);
1139 free(from_file);
1140 from_file = *argv; 1650 from_file = *argv;
1141 } 1651 }
1142 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1652 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1143 err("Nothing to scan !?"); 1653 err("Nothing to scan !?");
1144 while (optind < argc) { 1654 while (optind < argc) {
1145 search_path = argv[optind++]; 1655 search_path = argv[optind++];
1146 scanelf_dir(search_path); 1656 scanelf_dir(search_path);
1147 } 1657 }
1148 1658
1149 /* clean up */ 1659 /* clean up */
1150 if (find_sym) { 1660 if (versioned_symname) free(versioned_symname);
1151 free(find_sym);
1152 free(versioned_symname);
1153 }
1154 if (find_lib) free(find_lib);
1155 if (out_format) free(out_format);
1156 for (i = 0; ldpaths[i]; ++i) 1661 for (i = 0; ldpaths[i]; ++i)
1157 free(ldpaths[i]); 1662 free(ldpaths[i]);
1663
1664 if (ldcache != 0)
1665 munmap(ldcache, ldcache_size);
1158} 1666}
1159 1667
1160 1668
1161 1669
1162/* utility funcs */ 1670/* utility funcs */
1164{ 1672{
1165 char *ret = strdup(s); 1673 char *ret = strdup(s);
1166 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1674 if (!ret) err("Could not strdup(): %s", strerror(errno));
1167 return ret; 1675 return ret;
1168} 1676}
1169
1170static void *xmalloc(size_t size) 1677static void *xmalloc(size_t size)
1171{ 1678{
1172 void *ret = malloc(size); 1679 void *ret = malloc(size);
1173 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1680 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1174 return ret; 1681 return ret;
1175} 1682}
1176
1177static void xstrcat(char **dst, const char *src, size_t *curr_len) 1683static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1178{ 1684{
1179 size_t new_len; 1685 size_t new_len;
1180 1686
1181 new_len = strlen(*dst) + strlen(src); 1687 new_len = strlen(*dst) + strlen(src);
1182 if (*curr_len <= new_len) { 1688 if (*curr_len <= new_len) {
1183 *curr_len = new_len + (*curr_len / 2); 1689 *curr_len = new_len + (*curr_len / 2);
1184 *dst = realloc(*dst, *curr_len); 1690 *dst = realloc(*dst, *curr_len);
1185 if (!*dst) 1691 if (!*dst)
1186 err("could not realloc %li bytes", (unsigned long)*curr_len); 1692 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1187 } 1693 }
1188 1694
1695 if (n)
1696 strncat(*dst, src, n);
1697 else
1189 strcat(*dst, src); 1698 strcat(*dst, src);
1190} 1699}
1191
1192static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1700static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1193{ 1701{
1194 static char my_app[2]; 1702 static char my_app[2];
1195 my_app[0] = append; 1703 my_app[0] = append;
1196 my_app[1] = '\0'; 1704 my_app[1] = '\0';

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

  ViewVC Help
Powered by ViewVC 1.1.20