/[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.96 Revision 1.227
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2007 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.96 2005/12/28 22:26:47 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.227 2011/09/27 19:20:51 vapier Exp $
5 * 5 *
6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10#include <stdio.h> 10static const char *rcsid = "$Id: scanelf.c,v 1.227 2011/09/27 19:20:51 vapier Exp $";
11#include <stdlib.h> 11const char argv0[] = "scanelf";
12#include <sys/types.h> 12
13#include <libgen.h>
14#include <limits.h>
15#include <string.h>
16#include <errno.h>
17#include <unistd.h>
18#include <sys/stat.h>
19#include <sys/mman.h>
20#include <fcntl.h>
21#include <dirent.h>
22#include <getopt.h>
23#include <assert.h>
24#include "paxinc.h" 13#include "paxinc.h"
25 14
26static const char *rcsid = "$Id: scanelf.c,v 1.96 2005/12/28 22:26:47 solar Exp $";
27#define argv0 "scanelf"
28
29#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
30
31
32 16
33/* prototypes */ 17/* prototypes */
34static void scanelf_file(const char *filename); 18static int file_matches_list(const char *filename, char **matchlist);
19static int scanelf_elfobj(elfobj *elf);
20static int scanelf_elf(const char *filename, int fd, size_t len);
21static int scanelf_archive(const char *filename, int fd, size_t len);
22static int scanelf_file(const char *filename, const struct stat *st_cache);
35static void scanelf_dir(const char *path); 23static int scanelf_dir(const char *path);
36static void scanelf_ldpath(); 24static void scanelf_ldpath(void);
37static void scanelf_envpath(); 25static void scanelf_envpath(void);
38static void usage(int status); 26static void usage(int status);
27static char **get_split_env(const char *envvar);
28static void parseenv(void);
39static void parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
40static char *xstrdup(const char *s);
41static void *xmalloc(size_t size);
42static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
43#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
44static inline void xchrcat(char **dst, const char append, size_t *curr_len);
45 30
46/* variables to control behavior */ 31/* variables to control behavior */
47static char *ldpaths[256]; 32static char match_etypes[126] = "";
33static array_t _ldpaths = array_init_decl, *ldpaths = &_ldpaths;
48static char scan_ldpath = 0; 34static char scan_ldpath = 0;
49static char scan_envpath = 0; 35static char scan_envpath = 0;
50static char scan_symlink = 1; 36static char scan_symlink = 1;
37static char scan_archives = 0;
51static char dir_recurse = 0; 38static char dir_recurse = 0;
52static char dir_crossmount = 1; 39static char dir_crossmount = 1;
53static char show_pax = 0; 40static char show_pax = 0;
41static char show_perms = 0;
42static char show_size = 0;
54static char show_phdr = 0; 43static char show_phdr = 0;
55static char show_textrel = 0; 44static char show_textrel = 0;
56static char show_rpath = 0; 45static char show_rpath = 0;
57static char show_needed = 0; 46static char show_needed = 0;
58static char show_interp = 0; 47static char show_interp = 0;
59static char show_bind = 0; 48static char show_bind = 0;
60static char show_soname = 0; 49static char show_soname = 0;
61static char show_textrels = 0; 50static char show_textrels = 0;
62static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
53static char show_osabi = 0;
54static char show_eabi = 0;
63static char be_quiet = 0; 55static char be_quiet = 0;
64static char be_verbose = 0; 56static char be_verbose = 0;
65static char be_wewy_wewy_quiet = 0; 57static char be_wewy_wewy_quiet = 0;
66static char *find_sym = NULL, *versioned_symname = NULL; 58static char be_semi_verbose = 0;
59static char *find_sym = NULL;
67static char *find_lib = NULL; 60static char *find_lib = NULL;
61static array_t _find_lib_arr = array_init_decl, *find_lib_arr = &_find_lib_arr;
62static char *find_section = NULL;
63static array_t _find_section_arr = array_init_decl, *find_section_arr = &_find_section_arr;
68static char *out_format = NULL; 64static char *out_format = NULL;
69static char *search_path = NULL; 65static char *search_path = NULL;
66static char fix_elf = 0;
70static char gmatch = 0; 67static char g_match = 0;
71static char printcache = 0; 68static char use_ldcache = 0;
72 69
70static char **qa_textrels = NULL;
71static char **qa_execstack = NULL;
72static char **qa_wx_load = NULL;
73static char *root;
73 74
74caddr_t ldcache = 0; 75static int match_bits = 0;
76static unsigned int match_perms = 0;
77static void *ldcache = NULL;
75size_t ldcache_size = 0; 78static size_t ldcache_size = 0;
79static unsigned long setpax = 0UL;
80
81static int has_objdump = 0;
82
83/* find the path to a file by name */
84static char *which(const char *fname)
85{
86 static char fullpath[__PAX_UTILS_PATH_MAX];
87 char *path, *p;
88
89 path = getenv("PATH");
90 if (!path)
91 return NULL;
92
93 path = xstrdup(path);
94 while ((p = strrchr(path, ':')) != NULL) {
95 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
96 *p = 0;
97 if (access(fullpath, R_OK) != -1) {
98 free(path);
99 return fullpath;
100 }
101 }
102 free(path);
103 return NULL;
104}
105
106/* 1 on failure. 0 otherwise */
107static int rematch(const char *regex, const char *match, int cflags)
108{
109 regex_t preg;
110 int ret;
111
112 if ((match == NULL) || (regex == NULL))
113 return EXIT_FAILURE;
114
115 if ((ret = regcomp(&preg, regex, cflags))) {
116 char err[256];
117
118 if (regerror(ret, &preg, err, sizeof(err)))
119 fprintf(stderr, "regcomp failed: %s", err);
120 else
121 fprintf(stderr, "regcomp failed");
122
123 return EXIT_FAILURE;
124 }
125 ret = regexec(&preg, match, 0, NULL, 0);
126 regfree(&preg);
127
128 return ret;
129}
76 130
77/* sub-funcs for scanelf_file() */ 131/* sub-funcs for scanelf_file() */
78static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 132static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
79{ 133{
80 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 134 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
135
136 /* debug sections */
137 void *symtab = elf_findsecbyname(elf, ".symtab");
138 void *strtab = elf_findsecbyname(elf, ".strtab");
139 /* runtime sections */
140 void *dynsym = elf_findsecbyname(elf, ".dynsym");
141 void *dynstr = elf_findsecbyname(elf, ".dynstr");
142
81#define GET_SYMTABS(B) \ 143#define GET_SYMTABS(B) \
82 if (elf->elf_class == ELFCLASS ## B) { \ 144 if (elf->elf_class == ELFCLASS ## B) { \
83 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
84 /* debug sections */ \
85 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
86 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
87 /* runtime sections */ \
88 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
89 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
90 if (symtab && dynsym) { \ 145 if (symtab && dynsym) { \
146 Elf ## B ## _Shdr *esymtab = symtab; \
147 Elf ## B ## _Shdr *edynsym = dynsym; \
91 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \ 148 *sym = (EGET(esymtab->sh_size) > EGET(edynsym->sh_size)) ? symtab : dynsym; \
92 } else { \ 149 } else \
93 *sym = (void*)(symtab ? symtab : dynsym); \ 150 *sym = symtab ? symtab : dynsym; \
94 } \
95 if (strtab && dynstr) { \ 151 if (strtab && dynstr) { \
152 Elf ## B ## _Shdr *estrtab = strtab; \
153 Elf ## B ## _Shdr *edynstr = dynstr; \
96 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \ 154 *tab = (EGET(estrtab->sh_size) > EGET(edynstr->sh_size)) ? strtab : dynstr; \
97 } else { \ 155 } else \
98 *tab = (void*)(strtab ? strtab : dynstr); \ 156 *tab = strtab ? strtab : dynstr; \
99 } \
100 } 157 }
101 GET_SYMTABS(32) 158 GET_SYMTABS(32)
102 GET_SYMTABS(64) 159 GET_SYMTABS(64)
103} 160}
161
104static char *scanelf_file_pax(elfobj *elf, char *found_pax) 162static char *scanelf_file_pax(elfobj *elf, char *found_pax)
105{ 163{
106 static char ret[7]; 164 static char ret[7];
107 unsigned long i, shown; 165 unsigned long i, shown;
108 166
117 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
118 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
119 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 177 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
120 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 178 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
121 continue; \ 179 continue; \
122 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 180 if (fix_elf && setpax) { \
181 /* set the paxctl flags */ \
182 ESET(phdr[i].p_flags, setpax); \
183 } \
184 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
123 continue; \ 185 continue; \
124 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 186 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
125 *found_pax = 1; \ 187 *found_pax = 1; \
126 ++shown; \ 188 ++shown; \
127 break; \ 189 break; \
128 } \ 190 } \
129 } 191 }
130 SHOW_PAX(32) 192 SHOW_PAX(32)
131 SHOW_PAX(64) 193 SHOW_PAX(64)
194 }
195
196 if (fix_elf && setpax) {
197 /* set the chpax settings */
198 if (elf->elf_class == ELFCLASS32) {
199 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
200 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
201 } else {
202 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
203 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
204 }
132 } 205 }
133 206
134 /* fall back to EI_PAX if no PT_PAX was found */ 207 /* fall back to EI_PAX if no PT_PAX was found */
135 if (!*ret) { 208 if (!*ret) {
136 static char *paxflags; 209 static char *paxflags;
150 223
151static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 224static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
152{ 225{
153 static char ret[12]; 226 static char ret[12];
154 char *found; 227 char *found;
155 unsigned long i, shown;
156 unsigned char multi_stack, multi_relro, multi_load; 228 unsigned long i, shown, multi_stack, multi_relro, multi_load;
229 int max_pt_load;
157 230
158 if (!show_phdr) return NULL; 231 if (!show_phdr) return NULL;
159 232
160 memcpy(ret, "--- --- ---\0", 12); 233 memcpy(ret, "--- --- ---\0", 12);
161 234
162 shown = 0; 235 shown = 0;
163 multi_stack = multi_relro = multi_load = 0; 236 multi_stack = multi_relro = multi_load = 0;
237 max_pt_load = elf_max_pt_load(elf);
164 238
239#define NOTE_GNU_STACK ".note.GNU-stack"
165#define SHOW_PHDR(B) \ 240#define SHOW_PHDR(B) \
166 if (elf->elf_class == ELFCLASS ## B) { \ 241 if (elf->elf_class == ELFCLASS ## B) { \
167 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 242 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
168 Elf ## B ## _Off offset; \ 243 Elf ## B ## _Off offset; \
169 uint32_t flags, check_flags; \ 244 uint32_t flags, check_flags; \
170 if (elf->phdr != NULL) { \ 245 if (elf->phdr != NULL) { \
171 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 246 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
172 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 247 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
173 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 248 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
249 if (multi_stack++) \
174 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 250 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
251 if (file_matches_list(elf->filename, qa_execstack)) \
252 continue; \
175 found = found_phdr; \ 253 found = found_phdr; \
176 offset = 0; \ 254 offset = 0; \
177 check_flags = PF_X; \ 255 check_flags = PF_X; \
178 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 256 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
257 if (multi_relro++) \
179 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 258 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
180 found = found_relro; \ 259 found = found_relro; \
181 offset = 4; \ 260 offset = 4; \
182 check_flags = PF_X; \ 261 check_flags = PF_X; \
183 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 262 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
184 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 263 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
264 if (multi_load++ > max_pt_load) \
265 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
266 if (file_matches_list(elf->filename, qa_wx_load)) \
267 continue; \
185 found = found_load; \ 268 found = found_load; \
186 offset = 8; \ 269 offset = 8; \
187 check_flags = PF_W|PF_X; \ 270 check_flags = PF_W|PF_X; \
188 } else \ 271 } else \
189 continue; \ 272 continue; \
190 flags = EGET(phdr[i].p_flags); \ 273 flags = EGET(phdr[i].p_flags); \
191 if (be_quiet && ((flags & check_flags) != check_flags)) \ 274 if (be_quiet && ((flags & check_flags) != check_flags)) \
192 continue; \ 275 continue; \
276 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
277 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
278 ret[3] = ret[7] = '!'; \
279 flags = EGET(phdr[i].p_flags); \
280 } \
193 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 281 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
194 *found = 1; \ 282 *found = 1; \
195 ++shown; \ 283 ++shown; \
196 } \ 284 } \
197 } else if (elf->shdr != NULL) { \ 285 } else if (elf->shdr != NULL) { \
198 /* no program headers which means this is prob an object file */ \ 286 /* no program headers which means this is prob an object file */ \
199 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 287 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
200 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 288 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
289 char *str; \
290 if ((void*)strtbl > elf->data_end) \
291 goto skip_this_shdr##B; \
201 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 292 check_flags = SHF_WRITE|SHF_EXECINSTR; \
202 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 293 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
203 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 294 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
204 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 295 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
205 if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \ 296 str = elf->data + offset; \
297 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
298 if (!strcmp(str, NOTE_GNU_STACK)) { \
206 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \ 299 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
207 flags = EGET(shdr[i].sh_flags); \ 300 flags = EGET(shdr[i].sh_flags); \
208 if (be_quiet && ((flags & check_flags) != check_flags)) \ 301 if (be_quiet && ((flags & check_flags) != check_flags)) \
209 continue; \ 302 continue; \
210 ++*found_phdr; \ 303 ++*found_phdr; \
214 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \ 307 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
215 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \ 308 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
216 break; \ 309 break; \
217 } \ 310 } \
218 } \ 311 } \
312 skip_this_shdr##B: \
219 if (!multi_stack) { \ 313 if (!multi_stack) { \
314 if (file_matches_list(elf->filename, qa_execstack)) \
315 return NULL; \
220 *found_phdr = 1; \ 316 *found_phdr = 1; \
221 shown = 1; \ 317 shown = 1; \
222 memcpy(ret, "!WX", 3); \ 318 memcpy(ret, "!WX", 3); \
223 } \ 319 } \
224 } \ 320 } \
229 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 325 if (be_wewy_wewy_quiet || (be_quiet && !shown))
230 return NULL; 326 return NULL;
231 else 327 else
232 return ret; 328 return ret;
233} 329}
330
331/*
332 * See if this ELF contains a DT_TEXTREL tag in any of its
333 * PT_DYNAMIC sections.
334 */
234static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 335static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
235{ 336{
236 static const char *ret = "TEXTREL"; 337 static const char *ret = "TEXTREL";
237 unsigned long i; 338 unsigned long i;
238 339
239 if (!show_textrel && !show_textrels) return NULL; 340 if (!show_textrel && !show_textrels) return NULL;
341
342 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
240 343
241 if (elf->phdr) { 344 if (elf->phdr) {
242#define SHOW_TEXTREL(B) \ 345#define SHOW_TEXTREL(B) \
243 if (elf->elf_class == ELFCLASS ## B) { \ 346 if (elf->elf_class == ELFCLASS ## B) { \
244 Elf ## B ## _Dyn *dyn; \ 347 Elf ## B ## _Dyn *dyn; \
245 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 348 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
246 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 349 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
247 Elf ## B ## _Off offset; \ 350 Elf ## B ## _Off offset; \
248 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 351 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
249 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 352 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
250 offset = EGET(phdr[i].p_offset); \ 353 offset = EGET(phdr[i].p_offset); \
251 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 354 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
252 dyn = DYN ## B (elf->data + offset); \ 355 dyn = DYN ## B (elf->vdata + offset); \
253 while (EGET(dyn->d_tag) != DT_NULL) { \ 356 while (EGET(dyn->d_tag) != DT_NULL) { \
254 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 357 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
255 *found_textrel = 1; \ 358 *found_textrel = 1; \
256 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 359 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
257 return (be_wewy_wewy_quiet ? NULL : ret); \ 360 return (be_wewy_wewy_quiet ? NULL : ret); \
266 if (be_quiet || be_wewy_wewy_quiet) 369 if (be_quiet || be_wewy_wewy_quiet)
267 return NULL; 370 return NULL;
268 else 371 else
269 return " - "; 372 return " - ";
270} 373}
374
375/*
376 * Scan the .text section to see if there are any relocations in it.
377 * Should rewrite this to check PT_LOAD sections that are marked
378 * Executable rather than the section named '.text'.
379 */
271static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 380static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
272{ 381{
273 unsigned long s, r, rmax; 382 unsigned long s, r, rmax;
274 void *symtab_void, *strtab_void, *text_void; 383 void *symtab_void, *strtab_void, *text_void;
275 384
296 Elf ## B ## _Rela *rela; \ 405 Elf ## B ## _Rela *rela; \
297 /* search the section headers for relocations */ \ 406 /* search the section headers for relocations */ \
298 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ 407 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
299 uint32_t sh_type = EGET(shdr[s].sh_type); \ 408 uint32_t sh_type = EGET(shdr[s].sh_type); \
300 if (sh_type == SHT_REL) { \ 409 if (sh_type == SHT_REL) { \
301 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \ 410 rel = REL ## B (elf->vdata + EGET(shdr[s].sh_offset)); \
302 rela = NULL; \ 411 rela = NULL; \
303 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \ 412 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
304 } else if (sh_type == SHT_RELA) { \ 413 } else if (sh_type == SHT_RELA) { \
305 rel = NULL; \ 414 rel = NULL; \
306 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ 415 rela = RELA ## B (elf->vdata + EGET(shdr[s].sh_offset)); \
307 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ 416 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
308 } else \ 417 } else \
309 continue; \ 418 continue; \
310 /* now see if any of the relocs are in the .text */ \ 419 /* now see if any of the relocs are in the .text */ \
311 for (r = 0; r < rmax; ++r) { \ 420 for (r = 0; r < rmax; ++r) { \
326 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \ 435 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
327 if (be_verbose <= 2) continue; \ 436 if (be_verbose <= 2) continue; \
328 } else \ 437 } else \
329 *found_textrels = 1; \ 438 *found_textrels = 1; \
330 /* locate this relocation symbol name */ \ 439 /* locate this relocation symbol name */ \
331 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 440 sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
441 if ((void*)sym > elf->data_end) { \
442 warn("%s: corrupt ELF symbol", elf->filename); \
443 continue; \
444 } \
332 sym_max = ELF ## B ## _R_SYM(r_info); \ 445 sym_max = ELF ## B ## _R_SYM(r_info); \
333 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 446 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
334 sym += sym_max; \ 447 sym += sym_max; \
335 else \ 448 else \
336 sym = NULL; \ 449 sym = NULL; \
337 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 450 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
338 /* show the raw details about this reloc */ \ 451 /* show the raw details about this reloc */ \
339 printf(" %s: ", elf->base_filename); \ 452 printf(" %s: ", elf->base_filename); \
340 if (sym && sym->st_name) \ 453 if (sym && sym->st_name) \
341 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 454 printf("%s", elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
342 else \ 455 else \
343 printf("(memory/fake?)"); \ 456 printf("(memory/data?)"); \
344 printf(" [0x%lX]", (unsigned long)r_offset); \ 457 printf(" [0x%lX]", (unsigned long)r_offset); \
345 /* now try to find the closest symbol that this rel is probably in */ \ 458 /* now try to find the closest symbol that this rel is probably in */ \
346 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 459 sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
347 func = NULL; \ 460 func = NULL; \
348 offset_tmp = 0; \ 461 offset_tmp = 0; \
349 while (sym_max--) { \ 462 while (sym_max--) { \
350 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \ 463 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
351 func = sym; \ 464 func = sym; \
352 offset_tmp = EGET(sym->st_value); \ 465 offset_tmp = EGET(sym->st_value); \
353 } \ 466 } \
354 ++sym; \ 467 ++sym; \
355 } \ 468 } \
356 printf(" in "); \ 469 printf(" in "); \
357 if (func && func->st_name) \ 470 if (func && func->st_name) { \
358 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ 471 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
472 if (r_offset > EGET(func->st_size)) \
473 printf("(optimized out: previous %s)", func_name); \
359 else \ 474 else \
360 printf("(NULL: fake?)"); \ 475 printf("%s", func_name); \
476 } else \
477 printf("(optimized out)"); \
361 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 478 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
479 if (be_verbose && has_objdump) { \
480 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
481 char *sysbuf; \
482 size_t syslen; \
483 int sysret; \
484 const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
485 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
486 sysbuf = xmalloc(syslen); \
487 if (end_addr < r_offset) \
488 /* not uncommon when things are optimized out */ \
489 end_addr = r_offset + 0x100; \
490 snprintf(sysbuf, syslen, sysfmt, \
491 (unsigned long)offset_tmp, \
492 (unsigned long)end_addr, \
493 elf->filename, \
494 (unsigned long)r_offset); \
495 fflush(stdout); \
496 sysret = system(sysbuf); \
497 fflush(stdout); \
498 free(sysbuf); \
499 } \
362 } \ 500 } \
363 } } 501 } }
364 SHOW_TEXTRELS(32) 502 SHOW_TEXTRELS(32)
365 SHOW_TEXTRELS(64) 503 SHOW_TEXTRELS(64)
366 } 504 }
368 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename); 506 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
369 507
370 return NULL; 508 return NULL;
371} 509}
372 510
373static void rpath_security_checks(elfobj *, char *); 511static void rpath_security_checks(elfobj *, char *, const char *);
374static void rpath_security_checks(elfobj *elf, char *item) { 512static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
513{
375 struct stat st; 514 struct stat st;
376 switch (*item) { 515 switch (*item) {
377 case '/': break; 516 case '/': break;
378 case '.': 517 case '.':
379 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename); 518 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
380 break; 519 break;
520 case ':':
381 case '\0': 521 case '\0':
382 warnf("Security problem NULL RPATH in %s", elf->filename); 522 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
383 break; 523 break;
384 case '$': 524 case '$':
385 if (fstat(elf->fd, &st) != -1) 525 if (fstat(elf->fd, &st) != -1)
386 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 526 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
387 warnf("Security problem with RPATH='%s' in %s with mode set of %o", 527 warnf("Security problem with %s='%s' in %s with mode set of %o",
388 item, elf->filename, st.st_mode & 07777); 528 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
389 break; 529 break;
390 default: 530 default:
391 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename); 531 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
392 break; 532 break;
393 } 533 }
394} 534}
395static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 535static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
396{ 536{
397 unsigned long i, s; 537 unsigned long i;
398 char *rpath, *runpath, **r; 538 char *rpath, *runpath, **r;
399 void *strtbl_void; 539 void *strtbl_void;
400 540
401 if (!show_rpath) return; 541 if (!show_rpath) return;
402 542
413 Elf ## B ## _Off offset; \ 553 Elf ## B ## _Off offset; \
414 Elf ## B ## _Xword word; \ 554 Elf ## B ## _Xword word; \
415 /* Scan all the program headers */ \ 555 /* Scan all the program headers */ \
416 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 556 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
417 /* Just scan dynamic headers */ \ 557 /* Just scan dynamic headers */ \
418 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 558 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
419 offset = EGET(phdr[i].p_offset); \ 559 offset = EGET(phdr[i].p_offset); \
420 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 560 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
421 /* Just scan dynamic RPATH/RUNPATH headers */ \ 561 /* Just scan dynamic RPATH/RUNPATH headers */ \
422 dyn = DYN ## B (elf->data + offset); \ 562 dyn = DYN ## B (elf->vdata + offset); \
423 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 563 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
424 if (word == DT_RPATH) { \ 564 if (word == DT_RPATH) { \
425 r = &rpath; \ 565 r = &rpath; \
426 } else if (word == DT_RUNPATH) { \ 566 } else if (word == DT_RUNPATH) { \
427 r = &runpath; \ 567 r = &runpath; \
431 } \ 571 } \
432 /* Verify the memory is somewhat sane */ \ 572 /* Verify the memory is somewhat sane */ \
433 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 573 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
434 if (offset < (Elf ## B ## _Off)elf->len) { \ 574 if (offset < (Elf ## B ## _Off)elf->len) { \
435 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 575 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
436 *r = (char*)(elf->data + offset); \ 576 *r = elf->data + offset; \
577 /* cache the length in case we need to nuke this section later on */ \
578 if (fix_elf) \
579 offset = strlen(*r); \
437 /* If quiet, don't output paths in ld.so.conf */ \ 580 /* If quiet, don't output paths in ld.so.conf */ \
438 if (be_quiet) { \ 581 if (be_quiet) { \
439 size_t len; \ 582 size_t len; \
440 char *start, *end; \ 583 char *start, *end; \
441 /* note that we only 'chop' off leading known paths. */ \ 584 /* note that we only 'chop' off leading known paths. */ \
442 /* since *r is read-only memory, we can only move the ptr forward. */ \ 585 /* since *r is read-only memory, we can only move the ptr forward. */ \
443 start = *r; \ 586 start = *r; \
444 /* scan each path in : delimited list */ \ 587 /* scan each path in : delimited list */ \
445 while (start) { \ 588 while (start) { \
446 rpath_security_checks(elf, start); \ 589 rpath_security_checks(elf, start, get_elfdtype(word)); \
447 end = strchr(start, ':'); \ 590 end = strchr(start, ':'); \
448 len = (end ? abs(end - start) : strlen(start)); \ 591 len = (end ? abs(end - start) : strlen(start)); \
449 for (s = 0; ldpaths[s]; ++s) { \ 592 if (use_ldcache) { \
593 size_t n; \
594 const char *ldpath; \
595 array_for_each(ldpaths, n, ldpath) \
450 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 596 if (!strncmp(ldpath, start, len) && !ldpath[len]) { \
451 *r = (end ? end + 1 : NULL); \ 597 *r = end; \
598 /* corner case ... if RPATH reads "/usr/lib:", we want \
599 * to show ':' rather than '' */ \
600 if (end && end[1] != '\0') \
601 (*r)++; \
452 break; \ 602 break; \
453 } \ 603 } \
454 } \ 604 } \
455 if (!*r || !ldpaths[s] || !end) \ 605 if (!*r || !end) \
456 start = NULL; \ 606 break; \
457 else \ 607 else \
458 start = start + len + 1; \ 608 start = start + len + 1; \
459 } \ 609 } \
460 } \ 610 } \
611 if (*r) { \
612 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
613 /* just nuke it */ \
614 nuke_it##B: \
615 memset(*r, 0x00, offset); \
616 *r = NULL; \
617 ESET(dyn->d_tag, DT_DEBUG); \
618 ESET(dyn->d_un.d_ptr, 0); \
619 } else if (fix_elf) { \
620 /* try to clean "bad" paths */ \
621 size_t len, tmpdir_len; \
622 char *start, *end; \
623 const char *tmpdir; \
624 start = *r; \
625 tmpdir = (getenv("TMPDIR") ? : "."); \
626 tmpdir_len = strlen(tmpdir); \
627 while (1) { \
628 end = strchr(start, ':'); \
629 if (start == end) { \
630 eat_this_path##B: \
631 len = strlen(end); \
632 memmove(start, end+1, len); \
633 start[len-1] = '\0'; \
634 end = start - 1; \
635 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
636 if (!end) { \
637 if (start == *r) \
638 goto nuke_it##B; \
639 *--start = '\0'; \
640 } else \
641 goto eat_this_path##B; \
642 } \
643 if (!end) \
644 break; \
645 start = end + 1; \
646 } \
647 if (**r == '\0') \
648 goto nuke_it##B; \
649 } \
650 if (*r) \
461 if (*r) *found_rpath = 1; \ 651 *found_rpath = 1; \
652 } \
462 } \ 653 } \
463 ++dyn; \ 654 ++dyn; \
464 } \ 655 } \
465 } } 656 } }
466 SHOW_RPATH(32) 657 SHOW_RPATH(32)
488 679
489#define LDSO_CACHE_MAGIC "ld.so-" 680#define LDSO_CACHE_MAGIC "ld.so-"
490#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1) 681#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
491#define LDSO_CACHE_VER "1.7.0" 682#define LDSO_CACHE_VER "1.7.0"
492#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1) 683#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
684#define FLAG_ANY -1
685#define FLAG_TYPE_MASK 0x00ff
686#define FLAG_LIBC4 0x0000
687#define FLAG_ELF 0x0001
688#define FLAG_ELF_LIBC5 0x0002
689#define FLAG_ELF_LIBC6 0x0003
690#define FLAG_REQUIRED_MASK 0xff00
691#define FLAG_SPARC_LIB64 0x0100
692#define FLAG_IA64_LIB64 0x0200
693#define FLAG_X8664_LIB64 0x0300
694#define FLAG_S390_LIB64 0x0400
695#define FLAG_POWERPC_LIB64 0x0500
696#define FLAG_MIPS64_LIBN32 0x0600
697#define FLAG_MIPS64_LIBN64 0x0700
493 698
494static char *lookup_cache_lib(char *); 699static char *lookup_cache_lib(elfobj *, char *);
700
701#if defined(__GLIBC__) || defined(__UCLIBC__)
702
495static char *lookup_cache_lib(char *fname) 703static char *lookup_cache_lib(elfobj *elf, char *fname)
496{ 704{
497 int fd = 0; 705 int fd;
498 char *strs; 706 char *strs;
499 static char buf[_POSIX_PATH_MAX] = ""; 707 static char buf[__PAX_UTILS_PATH_MAX] = "";
500 const char *cachefile = "/etc/ld.so.cache"; 708 const char cachefile[] = "/etc/ld.so.cache";
501 struct stat st; 709 struct stat st;
502 710
503 typedef struct { 711 typedef struct {
504 char magic[LDSO_CACHE_MAGIC_LEN]; 712 char magic[LDSO_CACHE_MAGIC_LEN];
505 char version[LDSO_CACHE_VER_LEN]; 713 char version[LDSO_CACHE_VER_LEN];
506 int nlibs; 714 int nlibs;
507 } header_t; 715 } header_t;
716 header_t *header;
508 717
509 typedef struct { 718 typedef struct {
510 int flags; 719 int flags;
511 int sooffset; 720 int sooffset;
512 int liboffset; 721 int liboffset;
513 } libentry_t; 722 } libentry_t;
514
515 header_t *header;
516 libentry_t *libent; 723 libentry_t *libent;
517 724
518 if (fname == NULL) 725 if (fname == NULL)
519 return NULL; 726 return NULL;
520 727
521 if (ldcache == 0) { 728 if (ldcache == NULL) {
522 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) < 0) 729 if (stat(cachefile, &st))
523 return NULL; 730 return NULL;
524 /* save the cache size for latter unmapping */ 731
732 fd = open(cachefile, O_RDONLY);
733 if (fd == -1)
734 return NULL;
735
736 /* cache these values so we only map/unmap the cache file once */
525 ldcache_size = st.st_size; 737 ldcache_size = st.st_size;
738 header = ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
739 close(fd);
526 740
527 if ((ldcache = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) -1) 741 if (ldcache == MAP_FAILED) {
742 ldcache = NULL;
528 return NULL; 743 return NULL;
744 }
529 745
530 close(fd);
531
532 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 746 if (memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
747 memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
748 {
749 munmap(ldcache, ldcache_size);
750 ldcache = NULL;
533 return NULL; 751 return NULL;
534
535 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
536 return NULL;
537 } 752 }
753 } else
754 header = ldcache;
538 755
539 header = (header_t *) ldcache;
540 libent = (libentry_t *) (ldcache + sizeof(header_t)); 756 libent = ldcache + sizeof(header_t);
541 strs = (char *) &libent[header->nlibs]; 757 strs = (char *) &libent[header->nlibs];
542 758
543 for (fd = 0; fd < header->nlibs; fd++) { 759 for (fd = 0; fd < header->nlibs; ++fd) {
760 /* This should be more fine grained, but for now we assume that
761 * diff arches will not be cached together, and we ignore the
762 * the different multilib mips cases.
763 */
764 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
765 continue;
766 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
767 continue;
768
544 if (strcmp(fname, strs + libent[fd].sooffset) != 0) 769 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
545 continue; 770 continue;
771
772 /* Return first hit because that is how the ldso rolls */
546 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 773 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
774 break;
547 } 775 }
776
548 return buf; 777 return buf;
549} 778}
550 779
780#elif defined(__NetBSD__)
781static char *lookup_cache_lib(elfobj *elf, char *fname)
782{
783 static char buf[__PAX_UTILS_PATH_MAX] = "";
784 static struct stat st;
785 size_t n;
786 char *ldpath;
787
788 array_for_each(ldpath, n, ldpath) {
789 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", ldpath, fname) >= sizeof(buf))
790 continue; /* if the pathname is too long, or something went wrong, ignore */
791
792 if (stat(buf, &st) != 0)
793 continue; /* if the lib doesn't exist in *ldpath, look further */
794
795 /* NetBSD doesn't actually do sanity checks, it just loads the file
796 * and if that doesn't work, continues looking in other directories.
797 * This cannot easily be safely emulated, unfortunately. For now,
798 * just assume that if it exists, it's a valid library. */
799
800 return buf;
801 }
802
803 /* not found in any path */
804 return NULL;
805}
806#else
807#ifdef __ELF__
808#warning Cache support not implemented for your target
809#endif
810static char *lookup_cache_lib(elfobj *elf, char *fname)
811{
812 return NULL;
813}
814#endif
551 815
552static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 816static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
553{ 817{
554 unsigned long i; 818 unsigned long i;
555 char *needed; 819 char *needed;
556 void *strtbl_void; 820 void *strtbl_void;
557 char *p; 821 char *p;
558 822
823 /*
824 * -n -> op==0 -> print all
825 * -N -> op==1 -> print requested
826 */
559 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 827 if ((op == 0 && !show_needed) || (op == 1 && !find_lib))
828 return NULL;
560 829
561 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 830 strtbl_void = elf_findsecbyname(elf, ".dynstr");
562 831
563 if (elf->phdr && strtbl_void) { 832 if (elf->phdr && strtbl_void) {
564#define SHOW_NEEDED(B) \ 833#define SHOW_NEEDED(B) \
566 Elf ## B ## _Dyn *dyn; \ 835 Elf ## B ## _Dyn *dyn; \
567 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 836 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
568 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 837 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
569 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 838 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
570 Elf ## B ## _Off offset; \ 839 Elf ## B ## _Off offset; \
840 size_t matched = 0; \
841 /* Walk all the program headers to find the PT_DYNAMIC */ \
571 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 842 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
572 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 843 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) \
844 continue; \
573 offset = EGET(phdr[i].p_offset); \ 845 offset = EGET(phdr[i].p_offset); \
574 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 846 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) \
847 continue; \
848 /* Walk all the dynamic tags to find NEEDED entries */ \
575 dyn = DYN ## B (elf->data + offset); \ 849 dyn = DYN ## B (elf->vdata + offset); \
576 while (EGET(dyn->d_tag) != DT_NULL) { \ 850 while (EGET(dyn->d_tag) != DT_NULL) { \
577 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 851 if (EGET(dyn->d_tag) == DT_NEEDED) { \
578 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 852 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
579 if (offset >= (Elf ## B ## _Off)elf->len) { \ 853 if (offset >= (Elf ## B ## _Off)elf->len) { \
580 ++dyn; \ 854 ++dyn; \
581 continue; \ 855 continue; \
582 } \ 856 } \
583 needed = (char*)(elf->data + offset); \ 857 needed = elf->data + offset; \
584 if (op == 0) { \ 858 if (op == 0) { \
859 /* -n -> print all entries */ \
585 if (!be_wewy_wewy_quiet) { \ 860 if (!be_wewy_wewy_quiet) { \
586 if (*found_needed) xchrcat(ret, ',', ret_len); \ 861 if (*found_needed) xchrcat(ret, ',', ret_len); \
587 if (printcache) \ 862 if (use_ldcache) \
588 if ((p = lookup_cache_lib(needed)) != NULL) \ 863 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
589 needed = p; \ 864 needed = p; \
590 xstrcat(ret, needed, ret_len); \ 865 xstrcat(ret, needed, ret_len); \
591 } \ 866 } \
592 *found_needed = 1; \ 867 *found_needed = 1; \
593 } else { \ 868 } else { \
594 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 869 /* -N -> print matching entries */ \
870 size_t n; \
871 const char *find_lib_name; \
872 \
873 array_for_each(find_lib_arr, n, find_lib_name) \
874 if (!strcmp(find_lib_name, needed)) \
875 ++matched; \
876 \
877 if (matched == array_cnt(find_lib_arr)) { \
595 *found_lib = 1; \ 878 *found_lib = 1; \
596 return (be_wewy_wewy_quiet ? NULL : needed); \ 879 return (be_wewy_wewy_quiet ? NULL : find_lib); \
597 } \ 880 } \
598 } \ 881 } \
599 } \ 882 } \
600 ++dyn; \ 883 ++dyn; \
601 } \ 884 } \
630} 913}
631static char *scanelf_file_bind(elfobj *elf, char *found_bind) 914static char *scanelf_file_bind(elfobj *elf, char *found_bind)
632{ 915{
633 unsigned long i; 916 unsigned long i;
634 struct stat s; 917 struct stat s;
918 char dynamic = 0;
635 919
636 if (!show_bind) return NULL; 920 if (!show_bind) return NULL;
637 if (!elf->phdr) return NULL; 921 if (!elf->phdr) return NULL;
638 922
639#define SHOW_BIND(B) \ 923#define SHOW_BIND(B) \
641 Elf ## B ## _Dyn *dyn; \ 925 Elf ## B ## _Dyn *dyn; \
642 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 926 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
643 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 927 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
644 Elf ## B ## _Off offset; \ 928 Elf ## B ## _Off offset; \
645 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 929 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
646 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 930 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
931 dynamic = 1; \
647 offset = EGET(phdr[i].p_offset); \ 932 offset = EGET(phdr[i].p_offset); \
648 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 933 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
649 dyn = DYN ## B (elf->data + offset); \ 934 dyn = DYN ## B (elf->vdata + offset); \
650 while (EGET(dyn->d_tag) != DT_NULL) { \ 935 while (EGET(dyn->d_tag) != DT_NULL) { \
651 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 936 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
652 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \ 937 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
653 { \ 938 { \
654 if (be_quiet) return NULL; \ 939 if (be_quiet) return NULL; \
662 SHOW_BIND(32) 947 SHOW_BIND(32)
663 SHOW_BIND(64) 948 SHOW_BIND(64)
664 949
665 if (be_wewy_wewy_quiet) return NULL; 950 if (be_wewy_wewy_quiet) return NULL;
666 951
952 /* don't output anything if quiet mode and the ELF is static or not setuid */
667 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 953 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
668 return NULL; 954 return NULL;
669 } else { 955 } else {
670 *found_bind = 1; 956 *found_bind = 1;
671 return (char *) "LAZY"; 957 return (char *)(dynamic ? "LAZY" : "STATIC");
672 } 958 }
673} 959}
674static char *scanelf_file_soname(elfobj *elf, char *found_soname) 960static char *scanelf_file_soname(elfobj *elf, char *found_soname)
675{ 961{
676 unsigned long i; 962 unsigned long i;
688 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 974 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
689 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 975 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
690 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 976 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
691 Elf ## B ## _Off offset; \ 977 Elf ## B ## _Off offset; \
692 /* only look for soname in shared objects */ \ 978 /* only look for soname in shared objects */ \
693 if (ehdr->e_type != ET_DYN) \ 979 if (EGET(ehdr->e_type) != ET_DYN) \
694 return NULL; \ 980 return NULL; \
695 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 981 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
696 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 982 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
697 offset = EGET(phdr[i].p_offset); \ 983 offset = EGET(phdr[i].p_offset); \
698 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 984 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
699 dyn = DYN ## B (elf->data + offset); \ 985 dyn = DYN ## B (elf->vdata + offset); \
700 while (EGET(dyn->d_tag) != DT_NULL) { \ 986 while (EGET(dyn->d_tag) != DT_NULL) { \
701 if (EGET(dyn->d_tag) == DT_SONAME) { \ 987 if (EGET(dyn->d_tag) == DT_SONAME) { \
702 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 988 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
703 if (offset >= (Elf ## B ## _Off)elf->len) { \ 989 if (offset >= (Elf ## B ## _Off)elf->len) { \
704 ++dyn; \ 990 ++dyn; \
705 continue; \ 991 continue; \
706 } \ 992 } \
707 soname = (char*)(elf->data + offset); \ 993 soname = elf->data + offset; \
708 *found_soname = 1; \ 994 *found_soname = 1; \
709 return (be_wewy_wewy_quiet ? NULL : soname); \ 995 return (be_wewy_wewy_quiet ? NULL : soname); \
710 } \ 996 } \
711 ++dyn; \ 997 ++dyn; \
712 } \ 998 } \
715 SHOW_SONAME(64) 1001 SHOW_SONAME(64)
716 } 1002 }
717 1003
718 return NULL; 1004 return NULL;
719} 1005}
1006
1007/*
1008 * We support the symbol form:
1009 * [%[modifiers]%][[+-]<symbol name>][,[.....]]
1010 * If the symbol name is empty, then all symbols are matched.
1011 * If the symbol name is a glob ("*"), then all symbols are dumped (debug).
1012 * Do not rely on this output format at all.
1013 * Otherwise the symbol name is used to search (either regex or string compare).
1014 * If the first char of the symbol name is a plus ("+"), then only match
1015 * defined symbols. If it's a minus ("-"), only match undefined symbols.
1016 * Putting modifiers in between the percent signs allows for more in depth
1017 * filters. There are groups of modifiers. If you don't specify a member
1018 * of a group, then all types in that group are matched. The current
1019 * groups and their types are:
1020 * STT group: STT_NOTYPE:n STT_OBJECT:o STT_FUNC:f SST_FILE:F
1021 * STB group: STB_LOCAL:l STB_GLOBAL:g STB_WEAK:w
1022 * SHN group: SHN_UNDEF:u SHN_ABS:a SHN_COMMON:c {defined}:d
1023 * The "defined" value in the SHN group does not correspond to a SHN_xxx define.
1024 * You can search for multiple symbols at once by seperating with a comma (",").
1025 *
1026 * Some examples:
1027 * ELFs with a weak function "foo":
1028 * scanelf -s %wf%foo <ELFs>
1029 * ELFs that define the symbol "main":
1030 * scanelf -s +main <ELFs>
1031 * scanelf -s %d%main <ELFs>
1032 * ELFs that refer to the undefined symbol "brk":
1033 * scanelf -s -brk <ELFs>
1034 * scanelf -s %u%brk <ELFs>
1035 * All global defined objects in an ELF:
1036 * scanelf -s %ogd% <ELF>
1037 */
1038static void
1039scanelf_match_symname(elfobj *elf, char *found_sym, char **ret, size_t *ret_len, const char *symname,
1040 unsigned int stt, unsigned int stb, unsigned int shn, unsigned long size)
1041{
1042 char *this_sym, *next_sym, saved = saved;
1043
1044 /* allow the user to specify a comma delimited list of symbols to search for */
1045 next_sym = NULL;
1046 do {
1047 bool inc_notype, inc_object, inc_func, inc_file,
1048 inc_local, inc_global, inc_weak,
1049 inc_def, inc_undef, inc_abs, inc_common;
1050
1051 if (next_sym) {
1052 next_sym[-1] = saved;
1053 this_sym = next_sym;
1054 } else
1055 this_sym = find_sym;
1056 if ((next_sym = strchr(this_sym, ','))) {
1057 /* make parsing easier by killing the comma temporarily */
1058 saved = *next_sym;
1059 *next_sym = '\0';
1060 next_sym += 1;
1061 }
1062
1063 /* symbol selection! */
1064 inc_notype = inc_object = inc_func = inc_file = \
1065 inc_local = inc_global = inc_weak = \
1066 inc_def = inc_undef = inc_abs = inc_common = \
1067 (*this_sym != '%');
1068
1069 /* parse the contents of %...% */
1070 if (!inc_notype) {
1071 while (*(this_sym++)) {
1072 if (*this_sym == '%') {
1073 ++this_sym;
1074 break;
1075 }
1076 switch (*this_sym) {
1077 case 'n': inc_notype = true; break;
1078 case 'o': inc_object = true; break;
1079 case 'f': inc_func = true; break;
1080 case 'F': inc_file = true; break;
1081 case 'l': inc_local = true; break;
1082 case 'g': inc_global = true; break;
1083 case 'w': inc_weak = true; break;
1084 case 'd': inc_def = true; break;
1085 case 'u': inc_undef = true; break;
1086 case 'a': inc_abs = true; break;
1087 case 'c': inc_common = true; break;
1088 default: err("invalid symbol selector '%c'", *this_sym);
1089 }
1090 }
1091
1092 /* If no types are matched, not match all */
1093 if (!inc_notype && !inc_object && !inc_func && !inc_file)
1094 inc_notype = inc_object = inc_func = inc_file = true;
1095 if (!inc_local && !inc_global && !inc_weak)
1096 inc_local = inc_global = inc_weak = true;
1097 if (!inc_def && !inc_undef && !inc_abs && !inc_common)
1098 inc_def = inc_undef = inc_abs = inc_common = true;
1099
1100 /* backwards compat for defined/undefined short hand */
1101 } else if (*this_sym == '+') {
1102 inc_undef = false;
1103 ++this_sym;
1104 } else if (*this_sym == '-') {
1105 inc_def = inc_abs = inc_common = false;
1106 ++this_sym;
1107 }
1108
1109 /* filter symbols */
1110 if ((!inc_notype && stt == STT_NOTYPE) || \
1111 (!inc_object && stt == STT_OBJECT) || \
1112 (!inc_func && stt == STT_FUNC ) || \
1113 (!inc_file && stt == STT_FILE ) || \
1114 (!inc_local && stb == STB_LOCAL ) || \
1115 (!inc_global && stb == STB_GLOBAL) || \
1116 (!inc_weak && stb == STB_WEAK ) || \
1117 (!inc_def && shn && shn < SHN_LORESERVE) || \
1118 (!inc_undef && shn == SHN_UNDEF ) || \
1119 (!inc_abs && shn == SHN_ABS ) || \
1120 (!inc_common && shn == SHN_COMMON))
1121 continue;
1122
1123 if (*this_sym == '*') {
1124 /* a "*" symbol gets you debug output */
1125 printf("%s(%s) %5lX %15s %15s %15s %s\n",
1126 ((*found_sym == 0) ? "\n\t" : "\t"),
1127 elf->base_filename,
1128 size,
1129 get_elfstttype(stt),
1130 get_elfstbtype(stb),
1131 get_elfshntype(shn),
1132 symname);
1133 goto matched;
1134
1135 } else {
1136 if (g_match) {
1137 /* regex match the symbol */
1138 if (rematch(this_sym, symname, REG_EXTENDED) != 0)
1139 continue;
1140
1141 } else if (*this_sym) {
1142 /* give empty symbols a "pass", else do a normal compare */
1143 const size_t len = strlen(this_sym);
1144 if (!(strncmp(this_sym, symname, len) == 0 &&
1145 /* Accept unversioned symbol names */
1146 (symname[len] == '\0' || symname[len] == '@')))
1147 continue;
1148 }
1149
1150 if (be_semi_verbose) {
1151 char buf[1024];
1152 snprintf(buf, sizeof(buf), "%lX %s %s",
1153 size,
1154 get_elfstttype(stt),
1155 this_sym);
1156 *ret = xstrdup(buf);
1157 } else {
1158 if (*ret) xchrcat(ret, ',', ret_len);
1159 xstrcat(ret, symname, ret_len);
1160 }
1161
1162 goto matched;
1163 }
1164 } while (next_sym);
1165
1166 return;
1167
1168 matched:
1169 *found_sym = 1;
1170 if (next_sym)
1171 next_sym[-1] = saved;
1172}
1173
720static char *scanelf_file_sym(elfobj *elf, char *found_sym) 1174static const char *scanelf_file_sym(elfobj *elf, char *found_sym)
721{ 1175{
722 unsigned long i; 1176 unsigned long i;
723 char *ret; 1177 char *ret;
724 void *symtab_void, *strtab_void; 1178 void *symtab_void, *strtab_void;
725 1179
726 if (!find_sym) return NULL; 1180 if (!find_sym) return NULL;
727 ret = find_sym; 1181 ret = NULL;
728 1182
729 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 1183 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
730 1184
731 if (symtab_void && strtab_void) { 1185 if (symtab_void && strtab_void) {
732#define FIND_SYM(B) \ 1186#define FIND_SYM(B) \
733 if (elf->elf_class == ELFCLASS ## B) { \ 1187 if (elf->elf_class == ELFCLASS ## B) { \
734 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 1188 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
735 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 1189 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
736 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 1190 Elf ## B ## _Sym *sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
737 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 1191 unsigned long cnt = EGET(symtab->sh_entsize); \
738 char *symname; \ 1192 char *symname; \
1193 size_t ret_len = 0; \
1194 if (cnt) \
1195 cnt = EGET(symtab->sh_size) / cnt; \
739 for (i = 0; i < cnt; ++i) { \ 1196 for (i = 0; i < cnt; ++i) { \
1197 if ((void*)sym > elf->data_end) { \
1198 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1199 goto break_out; \
1200 } \
740 if (sym->st_name) { \ 1201 if (sym->st_name) { \
1202 /* make sure the symbol name is in acceptable memory range */ \
741 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1203 symname = elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name); \
742 if (*find_sym == '*') { \ 1204 if ((void*)symname > elf->data_end) { \
743 printf("%s(%s) %5lX %15s %s\n", \ 1205 warnf("%s: corrupt ELF symbols", elf->filename); \
744 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1206 ++sym; \
745 elf->base_filename, \ 1207 continue; \
746 (unsigned long)sym->st_size, \
747 get_elfstttype(sym->st_info), \
748 symname); \
749 *found_sym = 1; \
750 } else { \
751 char *this_sym, *next_sym; \
752 this_sym = find_sym; \
753 do { \
754 next_sym = strchr(this_sym, ','); \
755 if (next_sym == NULL) \
756 next_sym = this_sym + strlen(this_sym); \
757 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
758 (strcmp(symname, versioned_symname) == 0)) { \
759 ret = this_sym; \
760 (*found_sym)++; \
761 goto break_out; \
762 } \
763 this_sym = next_sym + 1; \
764 } while (*next_sym != '\0'); \
765 } \ 1208 } \
1209 scanelf_match_symname(elf, found_sym, \
1210 &ret, &ret_len, symname, \
1211 ELF##B##_ST_TYPE(EGET(sym->st_info)), \
1212 ELF##B##_ST_BIND(EGET(sym->st_info)), \
1213 EGET(sym->st_shndx), \
1214 /* st_size can be 64bit, but no one is really that big, so screw em */ \
1215 EGET(sym->st_size)); \
766 } \ 1216 } \
767 ++sym; \ 1217 ++sym; \
768 } } 1218 } }
769 FIND_SYM(32) 1219 FIND_SYM(32)
770 FIND_SYM(64) 1220 FIND_SYM(64)
776 if (*find_sym != '*' && *found_sym) 1226 if (*find_sym != '*' && *found_sym)
777 return ret; 1227 return ret;
778 if (be_quiet) 1228 if (be_quiet)
779 return NULL; 1229 return NULL;
780 else 1230 else
781 return (char *)" - "; 1231 return " - ";
782} 1232}
1233
1234static const char *scanelf_file_sections(elfobj *elf, char *found_section)
1235{
1236 if (!find_section)
1237 return NULL;
1238
1239#define FIND_SECTION(B) \
1240 if (elf->elf_class == ELFCLASS ## B) { \
1241 size_t matched, n; \
1242 int invert; \
1243 const char *section_name; \
1244 Elf ## B ## _Shdr *section; \
1245 \
1246 matched = 0; \
1247 array_for_each(find_section_arr, n, section_name) { \
1248 invert = (*section_name == '!' ? 1 : 0); \
1249 section = SHDR ## B (elf_findsecbyname(elf, section_name + invert)); \
1250 if ((section == NULL && invert) || (section != NULL && !invert)) \
1251 ++matched; \
1252 } \
1253 \
1254 if (matched == array_cnt(find_section_arr)) \
1255 *found_section = 1; \
1256 }
1257 FIND_SECTION(32)
1258 FIND_SECTION(64)
1259
1260 if (be_wewy_wewy_quiet)
1261 return NULL;
1262
1263 if (*found_section)
1264 return find_section;
1265
1266 if (be_quiet)
1267 return NULL;
1268 else
1269 return " - ";
1270}
1271
783/* scan an elf file and show all the fun stuff */ 1272/* scan an elf file and show all the fun stuff */
784#define prints(str) write(fileno(stdout), str, strlen(str)) 1273#define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
785static void scanelf_file(const char *filename) 1274static int scanelf_elfobj(elfobj *elf)
786{ 1275{
787 unsigned long i; 1276 unsigned long i;
788 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1277 char found_pax, found_phdr, found_relro, found_load, found_textrel,
789 found_rpath, found_needed, found_interp, found_bind, found_soname, 1278 found_rpath, found_needed, found_interp, found_bind, found_soname,
790 found_sym, found_lib, found_file, found_textrels; 1279 found_sym, found_lib, found_file, found_textrels, found_section;
791 elfobj *elf;
792 struct stat st;
793 static char *out_buffer = NULL; 1280 static char *out_buffer = NULL;
794 static size_t out_len; 1281 static size_t out_len;
795 1282
796 /* make sure 'filename' exists */
797 if (lstat(filename, &st) == -1) {
798 if (be_verbose > 2) printf("%s: does not exist\n", filename);
799 return;
800 }
801 /* always handle regular files and handle symlinked files if no -y */
802 if (S_ISLNK(st.st_mode)) {
803 if (!scan_symlink) return;
804 stat(filename, &st);
805 }
806 if (!S_ISREG(st.st_mode)) {
807 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
808 return;
809 }
810
811 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1283 found_pax = found_phdr = found_relro = found_load = found_textrel = \
812 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1284 found_rpath = found_needed = found_interp = found_bind = found_soname = \
813 found_sym = found_lib = found_file = found_textrels = 0; 1285 found_sym = found_lib = found_file = found_textrels = found_section = 0;
814 1286
815 /* verify this is real ELF */
816 if ((elf = readelf(filename)) == NULL) {
817 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
818 return;
819 }
820
821 if (be_verbose > 1) 1287 if (be_verbose > 2)
822 printf("%s: scanning file {%s,%s}\n", filename, 1288 printf("%s: scanning file {%s,%s}\n", elf->filename,
823 get_elfeitype(EI_CLASS, elf->elf_class), 1289 get_elfeitype(EI_CLASS, elf->elf_class),
824 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1290 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
825 else if (be_verbose) 1291 else if (be_verbose > 1)
826 printf("%s: scanning file\n", filename); 1292 printf("%s: scanning file\n", elf->filename);
827 1293
828 /* init output buffer */ 1294 /* init output buffer */
829 if (!out_buffer) { 1295 if (!out_buffer) {
830 out_len = sizeof(char) * 80; 1296 out_len = sizeof(char) * 80;
831 out_buffer = (char*)xmalloc(out_len); 1297 out_buffer = xmalloc(out_len);
832 } 1298 }
833 *out_buffer = '\0'; 1299 *out_buffer = '\0';
834 1300
835 /* show the header */ 1301 /* show the header */
836 if (!be_quiet && show_banner) { 1302 if (!be_quiet && show_banner) {
837 for (i = 0; out_format[i]; ++i) { 1303 for (i = 0; out_format[i]; ++i) {
838 if (!IS_MODIFIER(out_format[i])) continue; 1304 if (!IS_MODIFIER(out_format[i])) continue;
839 1305
840 switch (out_format[++i]) { 1306 switch (out_format[++i]) {
1307 case '+': break;
841 case '%': break; 1308 case '%': break;
842 case '#': break; 1309 case '#': break;
843 case 'F': 1310 case 'F':
844 case 'p': 1311 case 'p':
845 case 'f': prints("FILE "); found_file = 1; break; 1312 case 'f': prints("FILE "); found_file = 1; break;
846 case 'o': prints(" TYPE "); break; 1313 case 'o': prints(" TYPE "); break;
847 case 'x': prints(" PAX "); break; 1314 case 'x': prints(" PAX "); break;
848 case 'e': prints("STK/REL/PTL "); break; 1315 case 'e': prints("STK/REL/PTL "); break;
849 case 't': prints("TEXTREL "); break; 1316 case 't': prints("TEXTREL "); break;
850 case 'r': prints("RPATH "); break; 1317 case 'r': prints("RPATH "); break;
1318 case 'M': prints("CLASS "); break;
851 case 'n': prints("NEEDED "); break; 1319 case 'n': prints("NEEDED "); break;
852 case 'i': prints("INTERP "); break; 1320 case 'i': prints("INTERP "); break;
853 case 'b': prints("BIND "); break; 1321 case 'b': prints("BIND "); break;
1322 case 'Z': prints("SIZE "); break;
854 case 'S': prints("SONAME "); break; 1323 case 'S': prints("SONAME "); break;
855 case 's': prints("SYM "); break; 1324 case 's': prints("SYM "); break;
856 case 'N': prints("LIB "); break; 1325 case 'N': prints("LIB "); break;
857 case 'T': prints("TEXTRELS "); break; 1326 case 'T': prints("TEXTRELS "); break;
1327 case 'k': prints("SECTION "); break;
1328 case 'a': prints("ARCH "); break;
1329 case 'I': prints("OSABI "); break;
1330 case 'Y': prints("EABI "); break;
1331 case 'O': prints("PERM "); break;
1332 case 'D': prints("ENDIAN "); break;
858 default: warnf("'%c' has no title ?", out_format[i]); 1333 default: warnf("'%c' has no title ?", out_format[i]);
859 } 1334 }
860 } 1335 }
861 if (!found_file) prints("FILE "); 1336 if (!found_file) prints("FILE ");
862 prints("\n"); 1337 prints("\n");
866 1341
867 /* dump all the good stuff */ 1342 /* dump all the good stuff */
868 for (i = 0; out_format[i]; ++i) { 1343 for (i = 0; out_format[i]; ++i) {
869 const char *out; 1344 const char *out;
870 const char *tmp; 1345 const char *tmp;
871 1346 static char ubuf[sizeof(unsigned long)*2];
872 /* make sure we trim leading spaces in quiet mode */
873 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
874 *out_buffer = '\0';
875
876 if (!IS_MODIFIER(out_format[i])) { 1347 if (!IS_MODIFIER(out_format[i])) {
877 xchrcat(&out_buffer, out_format[i], &out_len); 1348 xchrcat(&out_buffer, out_format[i], &out_len);
878 continue; 1349 continue;
879 } 1350 }
880 1351
881 out = NULL; 1352 out = NULL;
882 be_wewy_wewy_quiet = (out_format[i] == '#'); 1353 be_wewy_wewy_quiet = (out_format[i] == '#');
1354 be_semi_verbose = (out_format[i] == '+');
883 switch (out_format[++i]) { 1355 switch (out_format[++i]) {
1356 case '+':
884 case '%': 1357 case '%':
885 case '#': 1358 case '#':
886 xchrcat(&out_buffer, out_format[i], &out_len); break; 1359 xchrcat(&out_buffer, out_format[i], &out_len); break;
887 case 'F': 1360 case 'F':
888 found_file = 1; 1361 found_file = 1;
889 if (be_wewy_wewy_quiet) break; 1362 if (be_wewy_wewy_quiet) break;
890 xstrcat(&out_buffer, filename, &out_len); 1363 xstrcat(&out_buffer, elf->filename, &out_len);
891 break; 1364 break;
892 case 'p': 1365 case 'p':
893 found_file = 1; 1366 found_file = 1;
894 if (be_wewy_wewy_quiet) break; 1367 if (be_wewy_wewy_quiet) break;
895 tmp = filename; 1368 tmp = elf->filename;
896 if (search_path) { 1369 if (search_path) {
897 ssize_t len_search = strlen(search_path); 1370 ssize_t len_search = strlen(search_path);
898 ssize_t len_file = strlen(filename); 1371 ssize_t len_file = strlen(elf->filename);
899 if (!strncmp(filename, search_path, len_search) && \ 1372 if (!strncmp(elf->filename, search_path, len_search) && \
900 len_file > len_search) 1373 len_file > len_search)
901 tmp += len_search; 1374 tmp += len_search;
902 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1375 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
903 } 1376 }
904 xstrcat(&out_buffer, tmp, &out_len); 1377 xstrcat(&out_buffer, tmp, &out_len);
905 break; 1378 break;
906 case 'f': 1379 case 'f':
907 found_file = 1; 1380 found_file = 1;
908 if (be_wewy_wewy_quiet) break; 1381 if (be_wewy_wewy_quiet) break;
909 tmp = strrchr(filename, '/'); 1382 tmp = strrchr(elf->filename, '/');
910 tmp = (tmp == NULL ? filename : tmp+1); 1383 tmp = (tmp == NULL ? elf->filename : tmp+1);
911 xstrcat(&out_buffer, tmp, &out_len); 1384 xstrcat(&out_buffer, tmp, &out_len);
912 break; 1385 break;
913 case 'o': out = get_elfetype(elf); break; 1386 case 'o': out = get_elfetype(elf); break;
914 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1387 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
915 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1388 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
916 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1389 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
917 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; 1390 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
918 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1391 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1392 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1393 case 'D': out = get_endian(elf); break;
1394 case 'O': out = strfileperms(elf->filename); break;
919 case 'n': 1395 case 'n':
920 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1396 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
921 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1397 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
922 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1398 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
923 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1399 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
924 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1400 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1401 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1402 case 'a': out = get_elfemtype(elf); break;
1403 case 'I': out = get_elfosabi(elf); break;
1404 case 'Y': out = get_elf_eabi(elf); break;
1405 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;;
925 default: warnf("'%c' has no scan code?", out_format[i]); 1406 default: warnf("'%c' has no scan code?", out_format[i]);
926 } 1407 }
927 if (out) { 1408 if (out)
928 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
929 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
930 xstrncat(&out_buffer, out, &out_len, (tmp-out));
931 else
932 xstrcat(&out_buffer, out, &out_len); 1409 xstrcat(&out_buffer, out, &out_len);
933 }
934 } 1410 }
935 1411
936#define FOUND_SOMETHING() \ 1412#define FOUND_SOMETHING() \
937 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1413 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
938 found_rpath || found_needed || found_interp || found_bind || \ 1414 found_rpath || found_needed || found_interp || found_bind || \
939 found_soname || found_sym || found_lib || found_textrels) 1415 found_soname || found_sym || found_lib || found_textrels || found_section )
940 1416
941 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1417 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
942 xchrcat(&out_buffer, ' ', &out_len); 1418 xchrcat(&out_buffer, ' ', &out_len);
943 xstrcat(&out_buffer, filename, &out_len); 1419 xstrcat(&out_buffer, elf->filename, &out_len);
944 } 1420 }
945 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1421 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
946 puts(out_buffer); 1422 puts(out_buffer);
947 fflush(stdout); 1423 fflush(stdout);
948 } 1424 }
949 1425
1426 return 0;
1427}
1428
1429/* scan a single elf */
1430static int scanelf_elf(const char *filename, int fd, size_t len)
1431{
1432 int ret = 1;
1433 elfobj *elf;
1434
1435 /* verify this is real ELF */
1436 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1437 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1438 return ret;
1439 }
1440 switch (match_bits) {
1441 case 32:
1442 if (elf->elf_class != ELFCLASS32)
1443 goto label_done;
1444 break;
1445 case 64:
1446 if (elf->elf_class != ELFCLASS64)
1447 goto label_done;
1448 break;
1449 default: break;
1450 }
1451 if (strlen(match_etypes)) {
1452 char sbuf[126];
1453 strncpy(sbuf, match_etypes, sizeof(sbuf));
1454 if (strchr(match_etypes, ',') != NULL) {
1455 char *p;
1456 while ((p = strrchr(sbuf, ',')) != NULL) {
1457 *p = 0;
1458 if (etype_lookup(p+1) == get_etype(elf))
1459 goto label_ret;
1460 }
1461 }
1462 if (etype_lookup(sbuf) != get_etype(elf))
1463 goto label_done;
1464 }
1465
1466label_ret:
1467 ret = scanelf_elfobj(elf);
1468
1469label_done:
950 unreadelf(elf); 1470 unreadelf(elf);
1471 return ret;
1472}
1473
1474/* scan an archive of elfs */
1475static int scanelf_archive(const char *filename, int fd, size_t len)
1476{
1477 archive_handle *ar;
1478 archive_member *m;
1479 char *ar_buffer;
1480 elfobj *elf;
1481
1482 ar = ar_open_fd(filename, fd);
1483 if (ar == NULL)
1484 return 1;
1485
1486 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1487 while ((m = ar_next(ar)) != NULL) {
1488 off_t cur_pos = lseek(fd, 0, SEEK_CUR);
1489 if (cur_pos == -1)
1490 errp("lseek() failed");
1491 elf = readelf_buffer(m->name, ar_buffer + cur_pos, m->size);
1492 if (elf) {
1493 scanelf_elfobj(elf);
1494 unreadelf(elf);
1495 }
1496 }
1497 munmap(ar_buffer, len);
1498
1499 return 0;
1500}
1501/* scan a file which may be an elf or an archive or some other magical beast */
1502static int scanelf_file(const char *filename, const struct stat *st_cache)
1503{
1504 const struct stat *st = st_cache;
1505 struct stat symlink_st;
1506 int fd;
1507
1508 /* always handle regular files and handle symlinked files if no -y */
1509 if (S_ISLNK(st->st_mode)) {
1510 if (!scan_symlink) return 1;
1511 stat(filename, &symlink_st);
1512 st = &symlink_st;
1513 }
1514
1515 if (!S_ISREG(st->st_mode)) {
1516 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1517 return 1;
1518 }
1519
1520 if (match_perms) {
1521 if ((st->st_mode | match_perms) != st->st_mode)
1522 return 1;
1523 }
1524 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1525 return 1;
1526
1527 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1528 /* if it isn't an ELF, maybe it's an .a archive */
1529 scanelf_archive(filename, fd, st->st_size);
1530
1531 close(fd);
1532 return 0;
1533}
1534
1535static const char *maybe_add_root(const char *fname, char *buf)
1536{
1537 if (root && strncmp(fname, root, strlen(root))) {
1538 strcpy(buf, root);
1539 strncat(buf, fname, __PAX_UTILS_PATH_MAX - strlen(root) - 1);
1540 fname = buf;
1541 }
1542 return fname;
951} 1543}
952 1544
953/* scan a directory for ET_EXEC files and print when we find one */ 1545/* scan a directory for ET_EXEC files and print when we find one */
954static void scanelf_dir(const char *path) 1546static int scanelf_dir(const char *path)
955{ 1547{
956 register DIR *dir; 1548 register DIR *dir;
957 register struct dirent *dentry; 1549 register struct dirent *dentry;
958 struct stat st_top, st; 1550 struct stat st_top, st;
959 char buf[_POSIX_PATH_MAX]; 1551 char buf[__PAX_UTILS_PATH_MAX];
1552 char _path[__PAX_UTILS_PATH_MAX];
960 size_t pathlen = 0, len = 0; 1553 size_t pathlen = 0, len = 0;
1554 int ret = 0;
1555
1556 path = maybe_add_root(path, _path);
961 1557
962 /* make sure path exists */ 1558 /* make sure path exists */
963 if (lstat(path, &st_top) == -1) { 1559 if (lstat(path, &st_top) == -1) {
964 if (be_verbose > 2) printf("%s: does not exist\n", path); 1560 if (be_verbose > 2) printf("%s: does not exist\n", path);
965 return; 1561 return 1;
966 } 1562 }
967 1563
968 /* ok, if it isn't a directory, assume we can open it */ 1564 /* ok, if it isn't a directory, assume we can open it */
969 if (!S_ISDIR(st_top.st_mode)) { 1565 if (!S_ISDIR(st_top.st_mode)) {
970 scanelf_file(path); 1566 return scanelf_file(path, &st_top);
971 return;
972 } 1567 }
973 1568
974 /* now scan the dir looking for fun stuff */ 1569 /* now scan the dir looking for fun stuff */
975 if ((dir = opendir(path)) == NULL) { 1570 if ((dir = opendir(path)) == NULL) {
976 warnf("could not opendir %s: %s", path, strerror(errno)); 1571 warnf("could not opendir %s: %s", path, strerror(errno));
977 return; 1572 return 1;
978 } 1573 }
979 if (be_verbose) printf("%s: scanning dir\n", path); 1574 if (be_verbose > 1) printf("%s: scanning dir\n", path);
980 1575
981 pathlen = strlen(path); 1576 pathlen = strlen(path);
982 while ((dentry = readdir(dir))) { 1577 while ((dentry = readdir(dir))) {
983 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1578 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
984 continue; 1579 continue;
986 if (len >= sizeof(buf)) { 1581 if (len >= sizeof(buf)) {
987 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1582 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
988 (unsigned long)len, (unsigned long)sizeof(buf)); 1583 (unsigned long)len, (unsigned long)sizeof(buf));
989 continue; 1584 continue;
990 } 1585 }
991 sprintf(buf, "%s/%s", path, dentry->d_name); 1586 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
992 if (lstat(buf, &st) != -1) { 1587 if (lstat(buf, &st) != -1) {
993 if (S_ISREG(st.st_mode)) 1588 if (S_ISREG(st.st_mode))
994 scanelf_file(buf); 1589 ret = scanelf_file(buf, &st);
995 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1590 else if (dir_recurse && S_ISDIR(st.st_mode)) {
996 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1591 if (dir_crossmount || (st_top.st_dev == st.st_dev))
997 scanelf_dir(buf); 1592 ret = scanelf_dir(buf);
998 } 1593 }
999 } 1594 }
1000 } 1595 }
1001 closedir(dir); 1596 closedir(dir);
1597 return ret;
1002} 1598}
1003 1599
1004static int scanelf_from_file(char *filename) 1600static int scanelf_from_file(const char *filename)
1005{ 1601{
1006 FILE *fp = NULL; 1602 FILE *fp = NULL;
1007 char *p; 1603 char *p;
1008 char path[_POSIX_PATH_MAX]; 1604 char path[__PAX_UTILS_PATH_MAX];
1605 int ret = 0;
1009 1606
1010 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1607 if (strcmp(filename, "-") == 0)
1011 fp = stdin; 1608 fp = stdin;
1012 else if ((fp = fopen(filename, "r")) == NULL) 1609 else if ((fp = fopen(filename, "r")) == NULL)
1013 return 1; 1610 return 1;
1014 1611
1015 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1612 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1016 if ((p = strchr(path, '\n')) != NULL) 1613 if ((p = strchr(path, '\n')) != NULL)
1017 *p = 0; 1614 *p = 0;
1018 search_path = path; 1615 search_path = path;
1019 scanelf_dir(path); 1616 ret = scanelf_dir(path);
1020 } 1617 }
1021 if (fp != stdin) 1618 if (fp != stdin)
1022 fclose(fp); 1619 fclose(fp);
1023 return 0; 1620 return ret;
1024} 1621}
1025 1622
1026static void load_ld_so_conf() 1623#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1624
1625static int load_ld_cache_config(int i, const char *fname)
1027{ 1626{
1028 FILE *fp = NULL; 1627 FILE *fp = NULL;
1029 char *p; 1628 char *p;
1030 char path[_POSIX_PATH_MAX]; 1629 char path[__PAX_UTILS_PATH_MAX];
1031 int i = 0; 1630 char _fname[__PAX_UTILS_PATH_MAX];
1032 1631
1632 fname = maybe_add_root(fname, _fname);
1633
1033 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1634 if ((fp = fopen(fname, "r")) == NULL)
1034 return; 1635 return i;
1035 1636
1036 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1637 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1037 if (*path != '/')
1038 continue;
1039
1040 if ((p = strrchr(path, '\r')) != NULL) 1638 if ((p = strrchr(path, '\r')) != NULL)
1041 *p = 0; 1639 *p = 0;
1042 if ((p = strchr(path, '\n')) != NULL) 1640 if ((p = strchr(path, '\n')) != NULL)
1043 *p = 0; 1641 *p = 0;
1044 1642
1045 ldpaths[i++] = xstrdup(path); 1643 /* recursive includes of the same file will make this segfault. */
1644 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1645 glob_t gl;
1646 size_t x;
1647 char gpath[__PAX_UTILS_PATH_MAX];
1046 1648
1047 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1649 memset(gpath, 0, sizeof(gpath));
1048 break; 1650 if (root)
1651 strcpy(gpath, root);
1652
1653 if (path[8] != '/')
1654 snprintf(gpath+strlen(gpath), sizeof(gpath)-strlen(gpath), "/etc/%s", &path[8]);
1655 else
1656 strncpy(gpath+strlen(gpath), &path[8], sizeof(gpath)-strlen(gpath));
1657
1658 if (glob(gpath, 0, NULL, &gl) == 0) {
1659 for (x = 0; x < gl.gl_pathc; ++x) {
1660 /* try to avoid direct loops */
1661 if (strcmp(gl.gl_pathv[x], fname) == 0)
1662 continue;
1663 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1664 }
1665 globfree(&gl);
1666 continue;
1667 }
1049 } 1668 }
1050 ldpaths[i] = NULL; 1669
1670 if (*path != '/')
1671 continue;
1672
1673 xarraypush(ldpaths, path, strlen(path));
1674 }
1051 1675
1052 fclose(fp); 1676 fclose(fp);
1677 return i;
1053} 1678}
1679
1680#elif defined(__FreeBSD__) || defined(__DragonFly__)
1681
1682static int load_ld_cache_config(int i, const char *fname)
1683{
1684 FILE *fp = NULL;
1685 char *b = NULL, *p;
1686 struct elfhints_hdr hdr;
1687 char _fname[__PAX_UTILS_PATH_MAX];
1688
1689 fname = maybe_add_root(fname, _fname);
1690
1691 if ((fp = fopen(fname, "r")) == NULL)
1692 return i;
1693
1694 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1695 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1696 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1697 {
1698 fclose(fp);
1699 return i;
1700 }
1701
1702 b = xmalloc(hdr.dirlistlen + 1);
1703 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1704 fclose(fp);
1705 free(b);
1706 return i;
1707 }
1708
1709 while ((p = strsep(&b, ":"))) {
1710 if (*p == '\0')
1711 continue;
1712 xarraypush(ldpaths, p, strlen(p));
1713 }
1714
1715 free(b);
1716 fclose(fp);
1717 return i;
1718}
1719
1720#else
1721#ifdef __ELF__
1722#warning Cache config support not implemented for your target
1723#endif
1724static int load_ld_cache_config(int i, const char *fname)
1725{
1726 return 0;
1727}
1728#endif
1054 1729
1055/* scan /etc/ld.so.conf for paths */ 1730/* scan /etc/ld.so.conf for paths */
1056static void scanelf_ldpath() 1731static void scanelf_ldpath(void)
1057{ 1732{
1058 char scan_l, scan_ul, scan_ull; 1733 char scan_l, scan_ul, scan_ull;
1734 size_t n;
1735 const char *ldpath;
1059 int i = 0; 1736 int i = 0;
1060 1737
1061 if (!ldpaths[0]) 1738 if (array_cnt(ldpaths) == 0)
1062 err("Unable to load any paths from ld.so.conf"); 1739 err("Unable to load any paths from ld.so.conf");
1063 1740
1064 scan_l = scan_ul = scan_ull = 0; 1741 scan_l = scan_ul = scan_ull = 0;
1065 1742
1066 while (ldpaths[i]) { 1743 array_for_each(ldpaths, n, ldpath) {
1067 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1; 1744 if (!scan_l && !strcmp(ldpath, "/lib")) scan_l = 1;
1068 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1; 1745 if (!scan_ul && !strcmp(ldpath, "/usr/lib")) scan_ul = 1;
1069 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1; 1746 if (!scan_ull && !strcmp(ldpath, "/usr/local/lib")) scan_ull = 1;
1070 scanelf_dir(ldpaths[i]); 1747 scanelf_dir(ldpath);
1071 ++i; 1748 ++i;
1072 } 1749 }
1073 1750
1074 if (!scan_l) scanelf_dir("/lib"); 1751 if (!scan_l) scanelf_dir("/lib");
1075 if (!scan_ul) scanelf_dir("/usr/lib"); 1752 if (!scan_ul) scanelf_dir("/usr/lib");
1076 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1753 if (!scan_ull) scanelf_dir("/usr/local/lib");
1077} 1754}
1078 1755
1079/* scan env PATH for paths */ 1756/* scan env PATH for paths */
1080static void scanelf_envpath() 1757static void scanelf_envpath(void)
1081{ 1758{
1082 char *path, *p; 1759 char *path, *p;
1083 1760
1084 path = getenv("PATH"); 1761 path = getenv("PATH");
1085 if (!path) 1762 if (!path)
1092 } 1769 }
1093 1770
1094 free(path); 1771 free(path);
1095} 1772}
1096 1773
1097 1774/* usage / invocation handling functions */ /* Free Flags: c d j u w G H J K P Q U W */
1098/* usage / invocation handling functions */
1099#define PARSE_FLAGS "plRmyxetrnLibSs:gN:TaqvF:f:o:BhV" 1775#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZCBhV"
1100#define a_argument required_argument 1776#define a_argument required_argument
1101static struct option const long_opts[] = { 1777static struct option const long_opts[] = {
1102 {"path", no_argument, NULL, 'p'}, 1778 {"path", no_argument, NULL, 'p'},
1103 {"ldpath", no_argument, NULL, 'l'}, 1779 {"ldpath", no_argument, NULL, 'l'},
1780 {"root", a_argument, NULL, 128},
1104 {"recursive", no_argument, NULL, 'R'}, 1781 {"recursive", no_argument, NULL, 'R'},
1105 {"mount", no_argument, NULL, 'm'}, 1782 {"mount", no_argument, NULL, 'm'},
1106 {"symlink", no_argument, NULL, 'y'}, 1783 {"symlink", no_argument, NULL, 'y'},
1784 {"archives", no_argument, NULL, 'A'},
1785 {"ldcache", no_argument, NULL, 'L'},
1786 {"fix", no_argument, NULL, 'X'},
1787 {"setpax", a_argument, NULL, 'z'},
1107 {"pax", no_argument, NULL, 'x'}, 1788 {"pax", no_argument, NULL, 'x'},
1108 {"header", no_argument, NULL, 'e'}, 1789 {"header", no_argument, NULL, 'e'},
1109 {"textrel", no_argument, NULL, 't'}, 1790 {"textrel", no_argument, NULL, 't'},
1110 {"rpath", no_argument, NULL, 'r'}, 1791 {"rpath", no_argument, NULL, 'r'},
1111 {"needed", no_argument, NULL, 'n'}, 1792 {"needed", no_argument, NULL, 'n'},
1112 {"ldcache", no_argument, NULL, 'L'},
1113 {"interp", no_argument, NULL, 'i'}, 1793 {"interp", no_argument, NULL, 'i'},
1114 {"bind", no_argument, NULL, 'b'}, 1794 {"bind", no_argument, NULL, 'b'},
1115 {"soname", no_argument, NULL, 'S'}, 1795 {"soname", no_argument, NULL, 'S'},
1116 {"symbol", a_argument, NULL, 's'}, 1796 {"symbol", a_argument, NULL, 's'},
1797 {"section", a_argument, NULL, 'k'},
1117 {"lib", a_argument, NULL, 'N'}, 1798 {"lib", a_argument, NULL, 'N'},
1118 {"gmatch", no_argument, NULL, 'g'}, 1799 {"gmatch", no_argument, NULL, 'g'},
1119 {"textrels", no_argument, NULL, 'T'}, 1800 {"textrels", no_argument, NULL, 'T'},
1801 {"etype", a_argument, NULL, 'E'},
1802 {"bits", a_argument, NULL, 'M'},
1803 {"endian", no_argument, NULL, 'D'},
1804 {"osabi", no_argument, NULL, 'I'},
1805 {"eabi", no_argument, NULL, 'Y'},
1806 {"perms", a_argument, NULL, 'O'},
1807 {"size", no_argument, NULL, 'Z'},
1120 {"all", no_argument, NULL, 'a'}, 1808 {"all", no_argument, NULL, 'a'},
1121 {"quiet", no_argument, NULL, 'q'}, 1809 {"quiet", no_argument, NULL, 'q'},
1122 {"verbose", no_argument, NULL, 'v'}, 1810 {"verbose", no_argument, NULL, 'v'},
1123 {"format", a_argument, NULL, 'F'}, 1811 {"format", a_argument, NULL, 'F'},
1124 {"from", a_argument, NULL, 'f'}, 1812 {"from", a_argument, NULL, 'f'},
1125 {"file", a_argument, NULL, 'o'}, 1813 {"file", a_argument, NULL, 'o'},
1814 {"nocolor", no_argument, NULL, 'C'},
1126 {"nobanner", no_argument, NULL, 'B'}, 1815 {"nobanner", no_argument, NULL, 'B'},
1127 {"help", no_argument, NULL, 'h'}, 1816 {"help", no_argument, NULL, 'h'},
1128 {"version", no_argument, NULL, 'V'}, 1817 {"version", no_argument, NULL, 'V'},
1129 {NULL, no_argument, NULL, 0x0} 1818 {NULL, no_argument, NULL, 0x0}
1130}; 1819};
1131 1820
1132static const char *opts_help[] = { 1821static const char * const opts_help[] = {
1133 "Scan all directories in PATH environment", 1822 "Scan all directories in PATH environment",
1134 "Scan all directories in /etc/ld.so.conf", 1823 "Scan all directories in /etc/ld.so.conf",
1824 "Root directory (use with -l or -p)",
1135 "Scan directories recursively", 1825 "Scan directories recursively",
1136 "Don't recursively cross mount points", 1826 "Don't recursively cross mount points",
1137 "Don't scan symlinks\n", 1827 "Don't scan symlinks",
1828 "Scan archives (.a files)",
1829 "Utilize ld.so.cache information (use with -r/-n)",
1830 "Try and 'fix' bad things (use with -r/-e)",
1831 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1138 "Print PaX markings", 1832 "Print PaX markings",
1139 "Print GNU_STACK/PT_LOAD markings", 1833 "Print GNU_STACK/PT_LOAD markings",
1140 "Print TEXTREL information", 1834 "Print TEXTREL information",
1141 "Print RPATH information", 1835 "Print RPATH information",
1142 "Print NEEDED information", 1836 "Print NEEDED information",
1143 "Resolve NEEDED information (use with -n)",
1144 "Print INTERP information", 1837 "Print INTERP information",
1145 "Print BIND information", 1838 "Print BIND information",
1146 "Print SONAME information", 1839 "Print SONAME information",
1147 "Find a specified symbol", 1840 "Find a specified symbol",
1841 "Find a specified section",
1148 "Find a specified library", 1842 "Find a specified library",
1149 "Use strncmp to match libraries. (use with -N)", 1843 "Use regex matching rather than string compare (use with -s)",
1150 "Locate cause of TEXTREL", 1844 "Locate cause of TEXTREL",
1151 "Print all scanned info (-x -e -t -r -b)\n", 1845 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1846 "Print only ELF files matching numeric bits",
1847 "Print Endianness",
1848 "Print OSABI",
1849 "Print EABI (EM_ARM Only)",
1850 "Print only ELF files matching octal permissions",
1851 "Print ELF file size",
1852 "Print all useful/simple info\n",
1152 "Only output 'bad' things", 1853 "Only output 'bad' things",
1153 "Be verbose (can be specified more than once)", 1854 "Be verbose (can be specified more than once)",
1154 "Use specified format for output", 1855 "Use specified format for output",
1155 "Read input stream from a filename", 1856 "Read input stream from a filename",
1156 "Write output stream to a filename", 1857 "Write output stream to a filename",
1858 "Don't emit color in output",
1157 "Don't display the header", 1859 "Don't display the header",
1158 "Print this help and exit", 1860 "Print this help and exit",
1159 "Print version and exit", 1861 "Print version and exit",
1160 NULL 1862 NULL
1161}; 1863};
1163/* display usage and exit */ 1865/* display usage and exit */
1164static void usage(int status) 1866static void usage(int status)
1165{ 1867{
1166 unsigned long i; 1868 unsigned long i;
1167 printf("* Scan ELF binaries for stuff\n\n" 1869 printf("* Scan ELF binaries for stuff\n\n"
1168 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1870 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1169 printf("Options: -[%s]\n", PARSE_FLAGS); 1871 printf("Options: -[%s]\n", PARSE_FLAGS);
1170 for (i = 0; long_opts[i].name; ++i) 1872 for (i = 0; long_opts[i].name; ++i)
1171 if (long_opts[i].has_arg == no_argument) 1873 if (long_opts[i].has_arg == no_argument)
1172 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1874 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1875 long_opts[i].name, opts_help[i]);
1876 else if (long_opts[i].val > '~')
1877 printf(" --%-7s <arg> * %s\n",
1173 long_opts[i].name, opts_help[i]); 1878 long_opts[i].name, opts_help[i]);
1174 else 1879 else
1175 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1880 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1176 long_opts[i].name, opts_help[i]); 1881 long_opts[i].name, opts_help[i]);
1177 1882
1178 if (status != EXIT_SUCCESS) 1883 puts("\nFor more information, see the scanelf(1) manpage");
1179 exit(status);
1180
1181 puts("\nThe format modifiers for the -F option are:");
1182 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1183 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1184 puts(" i INTERP \tb BIND \ts symbol");
1185 puts(" N library \to Type \tT TEXTRELs");
1186 puts(" S SONAME");
1187 puts(" p filename (with search path removed)");
1188 puts(" f filename (short name/basename)");
1189 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1190
1191 exit(status); 1884 exit(status);
1192} 1885}
1193 1886
1194/* parse command line arguments and preform needed actions */ 1887/* parse command line arguments and preform needed actions */
1888#define do_pax_state(option, flag) \
1889 if (islower(option)) { \
1890 flags &= ~PF_##flag; \
1891 flags |= PF_NO##flag; \
1892 } else { \
1893 flags &= ~PF_NO##flag; \
1894 flags |= PF_##flag; \
1895 }
1195static void parseargs(int argc, char *argv[]) 1896static int parseargs(int argc, char *argv[])
1196{ 1897{
1197 int i; 1898 int i;
1198 char *from_file = NULL; 1899 const char *from_file = NULL;
1900 int ret = 0;
1199 1901
1200 opterr = 0; 1902 opterr = 0;
1201 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1903 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1202 switch (i) { 1904 switch (i) {
1203 1905
1207 VERSION, __FILE__, __DATE__, rcsid, argv0); 1909 VERSION, __FILE__, __DATE__, rcsid, argv0);
1208 exit(EXIT_SUCCESS); 1910 exit(EXIT_SUCCESS);
1209 break; 1911 break;
1210 case 'h': usage(EXIT_SUCCESS); break; 1912 case 'h': usage(EXIT_SUCCESS); break;
1211 case 'f': 1913 case 'f':
1212 if (from_file) err("Don't specify -f twice"); 1914 if (from_file) warn("You prob don't want to specify -f twice");
1213 from_file = xstrdup(optarg); 1915 from_file = optarg;
1916 break;
1917 case 'E':
1918 strncpy(match_etypes, optarg, sizeof(match_etypes));
1919 break;
1920 case 'M':
1921 match_bits = atoi(optarg);
1922 if (match_bits == 0) {
1923 if (strcmp(optarg, "ELFCLASS32") == 0)
1924 match_bits = 32;
1925 if (strcmp(optarg, "ELFCLASS64") == 0)
1926 match_bits = 64;
1927 }
1928 break;
1929 case 'O':
1930 if (sscanf(optarg, "%o", &match_perms) == -1)
1931 match_bits = 0;
1214 break; 1932 break;
1215 case 'o': { 1933 case 'o': {
1216 FILE *fp = NULL;
1217 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1934 if (freopen(optarg, "w", stdout) == NULL)
1218 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1935 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1219 SET_STDOUT(fp);
1220 break; 1936 break;
1221 } 1937 }
1222 1938 case 'k':
1939 xarraypush(find_section_arr, optarg, strlen(optarg));
1940 break;
1223 case 's': { 1941 case 's': {
1224 if (find_sym) warn("You prob don't want to specify -s twice"); 1942 if (find_sym) warn("You prob don't want to specify -s twice");
1225 find_sym = optarg; 1943 find_sym = optarg;
1226 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1227 sprintf(versioned_symname, "%s@", find_sym);
1228 break; 1944 break;
1229 } 1945 }
1230 case 'N': { 1946 case 'N':
1231 if (find_lib) warn("You prob don't want to specify -N twice"); 1947 xarraypush(find_lib_arr, optarg, strlen(optarg));
1232 find_lib = optarg;
1233 break; 1948 break;
1234 }
1235
1236 case 'F': { 1949 case 'F': {
1237 if (out_format) warn("You prob don't want to specify -F twice"); 1950 if (out_format) warn("You prob don't want to specify -F twice");
1238 out_format = optarg; 1951 out_format = optarg;
1239 break; 1952 break;
1240 } 1953 }
1954 case 'z': {
1955 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1956 size_t x;
1241 1957
1242 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */ 1958 for (x = 0; x < strlen(optarg); x++) {
1959 switch (optarg[x]) {
1960 case 'p':
1961 case 'P':
1962 do_pax_state(optarg[x], PAGEEXEC);
1963 break;
1964 case 's':
1965 case 'S':
1966 do_pax_state(optarg[x], SEGMEXEC);
1967 break;
1968 case 'm':
1969 case 'M':
1970 do_pax_state(optarg[x], MPROTECT);
1971 break;
1972 case 'e':
1973 case 'E':
1974 do_pax_state(optarg[x], EMUTRAMP);
1975 break;
1976 case 'r':
1977 case 'R':
1978 do_pax_state(optarg[x], RANDMMAP);
1979 break;
1980 case 'x':
1981 case 'X':
1982 do_pax_state(optarg[x], RANDEXEC);
1983 break;
1984 default:
1985 break;
1986 }
1987 }
1988 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1989 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1990 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1991 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1992 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1993 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1994 setpax = flags;
1995 break;
1996 }
1997 case 'Z': show_size = 1; break;
1998 case 'g': g_match = 1; break;
1243 case 'L': printcache = 1; break; 1999 case 'L': use_ldcache = 1; break;
1244 case 'y': scan_symlink = 0; break; 2000 case 'y': scan_symlink = 0; break;
2001 case 'A': scan_archives = 1; break;
2002 case 'C': color_init(true); break;
1245 case 'B': show_banner = 0; break; 2003 case 'B': show_banner = 0; break;
1246 case 'l': scan_ldpath = 1; break; 2004 case 'l': scan_ldpath = 1; break;
1247 case 'p': scan_envpath = 1; break; 2005 case 'p': scan_envpath = 1; break;
1248 case 'R': dir_recurse = 1; break; 2006 case 'R': dir_recurse = 1; break;
1249 case 'm': dir_crossmount = 0; break; 2007 case 'm': dir_crossmount = 0; break;
2008 case 'X': ++fix_elf; break;
1250 case 'x': show_pax = 1; break; 2009 case 'x': show_pax = 1; break;
1251 case 'e': show_phdr = 1; break; 2010 case 'e': show_phdr = 1; break;
1252 case 't': show_textrel = 1; break; 2011 case 't': show_textrel = 1; break;
1253 case 'r': show_rpath = 1; break; 2012 case 'r': show_rpath = 1; break;
1254 case 'n': show_needed = 1; break; 2013 case 'n': show_needed = 1; break;
1256 case 'b': show_bind = 1; break; 2015 case 'b': show_bind = 1; break;
1257 case 'S': show_soname = 1; break; 2016 case 'S': show_soname = 1; break;
1258 case 'T': show_textrels = 1; break; 2017 case 'T': show_textrels = 1; break;
1259 case 'q': be_quiet = 1; break; 2018 case 'q': be_quiet = 1; break;
1260 case 'v': be_verbose = (be_verbose % 20) + 1; break; 2019 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1261 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 2020 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1262 2021 case 'D': show_endian = 1; break;
2022 case 'I': show_osabi = 1; break;
2023 case 'Y': show_eabi = 1; break;
2024 case 128:
2025 root = optarg;
2026 break;
1263 case ':': 2027 case ':':
1264 err("Option missing parameter\n"); 2028 err("Option '%c' is missing parameter", optopt);
1265 case '?': 2029 case '?':
1266 err("Unknown option\n"); 2030 err("Unknown option '%c' or argument missing", optopt);
1267 default: 2031 default:
1268 err("Unhandled option '%c'", i); 2032 err("Unhandled option '%c'; please report this", i);
1269 }
1270 } 2033 }
1271 2034 }
2035 if (show_textrels && be_verbose) {
2036 if (which("objdump") != NULL)
2037 has_objdump = 1;
2038 }
2039 /* flatten arrays for display */
2040 if (array_cnt(find_lib_arr))
2041 find_lib = array_flatten_str(find_lib_arr);
2042 if (array_cnt(find_section_arr))
2043 find_section = array_flatten_str(find_section_arr);
1272 /* let the format option override all other options */ 2044 /* let the format option override all other options */
1273 if (out_format) { 2045 if (out_format) {
1274 show_pax = show_phdr = show_textrel = show_rpath = \ 2046 show_pax = show_phdr = show_textrel = show_rpath = \
1275 show_needed = show_interp = show_bind = show_soname = \ 2047 show_needed = show_interp = show_bind = show_soname = \
1276 show_textrels = 0; 2048 show_textrels = show_perms = show_endian = show_size = \
2049 show_osabi = show_eabi = 0;
1277 for (i = 0; out_format[i]; ++i) { 2050 for (i = 0; out_format[i]; ++i) {
1278 if (!IS_MODIFIER(out_format[i])) continue; 2051 if (!IS_MODIFIER(out_format[i])) continue;
1279 2052
1280 switch (out_format[++i]) { 2053 switch (out_format[++i]) {
2054 case '+': break;
1281 case '%': break; 2055 case '%': break;
1282 case '#': break; 2056 case '#': break;
1283 case 'F': break; 2057 case 'F': break;
1284 case 'p': break; 2058 case 'p': break;
1285 case 'f': break; 2059 case 'f': break;
2060 case 'k': break;
1286 case 's': break; 2061 case 's': break;
1287 case 'N': break; 2062 case 'N': break;
1288 case 'o': break; 2063 case 'o': break;
2064 case 'a': break;
2065 case 'M': break;
2066 case 'Z': show_size = 1; break;
2067 case 'D': show_endian = 1; break;
2068 case 'I': show_osabi = 1; break;
2069 case 'Y': show_eabi = 1; break;
2070 case 'O': show_perms = 1; break;
1289 case 'x': show_pax = 1; break; 2071 case 'x': show_pax = 1; break;
1290 case 'e': show_phdr = 1; break; 2072 case 'e': show_phdr = 1; break;
1291 case 't': show_textrel = 1; break; 2073 case 't': show_textrel = 1; break;
1292 case 'r': show_rpath = 1; break; 2074 case 'r': show_rpath = 1; break;
1293 case 'n': show_needed = 1; break; 2075 case 'n': show_needed = 1; break;
1294 case 'i': show_interp = 1; break; 2076 case 'i': show_interp = 1; break;
1295 case 'b': show_bind = 1; break; 2077 case 'b': show_bind = 1; break;
1296 case 'S': show_soname = 1; break; 2078 case 'S': show_soname = 1; break;
1297 case 'T': show_textrels = 1; break; 2079 case 'T': show_textrels = 1; break;
1298 default: 2080 default:
1299 err("Invalid format specifier '%c' (byte %i)", 2081 err("Invalid format specifier '%c' (byte %i)",
1300 out_format[i], i+1); 2082 out_format[i], i+1);
1301 } 2083 }
1302 } 2084 }
1303 2085
1304 /* construct our default format */ 2086 /* construct our default format */
1305 } else { 2087 } else {
1306 size_t fmt_len = 30; 2088 size_t fmt_len = 30;
1307 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 2089 out_format = xmalloc(sizeof(char) * fmt_len);
2090 *out_format = '\0';
1308 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 2091 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1309 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 2092 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
2093 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
2094 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
2095 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
2096 if (show_osabi) xstrcat(&out_format, "%I ", &fmt_len);
2097 if (show_eabi) xstrcat(&out_format, "%Y ", &fmt_len);
1310 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 2098 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1311 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 2099 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1312 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 2100 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1313 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 2101 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1314 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 2102 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1315 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 2103 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1316 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 2104 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1317 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 2105 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1318 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 2106 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
2107 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1319 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 2108 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1320 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 2109 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1321 } 2110 }
1322 if (be_verbose > 2) printf("Format: %s\n", out_format); 2111 if (be_verbose > 2) printf("Format: %s\n", out_format);
1323 2112
1324 /* now lets actually do the scanning */ 2113 /* now lets actually do the scanning */
1325 if (scan_ldpath || (show_rpath && be_quiet)) 2114 if (scan_ldpath || use_ldcache)
1326 load_ld_so_conf(); 2115 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1327 if (scan_ldpath) scanelf_ldpath(); 2116 if (scan_ldpath) scanelf_ldpath();
1328 if (scan_envpath) scanelf_envpath(); 2117 if (scan_envpath) scanelf_envpath();
2118 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
2119 from_file = "-";
1329 if (from_file) { 2120 if (from_file) {
1330 scanelf_from_file(from_file); 2121 scanelf_from_file(from_file);
1331 free(from_file);
1332 from_file = *argv; 2122 from_file = *argv;
1333 } 2123 }
1334 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 2124 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1335 err("Nothing to scan !?"); 2125 err("Nothing to scan !?");
1336 while (optind < argc) { 2126 while (optind < argc) {
1337 search_path = argv[optind++]; 2127 search_path = argv[optind++];
1338 scanelf_dir(search_path); 2128 ret = scanelf_dir(search_path);
1339 } 2129 }
1340 2130
1341 /* clean up */ 2131 /* clean up */
1342 if (versioned_symname) free(versioned_symname);
1343 for (i = 0; ldpaths[i]; ++i)
1344 free(ldpaths[i]); 2132 xarrayfree(ldpaths);
2133 xarrayfree(find_lib_arr);
2134 xarrayfree(find_section_arr);
2135 free(find_lib);
2136 free(find_section);
1345 2137
1346 if (ldcache != 0) 2138 if (ldcache != 0)
1347 munmap(ldcache, ldcache_size); 2139 munmap(ldcache, ldcache_size);
1348}
1349
1350
1351
1352/* utility funcs */
1353static char *xstrdup(const char *s)
1354{
1355 char *ret = strdup(s);
1356 if (!ret) err("Could not strdup(): %s", strerror(errno));
1357 return ret; 2140 return ret;
1358} 2141}
1359static void *xmalloc(size_t size)
1360{
1361 void *ret = malloc(size);
1362 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1363 return ret;
1364}
1365static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1366{
1367 size_t new_len;
1368 2142
1369 new_len = strlen(*dst) + strlen(src); 2143static char **get_split_env(const char *envvar)
1370 if (*curr_len <= new_len) {
1371 *curr_len = new_len + (*curr_len / 2);
1372 *dst = realloc(*dst, *curr_len);
1373 if (!*dst)
1374 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1375 }
1376
1377 if (n)
1378 strncat(*dst, src, n);
1379 else
1380 strcat(*dst, src);
1381}
1382static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1383{ 2144{
1384 static char my_app[2]; 2145 const char *delims = " \t\n";
1385 my_app[0] = append; 2146 char **envvals = NULL;
1386 my_app[1] = '\0'; 2147 char *env, *s;
1387 xstrcat(dst, my_app, curr_len); 2148 int nentry;
1388}
1389 2149
2150 if ((env = getenv(envvar)) == NULL)
2151 return NULL;
1390 2152
2153 env = xstrdup(env);
2154 if (env == NULL)
2155 return NULL;
2156
2157 s = strtok(env, delims);
2158 if (s == NULL) {
2159 free(env);
2160 return NULL;
2161 }
2162
2163 nentry = 0;
2164 while (s != NULL) {
2165 ++nentry;
2166 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
2167 envvals[nentry-1] = s;
2168 s = strtok(NULL, delims);
2169 }
2170 envvals[nentry] = NULL;
2171
2172 /* don't want to free(env) as it contains the memory that backs
2173 * the envvals array of strings */
2174 return envvals;
2175}
2176
2177static void parseenv(void)
2178{
2179 color_init(false);
2180 qa_textrels = get_split_env("QA_TEXTRELS");
2181 qa_execstack = get_split_env("QA_EXECSTACK");
2182 qa_wx_load = get_split_env("QA_WX_LOAD");
2183}
2184
2185#ifdef __PAX_UTILS_CLEANUP
2186static void cleanup(void)
2187{
2188 free(out_format);
2189 free(qa_textrels);
2190 free(qa_execstack);
2191 free(qa_wx_load);
2192}
2193#endif
1391 2194
1392int main(int argc, char *argv[]) 2195int main(int argc, char *argv[])
1393{ 2196{
2197 int ret;
1394 if (argc < 2) 2198 if (argc < 2)
1395 usage(EXIT_FAILURE); 2199 usage(EXIT_FAILURE);
2200 parseenv();
1396 parseargs(argc, argv); 2201 ret = parseargs(argc, argv);
1397 fclose(stdout); 2202 fclose(stdout);
1398#ifdef __BOUNDS_CHECKING_ON 2203#ifdef __PAX_UTILS_CLEANUP
1399 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 2204 cleanup();
2205 warn("The calls to add/delete heap should be off:\n"
2206 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
2207 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1400#endif 2208#endif
1401 return EXIT_SUCCESS; 2209 return ret;
1402} 2210}
2211
2212/* Match filename against entries in matchlist, return TRUE
2213 * if the file is listed */
2214static int file_matches_list(const char *filename, char **matchlist)
2215{
2216 char **file;
2217 char *match;
2218 char buf[__PAX_UTILS_PATH_MAX];
2219
2220 if (matchlist == NULL)
2221 return 0;
2222
2223 for (file = matchlist; *file != NULL; file++) {
2224 if (search_path) {
2225 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2226 match = buf;
2227 } else {
2228 match = *file;
2229 }
2230 if (fnmatch(match, filename, 0) == 0)
2231 return 1;
2232 }
2233 return 0;
2234}

Legend:
Removed from v.1.96  
changed lines
  Added in v.1.227

  ViewVC Help
Powered by ViewVC 1.1.20