/[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.206 Revision 1.269
1/* 1/*
2 * Copyright 2003-2007 Gentoo Foundation 2 * Copyright 2003-2012 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.206 2008/12/30 13:34:46 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.269 2014/11/20 01:25:56 vapier Exp $
5 * 5 *
6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2012 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2012 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10static const char *rcsid = "$Id: scanelf.c,v 1.206 2008/12/30 13:34:46 vapier Exp $"; 10static const char rcsid[] = "$Id: scanelf.c,v 1.269 2014/11/20 01:25:56 vapier Exp $";
11const char * const argv0 = "scanelf"; 11const char argv0[] = "scanelf";
12 12
13#include "paxinc.h" 13#include "paxinc.h"
14 14
15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16 16
17/* prototypes */ 17/* prototypes */
18static int file_matches_list(const char *filename, char **matchlist); 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);
23static int scanelf_dir(const char *path);
24static void scanelf_ldpath(void);
25static void scanelf_envpath(void);
26static void usage(int status);
27static char **get_split_env(const char *envvar);
28static void parseenv(void);
29static int parseargs(int argc, char *argv[]);
30static int rematch(const char *regex, const char *match, int cflags);
31 19
32/* variables to control behavior */ 20/* variables to control behavior */
33static char match_etypes[126] = ""; 21static array_t _match_etypes = array_init_decl, *match_etypes = &_match_etypes;
34static char *ldpaths[256]; 22static array_t _ldpaths = array_init_decl, *ldpaths = &_ldpaths;
35static char scan_ldpath = 0; 23static char scan_ldpath = 0;
36static char scan_envpath = 0; 24static char scan_envpath = 0;
37static char scan_symlink = 1; 25static char scan_symlink = 1;
38static char scan_archives = 0; 26static char scan_archives = 0;
39static char dir_recurse = 0; 27static char dir_recurse = 0;
56static char be_quiet = 0; 44static char be_quiet = 0;
57static char be_verbose = 0; 45static char be_verbose = 0;
58static char be_wewy_wewy_quiet = 0; 46static char be_wewy_wewy_quiet = 0;
59static char be_semi_verbose = 0; 47static char be_semi_verbose = 0;
60static char *find_sym = NULL; 48static char *find_sym = NULL;
49static array_t _find_sym_arr = array_init_decl, *find_sym_arr = &_find_sym_arr;
50static array_t _find_sym_regex_arr = array_init_decl, *find_sym_regex_arr = &_find_sym_regex_arr;
61static char *find_lib = NULL; 51static char *find_lib = NULL;
52static array_t _find_lib_arr = array_init_decl, *find_lib_arr = &_find_lib_arr;
62static char *find_section = NULL; 53static char *find_section = NULL;
54static array_t _find_section_arr = array_init_decl, *find_section_arr = &_find_section_arr;
63static char *out_format = NULL; 55static char *out_format = NULL;
64static char *search_path = NULL; 56static char *search_path = NULL;
65static char fix_elf = 0; 57static char fix_elf = 0;
66static char g_match = 0; 58static char g_match = 0;
67static char use_ldcache = 0; 59static char use_ldcache = 0;
60static char use_ldpath = 0;
68 61
69static char **qa_textrels = NULL; 62static char **qa_textrels = NULL;
70static char **qa_execstack = NULL; 63static char **qa_execstack = NULL;
71static char **qa_wx_load = NULL; 64static char **qa_wx_load = NULL;
65static int root_fd = AT_FDCWD;
72 66
73static int match_bits = 0; 67static int match_bits = 0;
74static unsigned int match_perms = 0; 68static unsigned int match_perms = 0;
75static caddr_t ldcache = 0; 69static void *ldcache = NULL;
76static size_t ldcache_size = 0; 70static size_t ldcache_size = 0;
77static unsigned long setpax = 0UL; 71static unsigned long setpax = 0UL;
78 72
79static int has_objdump = 0; 73static const char *objdump;
80 74
81/* find the path to a file by name */ 75/* Find the path to a file by name. Note: we do not currently handle the
82static char *which(const char *fname) 76 * empty path element correctly (should behave by searching $PWD). */
77static const char *which(const char *fname, const char *envvar)
83{ 78{
84 static char fullpath[BUFSIZ]; 79 size_t path_len, fname_len;
80 const char *env_path;
85 char *path, *p; 81 char *path, *p, *ep;
86 82
83 p = getenv(envvar);
84 if (p)
85 return p;
86
87 path = getenv("PATH"); 87 env_path = getenv("PATH");
88 if (!path) 88 if (!env_path)
89 return NULL; 89 return NULL;
90 90
91 path = xstrdup(path); 91 /* Create a copy of the $PATH that we can safely modify.
92 while ((p = strrchr(path, ':')) != NULL) { 92 * Make it a little bigger so we can append "/fname".
93 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname); 93 * We do this twice -- once for a perm copy, and once for
94 *p = 0; 94 * room at the end of the last element. */
95 path_len = strlen(env_path);
96 fname_len = strlen(fname);
97 path = xmalloc(path_len + (fname_len * 2) + 2 + 2);
98 memcpy(path, env_path, path_len + 1);
99
100 p = path + path_len + 1 + fname_len + 1;
101 *p = '/';
102 memcpy(p + 1, fname, fname_len + 1);
103
104 /* Repoint fname to the copy in the env string as it has
105 * the leading slash which we can include in a single memcpy.
106 * Increase the fname len to include the '/' and '\0'. */
107 fname = p;
108 fname_len += 2;
109
110 p = path;
111 while (p) {
112 ep = strchr(p, ':');
113 /* Append the /foo path to the current element. */
114 if (ep)
115 memcpy(ep, fname, fname_len);
116 else
117 memcpy(path + path_len, fname, fname_len);
118
95 if (access(fullpath, R_OK) != -1) { 119 if (access(p, R_OK) != -1)
96 free(path);
97 return fullpath; 120 return p;
121
122 p = ep;
123 if (ep) {
124 /* If not the last element, restore the chunk we clobbered. */
125 size_t offset = ep - path;
126 size_t restore = min(path_len - offset, fname_len);
127 memcpy(ep, env_path + offset, restore);
128 ++p;
98 } 129 }
99 } 130 }
131
100 free(path); 132 free(path);
101 return NULL; 133 return NULL;
102} 134}
103 135
104/* 1 on failure. 0 otherwise */ 136static FILE *fopenat_r(int dir_fd, const char *path)
105static int rematch(const char *regex, const char *match, int cflags)
106{ 137{
107 regex_t preg; 138 int fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
108 int ret; 139 if (fd == -1)
140 return NULL;
141 return fdopen(fd, "re");
142}
109 143
110 if ((match == NULL) || (regex == NULL)) 144static const char *root_rel_path(const char *path)
111 return EXIT_FAILURE; 145{
112 146 /*
113 if ((ret = regcomp(&preg, regex, cflags))) { 147 * openat() will ignore the dirfd if path starts with
114 char err[256]; 148 * a /, so consume all of that noise
115 149 *
116 if (regerror(ret, &preg, err, sizeof(err))) 150 * XXX: we don't handle relative paths like ../ that
117 fprintf(stderr, "regcomp failed: %s", err); 151 * break out of the --root option, but for now, just
118 else 152 * don't do that :P.
119 fprintf(stderr, "regcomp failed"); 153 */
120 154 if (root_fd != AT_FDCWD) {
121 return EXIT_FAILURE; 155 while (*path == '/')
156 ++path;
157 if (*path == '\0')
158 path = ".";
122 } 159 }
123 ret = regexec(&preg, match, 0, NULL, 0);
124 regfree(&preg);
125 160
126 return ret; 161 return path;
127} 162}
128 163
129/* sub-funcs for scanelf_file() */ 164/* sub-funcs for scanelf_fileat() */
130static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 165static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
131{ 166{
132 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 167 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
168
169 /* debug sections */
170 void *symtab = elf_findsecbyname(elf, ".symtab");
171 void *strtab = elf_findsecbyname(elf, ".strtab");
172 /* runtime sections */
173 void *dynsym = elf_findsecbyname(elf, ".dynsym");
174 void *dynstr = elf_findsecbyname(elf, ".dynstr");
175
176 /*
177 * If the sections are marked NOBITS, then they don't exist, so we just
178 * skip them. This let's us work sanely with splitdebug ELFs (rather
179 * than spewing a lot of "corrupt ELF" messages later on). In malformed
180 * ELFs, the section might be wrongly set to NOBITS, but screw em.
181 *
182 * We need to make sure the debug/runtime sym/str sets are used together
183 * as they are generated in sync. Trying to mix them won't work.
184 */
133#define GET_SYMTABS(B) \ 185#define GET_SYMTABS(B) \
134 if (elf->elf_class == ELFCLASS ## B) { \ 186 if (elf->elf_class == ELFCLASS ## B) { \
135 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \ 187 Elf ## B ## _Shdr *esymtab = symtab; \
136 /* debug sections */ \ 188 Elf ## B ## _Shdr *estrtab = strtab; \
137 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \ 189 Elf ## B ## _Shdr *edynsym = dynsym; \
138 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \ 190 Elf ## B ## _Shdr *edynstr = dynstr; \
139 /* runtime sections */ \ 191 \
140 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \ 192 if (symtab && EGET(esymtab->sh_type) == SHT_NOBITS) \
141 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \ 193 symtab = NULL; \
142 if (symtab && dynsym) { \ 194 if (dynsym && EGET(edynsym->sh_type) == SHT_NOBITS) \
143 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \ 195 dynsym = NULL; \
196 if (strtab && EGET(estrtab->sh_type) == SHT_NOBITS) \
197 strtab = NULL; \
198 if (dynstr && EGET(edynstr->sh_type) == SHT_NOBITS) \
199 dynstr = NULL; \
200 \
201 /* Use the set with more symbols if both exist. */ \
202 if (symtab && dynsym && strtab && dynstr) { \
203 if (EGET(esymtab->sh_size) > EGET(edynsym->sh_size)) \
204 goto debug##B; \
205 else \
206 goto runtime##B; \
207 } else if (symtab && strtab) { \
208 debug##B: \
209 *sym = symtab; \
210 *str = strtab; \
211 return; \
212 } else if (dynsym && dynstr) { \
213 runtime##B: \
214 *sym = dynsym; \
215 *str = dynstr; \
216 return; \
144 } else { \ 217 } else { \
145 *sym = (void*)(symtab ? symtab : dynsym); \ 218 *sym = *str = NULL; \
146 } \ 219 } \
147 if (strtab && dynstr) { \
148 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
149 } else { \
150 *tab = (void*)(strtab ? strtab : dynstr); \
151 } \
152 } 220 }
153 GET_SYMTABS(32) 221 GET_SYMTABS(32)
154 GET_SYMTABS(64) 222 GET_SYMTABS(64)
223
224 if (*sym && *str)
225 return;
226
227 /*
228 * damn, they're really going to make us work for it huh?
229 * reconstruct the section header info out of the dynamic
230 * tags so we can see what symbols this guy uses at runtime.
231 */
232#define GET_SYMTABS_DT(B) \
233 if (elf->elf_class == ELFCLASS ## B) { \
234 size_t i; \
235 static Elf ## B ## _Shdr sym_shdr, str_shdr; \
236 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
237 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
238 Elf ## B ## _Addr vsym, vstr, vhash, vgnu_hash; \
239 Elf ## B ## _Dyn *dyn; \
240 Elf ## B ## _Off offset; \
241 \
242 /* lookup symbols used at runtime with DT_SYMTAB / DT_STRTAB */ \
243 vsym = vstr = vhash = vgnu_hash = 0; \
244 memset(&sym_shdr, 0, sizeof(sym_shdr)); \
245 memset(&str_shdr, 0, sizeof(str_shdr)); \
246 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
247 if (EGET(phdr[i].p_type) != PT_DYNAMIC) \
248 continue; \
249 \
250 offset = EGET(phdr[i].p_offset); \
251 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) \
252 continue; \
253 \
254 dyn = DYN ## B (elf->vdata + offset); \
255 while (EGET(dyn->d_tag) != DT_NULL) { \
256 switch (EGET(dyn->d_tag)) { \
257 case DT_SYMTAB: vsym = EGET(dyn->d_un.d_val); break; \
258 case DT_SYMENT: sym_shdr.sh_entsize = dyn->d_un.d_val; break; \
259 case DT_STRTAB: vstr = EGET(dyn->d_un.d_val); break; \
260 case DT_STRSZ: str_shdr.sh_size = dyn->d_un.d_val; break; \
261 case DT_HASH: vhash = EGET(dyn->d_un.d_val); break; \
262 /*case DT_GNU_HASH: vgnu_hash = EGET(dyn->d_un.d_val); break;*/ \
263 } \
264 ++dyn; \
265 } \
266 if (vsym && vstr) \
267 break; \
268 } \
269 if (!vsym || !vstr || !(vhash || vgnu_hash)) \
270 return; \
271 \
272 /* calc offset into the ELF by finding the load addr of the syms */ \
273 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
274 Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \
275 Elf ## B ## _Addr filesz = EGET(phdr[i].p_filesz); \
276 offset = EGET(phdr[i].p_offset); \
277 \
278 if (EGET(phdr[i].p_type) != PT_LOAD) \
279 continue; \
280 \
281 if (vhash >= vaddr && vhash < vaddr + filesz) { \
282 /* Scan the hash table to see how many entries we have */ \
283 Elf32_Word max_sym_idx = 0; \
284 Elf32_Word *hashtbl = elf->vdata + offset + (vhash - vaddr); \
285 Elf32_Word b, nbuckets = EGET(hashtbl[0]); \
286 Elf32_Word nchains = EGET(hashtbl[1]); \
287 Elf32_Word *buckets = &hashtbl[2]; \
288 Elf32_Word *chains = &buckets[nbuckets]; \
289 Elf32_Word sym_idx; \
290 \
291 for (b = 0; b < nbuckets; ++b) { \
292 if (!buckets[b]) \
293 continue; \
294 for (sym_idx = buckets[b]; sym_idx < nchains && sym_idx; sym_idx = chains[sym_idx]) \
295 if (max_sym_idx < sym_idx) \
296 max_sym_idx = sym_idx; \
297 } \
298 ESET(sym_shdr.sh_size, sym_shdr.sh_entsize * max_sym_idx); \
299 } \
300 \
301 if (vsym >= vaddr && vsym < vaddr + filesz) { \
302 ESET(sym_shdr.sh_offset, offset + (vsym - vaddr)); \
303 *sym = &sym_shdr; \
304 } \
305 \
306 if (vstr >= vaddr && vstr < vaddr + filesz) { \
307 ESET(str_shdr.sh_offset, offset + (vstr - vaddr)); \
308 *str = &str_shdr; \
309 } \
310 } \
311 }
312 GET_SYMTABS_DT(32)
313 GET_SYMTABS_DT(64)
155} 314}
156 315
157static char *scanelf_file_pax(elfobj *elf, char *found_pax) 316static char *scanelf_file_pax(elfobj *elf, char *found_pax)
158{ 317{
159 static char ret[7]; 318 static char ret[7];
186 } 345 }
187 SHOW_PAX(32) 346 SHOW_PAX(32)
188 SHOW_PAX(64) 347 SHOW_PAX(64)
189 } 348 }
190 349
191 if (fix_elf && setpax) { 350 /* Note: We do not support setting EI_PAX if not PT_PAX_FLAGS
192 /* set the chpax settings */ 351 * was found. This is known to break ELFs on glibc systems,
193 if (elf->elf_class == ELFCLASS32) { 352 * and mainline PaX has deprecated use of this for a long time.
194 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC) 353 * We could support changing PT_GNU_STACK, but that doesn't
195 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax)); 354 * seem like it's worth the effort. #411919
196 } else { 355 */
197 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
198 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
199 }
200 }
201 356
202 /* fall back to EI_PAX if no PT_PAX was found */ 357 /* fall back to EI_PAX if no PT_PAX was found */
203 if (!*ret) { 358 if (!*ret) {
204 static char *paxflags; 359 static char *paxflags;
205 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 360 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
219static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 374static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
220{ 375{
221 static char ret[12]; 376 static char ret[12];
222 char *found; 377 char *found;
223 unsigned long i, shown, multi_stack, multi_relro, multi_load; 378 unsigned long i, shown, multi_stack, multi_relro, multi_load;
224 int max_pt_load;
225 379
226 if (!show_phdr) return NULL; 380 if (!show_phdr) return NULL;
227 381
228 memcpy(ret, "--- --- ---\0", 12); 382 memcpy(ret, "--- --- ---\0", 12);
229 383
230 shown = 0; 384 shown = 0;
231 multi_stack = multi_relro = multi_load = 0; 385 multi_stack = multi_relro = multi_load = 0;
232 max_pt_load = elf_max_pt_load(elf);
233 386
234#define NOTE_GNU_STACK ".note.GNU-stack" 387#define NOTE_GNU_STACK ".note.GNU-stack"
235#define SHOW_PHDR(B) \ 388#define SHOW_PHDR(B) \
236 if (elf->elf_class == ELFCLASS ## B) { \ 389 if (elf->elf_class == ELFCLASS ## B) { \
237 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 390 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
253 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 406 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
254 found = found_relro; \ 407 found = found_relro; \
255 offset = 4; \ 408 offset = 4; \
256 check_flags = PF_X; \ 409 check_flags = PF_X; \
257 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 410 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
258 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
259 if (multi_load++ > max_pt_load) \
260 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
261 if (file_matches_list(elf->filename, qa_wx_load)) \ 411 if (file_matches_list(elf->filename, qa_wx_load)) \
262 continue; \ 412 continue; \
263 found = found_load; \ 413 found = found_load; \
264 offset = 8; \ 414 offset = 8; \
265 check_flags = PF_W|PF_X; \ 415 check_flags = PF_W|PF_X; \
280 } else if (elf->shdr != NULL) { \ 430 } else if (elf->shdr != NULL) { \
281 /* no program headers which means this is prob an object file */ \ 431 /* no program headers which means this is prob an object file */ \
282 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 432 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
283 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 433 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
284 char *str; \ 434 char *str; \
285 if ((void*)strtbl > (void*)elf->data_end) \ 435 if ((void*)strtbl > elf->data_end) \
286 goto skip_this_shdr##B; \ 436 goto skip_this_shdr##B; \
437 /* let's flag -w/+x object files since the final ELF will most likely \
438 * need write access to the stack (who doesn't !?). so the combined \
439 * output will bring in +w automatically and that's bad. \
440 */ \
287 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 441 check_flags = /*SHF_WRITE|*/SHF_EXECINSTR; \
288 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 442 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
289 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 443 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
290 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 444 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
291 str = elf->data + offset; \ 445 str = elf->data + offset; \
292 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \ 446 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
345 Elf ## B ## _Off offset; \ 499 Elf ## B ## _Off offset; \
346 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 500 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
347 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ 501 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
348 offset = EGET(phdr[i].p_offset); \ 502 offset = EGET(phdr[i].p_offset); \
349 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 503 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
350 dyn = DYN ## B (elf->data + offset); \ 504 dyn = DYN ## B (elf->vdata + offset); \
351 while (EGET(dyn->d_tag) != DT_NULL) { \ 505 while (EGET(dyn->d_tag) != DT_NULL) { \
352 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 506 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
353 *found_textrel = 1; \ 507 *found_textrel = 1; \
354 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 508 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
355 return (be_wewy_wewy_quiet ? NULL : ret); \ 509 return (be_wewy_wewy_quiet ? NULL : ret); \
400 Elf ## B ## _Rela *rela; \ 554 Elf ## B ## _Rela *rela; \
401 /* search the section headers for relocations */ \ 555 /* search the section headers for relocations */ \
402 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ 556 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
403 uint32_t sh_type = EGET(shdr[s].sh_type); \ 557 uint32_t sh_type = EGET(shdr[s].sh_type); \
404 if (sh_type == SHT_REL) { \ 558 if (sh_type == SHT_REL) { \
405 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \ 559 rel = REL ## B (elf->vdata + EGET(shdr[s].sh_offset)); \
406 rela = NULL; \ 560 rela = NULL; \
407 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \ 561 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
408 } else if (sh_type == SHT_RELA) { \ 562 } else if (sh_type == SHT_RELA) { \
409 rel = NULL; \ 563 rel = NULL; \
410 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ 564 rela = RELA ## B (elf->vdata + EGET(shdr[s].sh_offset)); \
411 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ 565 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
412 } else \ 566 } else \
413 continue; \ 567 continue; \
414 /* now see if any of the relocs are in the .text */ \ 568 /* now see if any of the relocs are in the .text */ \
415 for (r = 0; r < rmax; ++r) { \ 569 for (r = 0; r < rmax; ++r) { \
430 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \ 584 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
431 if (be_verbose <= 2) continue; \ 585 if (be_verbose <= 2) continue; \
432 } else \ 586 } else \
433 *found_textrels = 1; \ 587 *found_textrels = 1; \
434 /* locate this relocation symbol name */ \ 588 /* locate this relocation symbol name */ \
435 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 589 sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
436 if ((void*)sym > (void*)elf->data_end) { \ 590 if ((void*)sym > elf->data_end) { \
437 warn("%s: corrupt ELF symbol", elf->filename); \ 591 warn("%s: corrupt ELF symbol", elf->filename); \
438 continue; \ 592 continue; \
439 } \ 593 } \
440 sym_max = ELF ## B ## _R_SYM(r_info); \ 594 sym_max = ELF ## B ## _R_SYM(r_info); \
441 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 595 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
444 sym = NULL; \ 598 sym = NULL; \
445 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 599 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
446 /* show the raw details about this reloc */ \ 600 /* show the raw details about this reloc */ \
447 printf(" %s: ", elf->base_filename); \ 601 printf(" %s: ", elf->base_filename); \
448 if (sym && sym->st_name) \ 602 if (sym && sym->st_name) \
449 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ 603 printf("%s", elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
450 else \ 604 else \
451 printf("(memory/data?)"); \ 605 printf("(memory/data?)"); \
452 printf(" [0x%lX]", (unsigned long)r_offset); \ 606 printf(" [0x%lX]", (unsigned long)r_offset); \
453 /* now try to find the closest symbol that this rel is probably in */ \ 607 /* now try to find the closest symbol that this rel is probably in */ \
454 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 608 sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
455 func = NULL; \ 609 func = NULL; \
456 offset_tmp = 0; \ 610 offset_tmp = 0; \
457 while (sym_max--) { \ 611 while (sym_max--) { \
458 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \ 612 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
459 func = sym; \ 613 func = sym; \
469 else \ 623 else \
470 printf("%s", func_name); \ 624 printf("%s", func_name); \
471 } else \ 625 } else \
472 printf("(optimized out)"); \ 626 printf("(optimized out)"); \
473 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 627 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
474 if (be_verbose && has_objdump) { \ 628 if (be_verbose && objdump) { \
475 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \ 629 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
476 char *sysbuf; \ 630 char *sysbuf; \
477 size_t syslen; \ 631 size_t syslen; \
478 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"; \ 632 const char sysfmt[] = "%s -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
479 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \ 633 syslen = sizeof(sysfmt) + strlen(objdump) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
480 sysbuf = xmalloc(syslen); \ 634 sysbuf = xmalloc(syslen); \
481 if (end_addr < r_offset) \ 635 if (end_addr < r_offset) \
482 /* not uncommon when things are optimized out */ \ 636 /* not uncommon when things are optimized out */ \
483 end_addr = r_offset + 0x100; \ 637 end_addr = r_offset + 0x100; \
484 snprintf(sysbuf, syslen, sysfmt, \ 638 snprintf(sysbuf, syslen, sysfmt, \
639 objdump, \
485 (unsigned long)offset_tmp, \ 640 (unsigned long)offset_tmp, \
486 (unsigned long)end_addr, \ 641 (unsigned long)end_addr, \
487 elf->filename, \ 642 elf->filename, \
488 (unsigned long)r_offset); \ 643 (unsigned long)r_offset); \
489 fflush(stdout); \ 644 fflush(stdout); \
490 system(sysbuf); \ 645 if (system(sysbuf)) {/* don't care */} \
491 fflush(stdout); \ 646 fflush(stdout); \
492 free(sysbuf); \ 647 free(sysbuf); \
493 } \ 648 } \
494 } \ 649 } \
495 } } 650 } }
500 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename); 655 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
501 656
502 return NULL; 657 return NULL;
503} 658}
504 659
505static void rpath_security_checks(elfobj *, char *, const char *);
506static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type) 660static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
507{ 661{
508 struct stat st; 662 struct stat st;
509 switch (*item) { 663 switch (*item) {
510 case '/': break; 664 case '/': break;
523 break; 677 break;
524 default: 678 default:
525 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename); 679 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
526 break; 680 break;
527 } 681 }
682 if (fix_elf)
683 warnf("Note: RPATH has been automatically fixed, but this should be fixed in the package itself");
528} 684}
529static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 685static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
530{ 686{
531 unsigned long i, s; 687 unsigned long i;
532 char *rpath, *runpath, **r; 688 char *rpath, *runpath, **r;
533 void *strtbl_void; 689 void *strtbl_void;
534 690
535 if (!show_rpath) return; 691 if (!show_rpath) return;
536 692
551 /* Just scan dynamic headers */ \ 707 /* Just scan dynamic headers */ \
552 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ 708 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
553 offset = EGET(phdr[i].p_offset); \ 709 offset = EGET(phdr[i].p_offset); \
554 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 710 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
555 /* Just scan dynamic RPATH/RUNPATH headers */ \ 711 /* Just scan dynamic RPATH/RUNPATH headers */ \
556 dyn = DYN ## B (elf->data + offset); \ 712 dyn = DYN ## B (elf->vdata + offset); \
557 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 713 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
558 if (word == DT_RPATH) { \ 714 if (word == DT_RPATH) { \
559 r = &rpath; \ 715 r = &rpath; \
560 } else if (word == DT_RUNPATH) { \ 716 } else if (word == DT_RUNPATH) { \
561 r = &runpath; \ 717 r = &runpath; \
565 } \ 721 } \
566 /* Verify the memory is somewhat sane */ \ 722 /* Verify the memory is somewhat sane */ \
567 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 723 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
568 if (offset < (Elf ## B ## _Off)elf->len) { \ 724 if (offset < (Elf ## B ## _Off)elf->len) { \
569 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 725 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
570 *r = (char*)(elf->data + offset); \ 726 *r = elf->data + offset; \
571 /* cache the length in case we need to nuke this section later on */ \ 727 /* cache the length in case we need to nuke this section later on */ \
572 if (fix_elf) \ 728 if (fix_elf) \
573 offset = strlen(*r); \ 729 offset = strlen(*r); \
574 /* If quiet, don't output paths in ld.so.conf */ \ 730 /* If quiet, don't output paths in ld.so.conf */ \
575 if (be_quiet) { \ 731 if (be_quiet) { \
581 /* scan each path in : delimited list */ \ 737 /* scan each path in : delimited list */ \
582 while (start) { \ 738 while (start) { \
583 rpath_security_checks(elf, start, get_elfdtype(word)); \ 739 rpath_security_checks(elf, start, get_elfdtype(word)); \
584 end = strchr(start, ':'); \ 740 end = strchr(start, ':'); \
585 len = (end ? abs(end - start) : strlen(start)); \ 741 len = (end ? abs(end - start) : strlen(start)); \
586 if (use_ldcache) \ 742 if (use_ldcache) { \
587 for (s = 0; ldpaths[s]; ++s) \ 743 size_t n; \
744 const char *ldpath; \
745 array_for_each(ldpaths, n, ldpath) \
588 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 746 if (!strncmp(ldpath, start, len) && !ldpath[len]) { \
589 *r = end; \ 747 *r = end; \
590 /* corner case ... if RPATH reads "/usr/lib:", we want \ 748 /* corner case ... if RPATH reads "/usr/lib:", we want \
591 * to show ':' rather than '' */ \ 749 * to show ':' rather than '' */ \
592 if (end && end[1] != '\0') \ 750 if (end && end[1] != '\0') \
593 (*r)++; \ 751 (*r)++; \
594 break; \ 752 break; \
595 } \ 753 } \
754 } \
596 if (!*r || !end) \ 755 if (!*r || !end) \
597 break; \ 756 break; \
598 else \ 757 else \
599 start = start + len + 1; \ 758 start = start + len + 1; \
600 } \ 759 } \
666 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 825 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
667 else if (!be_quiet) 826 else if (!be_quiet)
668 xstrcat(ret, " - ", ret_len); 827 xstrcat(ret, " - ", ret_len);
669} 828}
670 829
830/* Defines can be seen in glibc's sysdeps/generic/ldconfig.h */
671#define LDSO_CACHE_MAGIC "ld.so-" 831#define LDSO_CACHE_MAGIC "ld.so-"
672#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1) 832#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
673#define LDSO_CACHE_VER "1.7.0" 833#define LDSO_CACHE_VER "1.7.0"
674#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1) 834#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
675#define FLAG_ANY -1 835#define FLAG_ANY -1
684#define FLAG_X8664_LIB64 0x0300 844#define FLAG_X8664_LIB64 0x0300
685#define FLAG_S390_LIB64 0x0400 845#define FLAG_S390_LIB64 0x0400
686#define FLAG_POWERPC_LIB64 0x0500 846#define FLAG_POWERPC_LIB64 0x0500
687#define FLAG_MIPS64_LIBN32 0x0600 847#define FLAG_MIPS64_LIBN32 0x0600
688#define FLAG_MIPS64_LIBN64 0x0700 848#define FLAG_MIPS64_LIBN64 0x0700
689 849#define FLAG_X8664_LIBX32 0x0800
690static char *lookup_cache_lib(elfobj *, char *); 850#define FLAG_ARM_LIBHF 0x0900
851#define FLAG_AARCH64_LIB64 0x0a00
691 852
692#if defined(__GLIBC__) || defined(__UCLIBC__) 853#if defined(__GLIBC__) || defined(__UCLIBC__)
693 854
694static char *lookup_cache_lib(elfobj *elf, char *fname) 855static char *lookup_cache_lib(elfobj *elf, const char *fname)
695{ 856{
696 int fd = 0; 857 int fd;
697 char *strs; 858 char *strs;
698 static char buf[__PAX_UTILS_PATH_MAX] = ""; 859 static char buf[__PAX_UTILS_PATH_MAX] = "";
699 const char *cachefile = "/etc/ld.so.cache"; 860 const char *cachefile = root_rel_path("/etc/ld.so.cache");
700 struct stat st; 861 struct stat st;
701 862
702 typedef struct { 863 typedef struct {
703 char magic[LDSO_CACHE_MAGIC_LEN]; 864 char magic[LDSO_CACHE_MAGIC_LEN];
704 char version[LDSO_CACHE_VER_LEN]; 865 char version[LDSO_CACHE_VER_LEN];
714 libentry_t *libent; 875 libentry_t *libent;
715 876
716 if (fname == NULL) 877 if (fname == NULL)
717 return NULL; 878 return NULL;
718 879
719 if (ldcache == 0) { 880 if (ldcache == NULL) {
720 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1) 881 if (fstatat(root_fd, cachefile, &st, 0))
882 return NULL;
883
884 fd = openat(root_fd, cachefile, O_RDONLY);
885 if (fd == -1)
721 return NULL; 886 return NULL;
722 887
723 /* cache these values so we only map/unmap the cache file once */ 888 /* cache these values so we only map/unmap the cache file once */
724 ldcache_size = st.st_size; 889 ldcache_size = st.st_size;
725 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); 890 header = ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
726
727 close(fd); 891 close(fd);
728 892
729 if (ldcache == MAP_FAILED) { 893 if (ldcache == MAP_FAILED) {
730 ldcache = 0; 894 ldcache = NULL;
731 return NULL; 895 return NULL;
732 } 896 }
733 897
734 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 898 if (memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
899 memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
900 {
901 munmap(ldcache, ldcache_size);
902 ldcache = NULL;
735 return NULL; 903 return NULL;
736 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
737 return NULL;
738 } 904 }
905 } else
906 header = ldcache;
739 907
740 header = (header_t *) ldcache;
741 libent = (libentry_t *) (ldcache + sizeof(header_t)); 908 libent = ldcache + sizeof(header_t);
742 strs = (char *) &libent[header->nlibs]; 909 strs = (char *) &libent[header->nlibs];
743 910
744 for (fd = 0; fd < header->nlibs; fd++) { 911 for (fd = 0; fd < header->nlibs; ++fd) {
745 /* this should be more fine grained, but for now we assume that 912 /* This should be more fine grained, but for now we assume that
746 * diff arches will not be cached together. and we ignore the 913 * diff arches will not be cached together, and we ignore the
747 * the different multilib mips cases. */ 914 * the different multilib mips cases.
915 */
748 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK)) 916 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
749 continue; 917 continue;
750 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK)) 918 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
751 continue; 919 continue;
752 920
753 if (strcmp(fname, strs + libent[fd].sooffset) != 0) 921 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
754 continue; 922 continue;
923
924 /* Return first hit because that is how the ldso rolls */
755 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 925 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
926 break;
756 } 927 }
928
757 return buf; 929 return buf;
758} 930}
931
759#elif defined(__NetBSD__) 932#elif defined(__NetBSD__)
760static char *lookup_cache_lib(elfobj *elf, char *fname) 933static char *lookup_cache_lib(elfobj *elf, const char *fname)
761{ 934{
762 static char buf[__PAX_UTILS_PATH_MAX] = ""; 935 static char buf[__PAX_UTILS_PATH_MAX] = "";
763 static struct stat st; 936 static struct stat st;
764 937 size_t n;
765 char **ldpath; 938 char *ldpath;
766 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) { 939
940 array_for_each(ldpath, n, ldpath) {
767 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf)) 941 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", ldpath, fname) >= sizeof(buf))
768 continue; /* if the pathname is too long, or something went wrong, ignore */ 942 continue; /* if the pathname is too long, or something went wrong, ignore */
769 943
770 if (stat(buf, &st) != 0) 944 if (stat(buf, &st) != 0)
771 continue; /* if the lib doesn't exist in *ldpath, look further */ 945 continue; /* if the lib doesn't exist in *ldpath, look further */
772 946
783} 957}
784#else 958#else
785#ifdef __ELF__ 959#ifdef __ELF__
786#warning Cache support not implemented for your target 960#warning Cache support not implemented for your target
787#endif 961#endif
788static char *lookup_cache_lib(elfobj *elf, char *fname) 962static char *lookup_cache_lib(elfobj *elf, const char *fname)
789{ 963{
790 return NULL; 964 return NULL;
791} 965}
792#endif 966#endif
967
968static char *lookup_config_lib(const char *fname)
969{
970 static char buf[__PAX_UTILS_PATH_MAX] = "";
971 const char *ldpath;
972 size_t n;
973
974 array_for_each(ldpaths, n, ldpath) {
975 snprintf(buf, sizeof(buf), "%s/%s", root_rel_path(ldpath), fname);
976 if (faccessat(root_fd, buf, F_OK, AT_SYMLINK_NOFOLLOW) == 0)
977 return buf;
978 }
979
980 return NULL;
981}
793 982
794static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 983static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
795{ 984{
796 unsigned long i; 985 unsigned long i;
797 char *needed; 986 char *needed;
798 void *strtbl_void; 987 void *strtbl_void;
799 char *p; 988 char *p;
800 989
990 /*
991 * -n -> op==0 -> print all
992 * -N -> op==1 -> print requested
993 */
801 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 994 if ((op == 0 && !show_needed) || (op == 1 && !find_lib))
995 return NULL;
802 996
803 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 997 strtbl_void = elf_findsecbyname(elf, ".dynstr");
804 998
805 if (elf->phdr && strtbl_void) { 999 if (elf->phdr && strtbl_void) {
806#define SHOW_NEEDED(B) \ 1000#define SHOW_NEEDED(B) \
808 Elf ## B ## _Dyn *dyn; \ 1002 Elf ## B ## _Dyn *dyn; \
809 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 1003 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
810 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 1004 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
811 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 1005 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
812 Elf ## B ## _Off offset; \ 1006 Elf ## B ## _Off offset; \
1007 size_t matched = 0; \
1008 /* Walk all the program headers to find the PT_DYNAMIC */ \
813 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 1009 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
814 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ 1010 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) \
1011 continue; \
815 offset = EGET(phdr[i].p_offset); \ 1012 offset = EGET(phdr[i].p_offset); \
816 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 1013 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) \
1014 continue; \
1015 /* Walk all the dynamic tags to find NEEDED entries */ \
817 dyn = DYN ## B (elf->data + offset); \ 1016 dyn = DYN ## B (elf->vdata + offset); \
818 while (EGET(dyn->d_tag) != DT_NULL) { \ 1017 while (EGET(dyn->d_tag) != DT_NULL) { \
819 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 1018 if (EGET(dyn->d_tag) == DT_NEEDED) { \
820 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 1019 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
821 if (offset >= (Elf ## B ## _Off)elf->len) { \ 1020 if (offset >= (Elf ## B ## _Off)elf->len) { \
822 ++dyn; \ 1021 ++dyn; \
823 continue; \ 1022 continue; \
824 } \ 1023 } \
825 needed = (char*)(elf->data + offset); \ 1024 needed = elf->data + offset; \
826 if (op == 0) { \ 1025 if (op == 0) { \
1026 /* -n -> print all entries */ \
827 if (!be_wewy_wewy_quiet) { \ 1027 if (!be_wewy_wewy_quiet) { \
828 if (*found_needed) xchrcat(ret, ',', ret_len); \ 1028 if (*found_needed) xchrcat(ret, ',', ret_len); \
829 if (use_ldcache) \ 1029 if (use_ldpath) { \
1030 if ((p = lookup_config_lib(needed)) != NULL) \
1031 needed = p; \
1032 } else if (use_ldcache) { \
830 if ((p = lookup_cache_lib(elf, needed)) != NULL) \ 1033 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
831 needed = p; \ 1034 needed = p; \
1035 } \
832 xstrcat(ret, needed, ret_len); \ 1036 xstrcat(ret, needed, ret_len); \
833 } \ 1037 } \
834 *found_needed = 1; \ 1038 *found_needed = 1; \
835 } else { \ 1039 } else { \
836 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \ 1040 /* -N -> print matching entries */ \
1041 size_t n; \
1042 const char *find_lib_name; \
1043 \
1044 array_for_each(find_lib_arr, n, find_lib_name) { \
1045 int invert = 1; \
1046 if (find_lib_name[0] == '!') \
1047 invert = 0, ++find_lib_name; \
1048 if (!strcmp(find_lib_name, needed) == invert) \
1049 ++matched; \
1050 } \
1051 \
1052 if (matched == array_cnt(find_lib_arr)) { \
837 *found_lib = 1; \ 1053 *found_lib = 1; \
838 return (be_wewy_wewy_quiet ? NULL : needed); \ 1054 return (be_wewy_wewy_quiet ? NULL : find_lib); \
839 } \ 1055 } \
840 } \ 1056 } \
841 } \ 1057 } \
842 ++dyn; \ 1058 ++dyn; \
843 } \ 1059 } \
865 *found_interp = 1; \ 1081 *found_interp = 1; \
866 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \ 1082 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
867 } 1083 }
868 SHOW_INTERP(32) 1084 SHOW_INTERP(32)
869 SHOW_INTERP(64) 1085 SHOW_INTERP(64)
1086 } else {
1087 /* Walk all the program headers to find the PT_INTERP */
1088#define SHOW_PT_INTERP(B) \
1089 if (elf->elf_class == ELFCLASS ## B) { \
1090 unsigned long i; \
1091 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
1092 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
1093 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
1094 if (EGET(phdr[i].p_type) != PT_INTERP) \
1095 continue; \
1096 *found_interp = 1; \
1097 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(phdr[i].p_offset)); \
1098 } \
870 } 1099 }
1100 SHOW_PT_INTERP(32)
1101 SHOW_PT_INTERP(64)
1102 }
1103
871 return NULL; 1104 return NULL;
872} 1105}
873static char *scanelf_file_bind(elfobj *elf, char *found_bind) 1106static const char *scanelf_file_bind(elfobj *elf, char *found_bind)
874{ 1107{
875 unsigned long i; 1108 unsigned long i;
876 struct stat s; 1109 struct stat s;
877 char dynamic = 0; 1110 bool dynamic = false;
878 1111
879 if (!show_bind) return NULL; 1112 if (!show_bind) return NULL;
880 if (!elf->phdr) return NULL; 1113 if (!elf->phdr) return NULL;
881 1114
882#define SHOW_BIND(B) \ 1115#define SHOW_BIND(B) \
885 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 1118 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
886 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 1119 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
887 Elf ## B ## _Off offset; \ 1120 Elf ## B ## _Off offset; \
888 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 1121 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
889 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ 1122 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
890 dynamic = 1; \ 1123 dynamic = true; \
891 offset = EGET(phdr[i].p_offset); \ 1124 offset = EGET(phdr[i].p_offset); \
892 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 1125 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
893 dyn = DYN ## B (elf->data + offset); \ 1126 dyn = DYN ## B (elf->vdata + offset); \
894 while (EGET(dyn->d_tag) != DT_NULL) { \ 1127 while (EGET(dyn->d_tag) != DT_NULL) { \
895 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 1128 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
896 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \ 1129 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
897 { \ 1130 { \
898 if (be_quiet) return NULL; \ 1131 if (be_quiet) return NULL; \
911 /* don't output anything if quiet mode and the ELF is static or not setuid */ 1144 /* don't output anything if quiet mode and the ELF is static or not setuid */
912 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) { 1145 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
913 return NULL; 1146 return NULL;
914 } else { 1147 } else {
915 *found_bind = 1; 1148 *found_bind = 1;
916 return (char *) (dynamic ? "LAZY" : "STATIC"); 1149 return dynamic ? "LAZY" : "STATIC";
917 } 1150 }
918} 1151}
919static char *scanelf_file_soname(elfobj *elf, char *found_soname) 1152static char *scanelf_file_soname(elfobj *elf, char *found_soname)
920{ 1153{
921 unsigned long i; 1154 unsigned long i;
939 return NULL; \ 1172 return NULL; \
940 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 1173 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
941 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ 1174 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
942 offset = EGET(phdr[i].p_offset); \ 1175 offset = EGET(phdr[i].p_offset); \
943 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 1176 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
944 dyn = DYN ## B (elf->data + offset); \ 1177 dyn = DYN ## B (elf->vdata + offset); \
945 while (EGET(dyn->d_tag) != DT_NULL) { \ 1178 while (EGET(dyn->d_tag) != DT_NULL) { \
946 if (EGET(dyn->d_tag) == DT_SONAME) { \ 1179 if (EGET(dyn->d_tag) == DT_SONAME) { \
947 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 1180 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
948 if (offset >= (Elf ## B ## _Off)elf->len) { \ 1181 if (offset >= (Elf ## B ## _Off)elf->len) { \
949 ++dyn; \ 1182 ++dyn; \
950 continue; \ 1183 continue; \
951 } \ 1184 } \
952 soname = (char*)(elf->data + offset); \ 1185 soname = elf->data + offset; \
953 *found_soname = 1; \ 1186 *found_soname = 1; \
954 return (be_wewy_wewy_quiet ? NULL : soname); \ 1187 return (be_wewy_wewy_quiet ? NULL : soname); \
955 } \ 1188 } \
956 ++dyn; \ 1189 ++dyn; \
957 } \ 1190 } \
961 } 1194 }
962 1195
963 return NULL; 1196 return NULL;
964} 1197}
965 1198
966static int scanelf_match_symname(const char *symname, const char *tomatch) { 1199/*
967 /* We do things differently when checking with regexp */ 1200 * We support the symbol form:
968 if (g_match) { 1201 * [%[modifiers]%][[+-]<symbol name>][,[.....]]
969 return rematch(symname, tomatch, REG_EXTENDED) == 0; 1202 * If the symbol name is empty, then all symbols are matched.
1203 * If the symbol name is a glob ("*"), then all symbols are dumped (debug).
1204 * Do not rely on this output format at all.
1205 * Otherwise the symbol name is used to search (either regex or string compare).
1206 * If the first char of the symbol name is a plus ("+"), then only match
1207 * defined symbols. If it's a minus ("-"), only match undefined symbols.
1208 * Putting modifiers in between the percent signs allows for more in depth
1209 * filters. There are groups of modifiers. If you don't specify a member
1210 * of a group, then all types in that group are matched. The current
1211 * groups and their types are:
1212 * STT group: STT_NOTYPE:n STT_OBJECT:o STT_FUNC:f STT_FILE:F
1213 * STB group: STB_LOCAL:l STB_GLOBAL:g STB_WEAK:w
1214 * STV group: STV_DEFAULT:p STV_INTERNAL:i STV_HIDDEN:h STV_PROTECTED:P
1215 * SHN group: SHN_UNDEF:u SHN_ABS:a SHN_COMMON:c {defined}:d
1216 * The "defined" value in the SHN group does not correspond to a SHN_xxx define.
1217 * You can search for multiple symbols at once by seperating with a comma (",").
1218 *
1219 * Some examples:
1220 * ELFs with a weak function "foo":
1221 * scanelf -s %wf%foo <ELFs>
1222 * ELFs that define the symbol "main":
1223 * scanelf -s +main <ELFs>
1224 * scanelf -s %d%main <ELFs>
1225 * ELFs that refer to the undefined symbol "brk":
1226 * scanelf -s -brk <ELFs>
1227 * scanelf -s %u%brk <ELFs>
1228 * All global defined objects in an ELF:
1229 * scanelf -s %ogd% <ELF>
1230 */
1231static void
1232scanelf_match_symname(elfobj *elf, char *found_sym, char **ret, size_t *ret_len, const char *symname,
1233 unsigned int stt, unsigned int stb, unsigned int stv, unsigned int shn, unsigned long size)
1234{
1235 const char *this_sym;
1236 size_t n;
1237
1238 array_for_each(find_sym_arr, n, this_sym) {
1239 bool inc_notype, inc_object, inc_func, inc_file,
1240 inc_local, inc_global, inc_weak,
1241 inc_visdef, inc_intern, inc_hidden, inc_prot,
1242 inc_def, inc_undef, inc_abs, inc_common;
1243
1244 /* symbol selection! */
1245 inc_notype = inc_object = inc_func = inc_file =
1246 inc_local = inc_global = inc_weak =
1247 inc_visdef = inc_intern = inc_hidden = inc_prot =
1248 inc_def = inc_undef = inc_abs = inc_common =
1249 (*this_sym != '%');
1250
1251 /* parse the contents of %...% */
1252 if (!inc_notype) {
1253 while (*(this_sym++)) {
1254 if (*this_sym == '%') {
1255 ++this_sym;
1256 break;
1257 }
1258 switch (*this_sym) {
1259 case 'n': inc_notype = true; break;
1260 case 'o': inc_object = true; break;
1261 case 'f': inc_func = true; break;
1262 case 'F': inc_file = true; break;
1263 case 'l': inc_local = true; break;
1264 case 'g': inc_global = true; break;
1265 case 'w': inc_weak = true; break;
1266 case 'p': inc_visdef = true; break;
1267 case 'i': inc_intern = true; break;
1268 case 'h': inc_hidden = true; break;
1269 case 'P': inc_prot = true; break;
1270 case 'd': inc_def = true; break;
1271 case 'u': inc_undef = true; break;
1272 case 'a': inc_abs = true; break;
1273 case 'c': inc_common = true; break;
1274 default: err("invalid symbol selector '%c'", *this_sym);
1275 }
1276 }
1277
1278 /* If no types are matched, not match all */
1279 if (!inc_notype && !inc_object && !inc_func && !inc_file)
1280 inc_notype = inc_object = inc_func = inc_file = true;
1281 if (!inc_local && !inc_global && !inc_weak)
1282 inc_local = inc_global = inc_weak = true;
1283 if (!inc_visdef && !inc_intern && !inc_hidden && !inc_prot)
1284 inc_visdef = inc_intern = inc_hidden = inc_prot = true;
1285 if (!inc_def && !inc_undef && !inc_abs && !inc_common)
1286 inc_def = inc_undef = inc_abs = inc_common = true;
1287
1288 /* backwards compat for defined/undefined short hand */
1289 } else if (*this_sym == '+') {
1290 inc_undef = false;
1291 ++this_sym;
1292 } else if (*this_sym == '-') {
1293 inc_def = inc_abs = inc_common = false;
1294 ++this_sym;
1295 }
1296
1297 /* filter symbols */
1298 if ((!inc_notype && stt == STT_NOTYPE ) || \
1299 (!inc_object && stt == STT_OBJECT ) || \
1300 (!inc_func && stt == STT_FUNC ) || \
1301 (!inc_file && stt == STT_FILE ) || \
1302 (!inc_local && stb == STB_LOCAL ) || \
1303 (!inc_global && stb == STB_GLOBAL ) || \
1304 (!inc_weak && stb == STB_WEAK ) || \
1305 (!inc_visdef && stv == STV_DEFAULT ) || \
1306 (!inc_intern && stv == STV_INTERNAL ) || \
1307 (!inc_hidden && stv == STV_HIDDEN ) || \
1308 (!inc_prot && stv == STV_PROTECTED) || \
1309 (!inc_def && shn && shn < SHN_LORESERVE) || \
1310 (!inc_undef && shn == SHN_UNDEF ) || \
1311 (!inc_abs && shn == SHN_ABS ) || \
1312 (!inc_common && shn == SHN_COMMON ))
1313 continue;
1314
1315 if (*this_sym == '*') {
1316 /* a "*" symbol gets you debug output */
1317 printf("%s(%s) %5lX %-15s %-15s %-15s %-15s %s\n",
1318 ((*found_sym == 0) ? "\n\t" : "\t"),
1319 elf->base_filename,
1320 size,
1321 get_elfstttype(stt),
1322 get_elfstbtype(stb),
1323 get_elfstvtype(stv),
1324 get_elfshntype(shn),
1325 symname);
1326 goto matched;
1327
970 } else { 1328 } else {
1329 if (g_match) {
1330 /* regex match the symbol */
1331 if (regexec(find_sym_regex_arr->eles[n], symname, 0, NULL, 0) == REG_NOMATCH)
1332 continue;
1333
1334 } else if (*this_sym) {
1335 /* give empty symbols a "pass", else do a normal compare */
971 const size_t symname_len = strlen(symname); 1336 const size_t len = strlen(this_sym);
972 return (strncmp(symname, tomatch, symname_len) == 0 && 1337 if (!(strncmp(this_sym, symname, len) == 0 &&
973 /* Accept unversioned symbol names */ 1338 /* Accept unversioned symbol names */
974 (tomatch[symname_len] == '\0' || tomatch[symname_len] == '@')); 1339 (symname[len] == '\0' || symname[len] == '@')))
1340 continue;
1341 }
1342
1343 if (be_semi_verbose) {
1344 char buf[1024];
1345 snprintf(buf, sizeof(buf), "%lX %s %s",
1346 size,
1347 get_elfstttype(stt),
1348 this_sym);
1349 *ret = xstrdup(buf);
1350 } else {
1351 if (*ret) xchrcat(ret, ',', ret_len);
1352 xstrcat(ret, symname, ret_len);
1353 }
1354
1355 goto matched;
975 } 1356 }
976} 1357 }
977 1358
1359 return;
1360
1361 matched:
1362 *found_sym = 1;
1363}
1364
978static char *scanelf_file_sym(elfobj *elf, char *found_sym) 1365static const char *scanelf_file_sym(elfobj *elf, char *found_sym)
979{ 1366{
980 unsigned long i;
981 char *ret; 1367 char *ret;
982 void *symtab_void, *strtab_void; 1368 void *symtab_void, *strtab_void;
983 1369
984 if (!find_sym) return NULL; 1370 if (!find_sym) return NULL;
985 ret = find_sym; 1371 ret = NULL;
986 1372
987 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 1373 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
988 1374
989 if (symtab_void && strtab_void) { 1375 if (symtab_void && strtab_void) {
990#define FIND_SYM(B) \ 1376#define FIND_SYM(B) \
991 if (elf->elf_class == ELFCLASS ## B) { \ 1377 if (elf->elf_class == ELFCLASS ## B) { \
992 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 1378 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
993 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 1379 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
994 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 1380 Elf ## B ## _Sym *sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
995 unsigned long cnt = EGET(symtab->sh_entsize); \ 1381 Elf ## B ## _Word i, cnt = EGET(symtab->sh_entsize); \
996 char *symname; \ 1382 char *symname; \
1383 size_t ret_len = 0; \
997 if (cnt) \ 1384 if (cnt) \
998 cnt = EGET(symtab->sh_size) / cnt; \ 1385 cnt = EGET(symtab->sh_size) / cnt; \
999 for (i = 0; i < cnt; ++i) { \ 1386 for (i = 0; i < cnt; ++i) { \
1000 if ((void*)sym > (void*)elf->data_end) { \ 1387 if ((void*)sym > elf->data_end) { \
1001 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \ 1388 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1002 goto break_out; \ 1389 goto break_out; \
1003 } \ 1390 } \
1004 if (sym->st_name) { \ 1391 if (sym->st_name) { \
1005 /* make sure the symbol name is in acceptable memory range */ \ 1392 /* make sure the symbol name is in acceptable memory range */ \
1006 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1393 symname = elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name); \
1007 if ((void*)symname > (void*)elf->data_end) { \ 1394 if ((void*)symname > elf->data_end) { \
1008 warnf("%s: corrupt ELF symbols", elf->filename); \ 1395 warnf("%s: corrupt ELF symbols", elf->filename); \
1009 ++sym; \ 1396 ++sym; \
1010 continue; \ 1397 continue; \
1011 } \ 1398 } \
1012 /* debug display ... show all symbols and some extra info */ \ 1399 scanelf_match_symname(elf, found_sym, \
1013 if (0 && g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \ 1400 &ret, &ret_len, symname, \
1014 printf("%s(%s) %5lX %15s %s %s\n", \ 1401 ELF##B##_ST_TYPE(EGET(sym->st_info)), \
1015 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1402 ELF##B##_ST_BIND(EGET(sym->st_info)), \
1016 elf->base_filename, \ 1403 ELF##B##_ST_VISIBILITY(EGET(sym->st_other)), \
1017 (unsigned long)sym->st_size, \ 1404 EGET(sym->st_shndx), \
1018 get_elfstttype(sym->st_info), \ 1405 /* st_size can be 64bit, but no one is really that big, so screw em */ \
1019 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \ 1406 EGET(sym->st_size)); \
1020 *found_sym = 1; \
1021 } else { \
1022 /* allow the user to specify a comma delimited list of symbols to search for */ \
1023 char *this_sym, *next_sym; \
1024 next_sym = ret; \
1025 while (next_sym) { \
1026 this_sym = next_sym; \
1027 if ((next_sym = strchr(this_sym, ','))) \
1028 next_sym += 1; /* Skip the comma */ \
1029 /* do we want a defined symbol ? */ \
1030 if (*this_sym == '+') { \
1031 if (sym->st_shndx == SHN_UNDEF) \
1032 continue; \
1033 ++this_sym; \
1034 /* do we want an undefined symbol ? */ \
1035 } else if (*this_sym == '-') { \
1036 if (sym->st_shndx != SHN_UNDEF) \
1037 continue; \
1038 ++this_sym; \
1039 } \
1040 if (next_sym) /* Copy it so that we don't have to worry about the final , */ \
1041 this_sym = strndup(this_sym, next_sym-this_sym); \
1042 /* ok, lets compare the name now */ \
1043 if (scanelf_match_symname(this_sym, symname)) { \
1044 if (be_semi_verbose) { \
1045 char buf[126]; \
1046 snprintf(buf, sizeof(buf), "%lX %s %s", \
1047 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1048 ret = buf; \
1049 } else \
1050 ret = symname; \
1051 (*found_sym)++; \
1052 goto break_out; \
1053 } \
1054 if (next_sym) free(this_sym); \
1055 } \
1056 } \
1057 } \ 1407 } \
1058 ++sym; \ 1408 ++sym; \
1059 } } 1409 } \
1410 }
1060 FIND_SYM(32) 1411 FIND_SYM(32)
1061 FIND_SYM(64) 1412 FIND_SYM(64)
1062 } 1413 }
1063 1414
1064break_out: 1415break_out:
1067 if (*find_sym != '*' && *found_sym) 1418 if (*find_sym != '*' && *found_sym)
1068 return ret; 1419 return ret;
1069 if (be_quiet) 1420 if (be_quiet)
1070 return NULL; 1421 return NULL;
1071 else 1422 else
1072 return (char *)" - "; 1423 return " - ";
1073} 1424}
1074 1425
1075static char *scanelf_file_sections(elfobj *elf, char *found_section) 1426static const char *scanelf_file_sections(elfobj *elf, char *found_section)
1076{ 1427{
1077 if (!find_section) 1428 if (!find_section)
1078 return NULL; 1429 return NULL;
1079 1430
1080#define FIND_SECTION(B) \ 1431#define FIND_SECTION(B) \
1081 if (elf->elf_class == ELFCLASS ## B) { \ 1432 if (elf->elf_class == ELFCLASS ## B) { \
1433 size_t matched, n; \
1082 int invert; \ 1434 int invert; \
1435 const char *section_name; \
1083 Elf ## B ## _Shdr *section; \ 1436 Elf ## B ## _Shdr *section; \
1437 \
1438 matched = 0; \
1439 array_for_each(find_section_arr, n, section_name) { \
1084 invert = (*find_section == '!' ? 1 : 0); \ 1440 invert = (*section_name == '!' ? 1 : 0); \
1085 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \ 1441 section = SHDR ## B (elf_findsecbyname(elf, section_name + invert)); \
1086 if ((section == NULL && invert) || (section != NULL && !invert)) \ 1442 if ((section == NULL && invert) || (section != NULL && !invert)) \
1443 ++matched; \
1444 } \
1445 \
1446 if (matched == array_cnt(find_section_arr)) \
1087 *found_section = 1; \ 1447 *found_section = 1; \
1088 } 1448 }
1089 FIND_SECTION(32) 1449 FIND_SECTION(32)
1090 FIND_SECTION(64) 1450 FIND_SECTION(64)
1091 1451
1096 return find_section; 1456 return find_section;
1097 1457
1098 if (be_quiet) 1458 if (be_quiet)
1099 return NULL; 1459 return NULL;
1100 else 1460 else
1101 return (char *)" - "; 1461 return " - ";
1102} 1462}
1103 1463
1104/* scan an elf file and show all the fun stuff */ 1464/* scan an elf file and show all the fun stuff */
1105#define prints(str) write(fileno(stdout), str, strlen(str)) 1465#define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
1106static int scanelf_elfobj(elfobj *elf) 1466static int scanelf_elfobj(elfobj *elf)
1107{ 1467{
1108 unsigned long i; 1468 unsigned long i;
1109 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1469 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1110 found_rpath, found_needed, found_interp, found_bind, found_soname, 1470 found_rpath, found_needed, found_interp, found_bind, found_soname,
1146 case 'x': prints(" PAX "); break; 1506 case 'x': prints(" PAX "); break;
1147 case 'e': prints("STK/REL/PTL "); break; 1507 case 'e': prints("STK/REL/PTL "); break;
1148 case 't': prints("TEXTREL "); break; 1508 case 't': prints("TEXTREL "); break;
1149 case 'r': prints("RPATH "); break; 1509 case 'r': prints("RPATH "); break;
1150 case 'M': prints("CLASS "); break; 1510 case 'M': prints("CLASS "); break;
1511 case 'l':
1151 case 'n': prints("NEEDED "); break; 1512 case 'n': prints("NEEDED "); break;
1152 case 'i': prints("INTERP "); break; 1513 case 'i': prints("INTERP "); break;
1153 case 'b': prints("BIND "); break; 1514 case 'b': prints("BIND "); break;
1154 case 'Z': prints("SIZE "); break; 1515 case 'Z': prints("SIZE "); break;
1155 case 'S': prints("SONAME "); break; 1516 case 'S': prints("SONAME "); break;
1235 case 'I': out = get_elfosabi(elf); break; 1596 case 'I': out = get_elfosabi(elf); break;
1236 case 'Y': out = get_elf_eabi(elf); break; 1597 case 'Y': out = get_elf_eabi(elf); break;
1237 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;; 1598 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;;
1238 default: warnf("'%c' has no scan code?", out_format[i]); 1599 default: warnf("'%c' has no scan code?", out_format[i]);
1239 } 1600 }
1240 if (out) { 1601 if (out)
1241 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1242 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1243 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1244 else
1245 xstrcat(&out_buffer, out, &out_len); 1602 xstrcat(&out_buffer, out, &out_len);
1246 }
1247 } 1603 }
1248 1604
1249#define FOUND_SOMETHING() \ 1605#define FOUND_SOMETHING() \
1250 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1606 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1251 found_rpath || found_needed || found_interp || found_bind || \ 1607 found_rpath || found_needed || found_interp || found_bind || \
1265 1621
1266/* scan a single elf */ 1622/* scan a single elf */
1267static int scanelf_elf(const char *filename, int fd, size_t len) 1623static int scanelf_elf(const char *filename, int fd, size_t len)
1268{ 1624{
1269 int ret = 1; 1625 int ret = 1;
1626 size_t n;
1627 const char *match_etype;
1270 elfobj *elf; 1628 elfobj *elf;
1271 1629
1272 /* verify this is real ELF */ 1630 /* Verify this is a real ELF */
1273 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { 1631 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1274 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 1632 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1275 return ret; 1633 return 2;
1276 } 1634 }
1635
1636 /* Possibly filter based on ELF bitness */
1277 switch (match_bits) { 1637 switch (match_bits) {
1278 case 32: 1638 case 32:
1279 if (elf->elf_class != ELFCLASS32) 1639 if (elf->elf_class != ELFCLASS32)
1280 goto label_done; 1640 goto done;
1281 break; 1641 break;
1282 case 64: 1642 case 64:
1283 if (elf->elf_class != ELFCLASS64) 1643 if (elf->elf_class != ELFCLASS64)
1284 goto label_done; 1644 goto done;
1285 break; 1645 break;
1286 default: break;
1287 } 1646 }
1288 if (strlen(match_etypes)) { 1647
1289 char sbuf[126]; 1648 /* Possibly filter based on the ELF's e_type field */
1290 strncpy(sbuf, match_etypes, sizeof(sbuf)); 1649 array_for_each(match_etypes, n, match_etype)
1291 if (strchr(match_etypes, ',') != NULL) {
1292 char *p;
1293 while ((p = strrchr(sbuf, ',')) != NULL) {
1294 *p = 0;
1295 if (etype_lookup(p+1) == get_etype(elf)) 1650 if (etype_lookup(match_etype) == get_etype(elf))
1296 goto label_ret; 1651 goto scanit;
1297 } 1652 if (array_cnt(match_etypes))
1298 }
1299 if (etype_lookup(sbuf) != get_etype(elf))
1300 goto label_done; 1653 goto done;
1301 }
1302 1654
1303label_ret: 1655 scanit:
1304 ret = scanelf_elfobj(elf); 1656 ret = scanelf_elfobj(elf);
1305 1657
1306label_done: 1658 done:
1307 unreadelf(elf); 1659 unreadelf(elf);
1308 return ret; 1660 return ret;
1309} 1661}
1310 1662
1311/* scan an archive of elfs */ 1663/* scan an archive of elfs */
1319 ar = ar_open_fd(filename, fd); 1671 ar = ar_open_fd(filename, fd);
1320 if (ar == NULL) 1672 if (ar == NULL)
1321 return 1; 1673 return 1;
1322 1674
1323 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0); 1675 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1324 while ((m=ar_next(ar)) != NULL) { 1676 while ((m = ar_next(ar)) != NULL) {
1677 off_t cur_pos = lseek(fd, 0, SEEK_CUR);
1678 if (cur_pos == -1)
1679 errp("lseek() failed");
1325 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size); 1680 elf = readelf_buffer(m->name, ar_buffer + cur_pos, m->size);
1326 if (elf) { 1681 if (elf) {
1327 scanelf_elfobj(elf); 1682 scanelf_elfobj(elf);
1328 unreadelf(elf); 1683 unreadelf(elf);
1329 } 1684 }
1330 } 1685 }
1331 munmap(ar_buffer, len); 1686 munmap(ar_buffer, len);
1332 1687
1333 return 0; 1688 return 0;
1334} 1689}
1335/* scan a file which may be an elf or an archive or some other magical beast */ 1690/* scan a file which may be an elf or an archive or some other magical beast */
1336static int scanelf_file(const char *filename, const struct stat *st_cache) 1691static int scanelf_fileat(int dir_fd, const char *filename, const struct stat *st_cache)
1337{ 1692{
1338 const struct stat *st = st_cache; 1693 const struct stat *st = st_cache;
1339 struct stat symlink_st; 1694 struct stat symlink_st;
1340 int fd; 1695 int fd;
1341 1696
1342 /* always handle regular files and handle symlinked files if no -y */ 1697 /* always handle regular files and handle symlinked files if no -y */
1343 if (S_ISLNK(st->st_mode)) { 1698 if (S_ISLNK(st->st_mode)) {
1344 if (!scan_symlink) return 1; 1699 if (!scan_symlink)
1700 return 1;
1345 stat(filename, &symlink_st); 1701 fstatat(dir_fd, filename, &symlink_st, 0);
1346 st = &symlink_st; 1702 st = &symlink_st;
1347 } 1703 }
1348 1704
1349 if (!S_ISREG(st->st_mode)) { 1705 if (!S_ISREG(st->st_mode)) {
1350 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1706 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1353 1709
1354 if (match_perms) { 1710 if (match_perms) {
1355 if ((st->st_mode | match_perms) != st->st_mode) 1711 if ((st->st_mode | match_perms) != st->st_mode)
1356 return 1; 1712 return 1;
1357 } 1713 }
1358 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1714 fd = openat(dir_fd, filename, (fix_elf ? O_RDWR : O_RDONLY) | O_CLOEXEC);
1715 if (fd == -1) {
1716 if (fix_elf && errno == ETXTBSY)
1717 warnp("%s: could not fix", filename);
1718 else if (be_verbose > 2)
1719 printf("%s: skipping file: %s\n", filename, strerror(errno));
1359 return 1; 1720 return 1;
1721 }
1360 1722
1361 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives) 1723 if (scanelf_elf(filename, fd, st->st_size) == 2) {
1362 /* if it isn't an ELF, maybe it's an .a archive */ 1724 /* if it isn't an ELF, maybe it's an .a archive */
1725 if (scan_archives)
1363 scanelf_archive(filename, fd, st->st_size); 1726 scanelf_archive(filename, fd, st->st_size);
1364 1727
1728 /*
1729 * unreadelf() implicitly closes its fd, so only close it
1730 * when we are returning it in the non-ELF case
1731 */
1365 close(fd); 1732 close(fd);
1733 }
1734
1366 return 0; 1735 return 0;
1367} 1736}
1368 1737
1369/* scan a directory for ET_EXEC files and print when we find one */ 1738/* scan a directory for ET_EXEC files and print when we find one */
1370static int scanelf_dir(const char *path) 1739static int scanelf_dirat(int dir_fd, const char *path)
1371{ 1740{
1372 register DIR *dir; 1741 register DIR *dir;
1373 register struct dirent *dentry; 1742 register struct dirent *dentry;
1374 struct stat st_top, st; 1743 struct stat st_top, st;
1375 char buf[__PAX_UTILS_PATH_MAX]; 1744 char buf[__PAX_UTILS_PATH_MAX], *subpath;
1376 size_t pathlen = 0, len = 0; 1745 size_t pathlen = 0, len = 0;
1377 int ret = 0; 1746 int ret = 0;
1747 int subdir_fd;
1378 1748
1379 /* make sure path exists */ 1749 /* make sure path exists */
1380 if (lstat(path, &st_top) == -1) { 1750 if (fstatat(dir_fd, path, &st_top, AT_SYMLINK_NOFOLLOW) == -1) {
1381 if (be_verbose > 2) printf("%s: does not exist\n", path); 1751 if (be_verbose > 2) printf("%s: does not exist\n", path);
1382 return 1; 1752 return 1;
1383 } 1753 }
1384 1754
1385 /* ok, if it isn't a directory, assume we can open it */ 1755 /* ok, if it isn't a directory, assume we can open it */
1386 if (!S_ISDIR(st_top.st_mode)) { 1756 if (!S_ISDIR(st_top.st_mode))
1387 return scanelf_file(path, &st_top); 1757 return scanelf_fileat(dir_fd, path, &st_top);
1388 }
1389 1758
1390 /* now scan the dir looking for fun stuff */ 1759 /* now scan the dir looking for fun stuff */
1391 if ((dir = opendir(path)) == NULL) { 1760 subdir_fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
1392 warnf("could not opendir %s: %s", path, strerror(errno)); 1761 if (subdir_fd == -1)
1762 dir = NULL;
1763 else
1764 dir = fdopendir(subdir_fd);
1765 if (dir == NULL) {
1766 if (subdir_fd != -1)
1767 close(subdir_fd);
1768 else if (be_verbose > 2)
1769 printf("%s: skipping dir: %s\n", path, strerror(errno));
1393 return 1; 1770 return 1;
1394 } 1771 }
1395 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1772 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1396 1773
1397 pathlen = strlen(path); 1774 subpath = stpcpy(buf, path);
1775 if (subpath[-1] != '/')
1776 *subpath++ = '/';
1777 pathlen = subpath - buf;
1398 while ((dentry = readdir(dir))) { 1778 while ((dentry = readdir(dir))) {
1399 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1779 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1400 continue; 1780 continue;
1781
1782 if (fstatat(subdir_fd, dentry->d_name, &st, AT_SYMLINK_NOFOLLOW) == -1)
1783 continue;
1784
1401 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1785 len = strlen(dentry->d_name);
1402 if (len >= sizeof(buf)) { 1786 if (len + pathlen + 1 >= sizeof(buf)) {
1403 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1787 warnf("Skipping '%s%s': len > sizeof(buf); %zu > %zu\n",
1404 (unsigned long)len, (unsigned long)sizeof(buf)); 1788 path, dentry->d_name, len + pathlen + 1, sizeof(buf));
1405 continue; 1789 continue;
1406 } 1790 }
1407 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name); 1791 memcpy(subpath, dentry->d_name, len);
1408 if (lstat(buf, &st) != -1) { 1792 subpath[len] = '\0';
1793
1409 if (S_ISREG(st.st_mode)) 1794 if (S_ISREG(st.st_mode))
1410 ret = scanelf_file(buf, &st); 1795 ret = scanelf_fileat(dir_fd, buf, &st);
1411 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1796 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1412 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1797 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1413 ret = scanelf_dir(buf); 1798 ret = scanelf_dirat(dir_fd, buf);
1414 }
1415 } 1799 }
1416 } 1800 }
1417 closedir(dir); 1801 closedir(dir);
1802
1418 return ret; 1803 return ret;
1419} 1804}
1805static int scanelf_dir(const char *path)
1806{
1807 return scanelf_dirat(root_fd, root_rel_path(path));
1808}
1420 1809
1421static int scanelf_from_file(const char *filename) 1810static int scanelf_from_file(const char *filename)
1422{ 1811{
1423 FILE *fp = NULL; 1812 FILE *fp;
1424 char *p; 1813 char *p, *path;
1425 char path[__PAX_UTILS_PATH_MAX]; 1814 size_t len;
1426 int ret = 0; 1815 int ret;
1427 1816
1428 if (strcmp(filename, "-") == 0) 1817 if (strcmp(filename, "-") == 0)
1429 fp = stdin; 1818 fp = stdin;
1430 else if ((fp = fopen(filename, "r")) == NULL) 1819 else if ((fp = fopen(filename, "r")) == NULL)
1431 return 1; 1820 return 1;
1432 1821
1433 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1822 path = NULL;
1823 len = 0;
1824 ret = 0;
1825 while (getline(&path, &len, fp) != -1) {
1434 if ((p = strchr(path, '\n')) != NULL) 1826 if ((p = strchr(path, '\n')) != NULL)
1435 *p = 0; 1827 *p = 0;
1436 search_path = path; 1828 search_path = path;
1437 ret = scanelf_dir(path); 1829 ret = scanelf_dir(path);
1438 } 1830 }
1831 free(path);
1832
1439 if (fp != stdin) 1833 if (fp != stdin)
1440 fclose(fp); 1834 fclose(fp);
1835
1441 return ret; 1836 return ret;
1442} 1837}
1443 1838
1444#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__) 1839#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1445 1840
1446static int load_ld_cache_config(int i, const char *fname) 1841static int _load_ld_cache_config(const char *fname)
1447{ 1842{
1448 FILE *fp = NULL; 1843 FILE *fp = NULL;
1449 char *p; 1844 char *p, *path;
1450 char path[__PAX_UTILS_PATH_MAX]; 1845 size_t len;
1846 int curr_fd = -1;
1451 1847
1452 if (i + 1 == ARRAY_SIZE(ldpaths)) 1848 fp = fopenat_r(root_fd, root_rel_path(fname));
1849 if (fp == NULL)
1453 return i; 1850 return -1;
1454 1851
1455 if ((fp = fopen(fname, "r")) == NULL) 1852 path = NULL;
1456 return i; 1853 len = 0;
1457 1854 while (getline(&path, &len, fp) != -1) {
1458 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1459 if ((p = strrchr(path, '\r')) != NULL) 1855 if ((p = strrchr(path, '\r')) != NULL)
1460 *p = 0; 1856 *p = 0;
1461 if ((p = strchr(path, '\n')) != NULL) 1857 if ((p = strchr(path, '\n')) != NULL)
1462 *p = 0; 1858 *p = 0;
1463#ifdef __linux__ 1859
1464 /* recursive includes of the same file will make this segfault. */ 1860 /* recursive includes of the same file will make this segfault. */
1465 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { 1861 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1466 glob64_t gl; 1862 glob_t gl;
1467 size_t x; 1863 size_t x;
1468 char gpath[__PAX_UTILS_PATH_MAX]; 1864 const char *gpath;
1469 1865
1470 memset(gpath, 0, sizeof(gpath)); 1866 /* re-use existing path buffer ... need to be creative */
1471
1472 if (path[8] != '/') 1867 if (path[8] != '/')
1473 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]); 1868 gpath = memcpy(path + 3, "/etc/", 5);
1474 else 1869 else
1475 strncpy(gpath, &path[8], sizeof(gpath)); 1870 gpath = path + 8;
1871 if (root_fd != AT_FDCWD) {
1872 if (curr_fd == -1) {
1873 curr_fd = open(".", O_RDONLY|O_CLOEXEC);
1874 if (fchdir(root_fd))
1875 errp("unable to change to root dir");
1876 }
1877 gpath = root_rel_path(gpath);
1878 }
1476 1879
1477 if ((glob64(gpath, 0, NULL, &gl)) == 0) { 1880 if (glob(gpath, 0, NULL, &gl) == 0) {
1478 for (x = 0; x < gl.gl_pathc; ++x) { 1881 for (x = 0; x < gl.gl_pathc; ++x) {
1479 /* try to avoid direct loops */ 1882 /* try to avoid direct loops */
1480 if (strcmp(gl.gl_pathv[x], fname) == 0) 1883 if (strcmp(gl.gl_pathv[x], fname) == 0)
1481 continue; 1884 continue;
1482 i = load_ld_cache_config(i, gl.gl_pathv[x]); 1885 _load_ld_cache_config(gl.gl_pathv[x]);
1483 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1484 globfree64(&gl);
1485 return i;
1486 }
1487 } 1886 }
1488 globfree64 (&gl); 1887 globfree(&gl);
1489 continue;
1490 } 1888 }
1889
1890 /* failed globs are ignored by glibc */
1891 continue;
1491 } 1892 }
1492#endif 1893
1493 if (*path != '/') 1894 if (*path != '/')
1494 continue; 1895 continue;
1495 1896
1496 ldpaths[i++] = xstrdup(path); 1897 xarraypush_str(ldpaths, path);
1497
1498 if (i + 1 == ARRAY_SIZE(ldpaths))
1499 break;
1500 } 1898 }
1501 ldpaths[i] = NULL; 1899 free(path);
1502 1900
1503 fclose(fp); 1901 fclose(fp);
1902
1903 if (curr_fd != -1) {
1904 if (fchdir(curr_fd))
1905 {/* don't care */}
1906 close(curr_fd);
1907 }
1908
1504 return i; 1909 return 0;
1505} 1910}
1506 1911
1507#elif defined(__FreeBSD__) || (__DragonFly__) 1912#elif defined(__FreeBSD__) || defined(__DragonFly__)
1508 1913
1509static int load_ld_cache_config(int i, const char *fname) 1914static int _load_ld_cache_config(const char *fname)
1510{ 1915{
1511 FILE *fp = NULL; 1916 FILE *fp = NULL;
1512 char *b = NULL, *p; 1917 char *b = NULL, *p;
1513 struct elfhints_hdr hdr; 1918 struct elfhints_hdr hdr;
1514 1919
1515 if (i + 1 == ARRAY_SIZE(ldpaths)) 1920 fp = fopenat_r(root_fd, root_rel_path(fname));
1921 if (fp == NULL)
1516 return i; 1922 return -1;
1517
1518 if ((fp = fopen(fname, "r")) == NULL)
1519 return i;
1520 1923
1521 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) || 1924 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1522 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 || 1925 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1523 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1) 1926 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1524 { 1927 {
1525 fclose(fp); 1928 fclose(fp);
1526 return i; 1929 return -1;
1527 } 1930 }
1528 1931
1529 b = xmalloc(hdr.dirlistlen + 1); 1932 b = xmalloc(hdr.dirlistlen + 1);
1530 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) { 1933 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1531 fclose(fp); 1934 fclose(fp);
1532 free(b); 1935 free(b);
1533 return i; 1936 return -1;
1534 } 1937 }
1535 1938
1536 while ((p = strsep(&b, ":"))) { 1939 while ((p = strsep(&b, ":"))) {
1537 if (*p == '\0') continue; 1940 if (*p == '\0')
1538 ldpaths[i++] = xstrdup(p); 1941 continue;
1539 1942 xarraypush_str(ldpaths, p);
1540 if (i + 1 == ARRAY_SIZE(ldpaths))
1541 break;
1542 } 1943 }
1543 ldpaths[i] = NULL;
1544 1944
1545 free(b); 1945 free(b);
1546 fclose(fp); 1946 fclose(fp);
1547 return i; 1947 return 0;
1548} 1948}
1549 1949
1550#else 1950#else
1551#ifdef __ELF__ 1951#ifdef __ELF__
1552#warning Cache config support not implemented for your target 1952#warning Cache config support not implemented for your target
1553#endif 1953#endif
1554static int load_ld_cache_config(int i, const char *fname) 1954static int _load_ld_cache_config(const char *fname)
1555{ 1955{
1556 memset(ldpaths, 0x00, sizeof(ldpaths));
1557 return 0; 1956 return 0;
1558} 1957}
1559#endif 1958#endif
1959
1960static void load_ld_cache_config(const char *fname)
1961{
1962 bool scan_l, scan_ul, scan_ull;
1963 size_t n;
1964 const char *ldpath;
1965
1966 _load_ld_cache_config(fname);
1967
1968 scan_l = scan_ul = scan_ull = false;
1969 array_for_each(ldpaths, n, ldpath) {
1970 if (!scan_l && !strcmp(ldpath, "/lib")) scan_l = true;
1971 if (!scan_ul && !strcmp(ldpath, "/usr/lib")) scan_ul = true;
1972 if (!scan_ull && !strcmp(ldpath, "/usr/local/lib")) scan_ull = true;
1973 }
1974
1975 if (!scan_l) xarraypush_str(ldpaths, "/lib");
1976 if (!scan_ul) xarraypush_str(ldpaths, "/usr/lib");
1977 if (!scan_ull) xarraypush_str(ldpaths, "/usr/local/lib");
1978}
1560 1979
1561/* scan /etc/ld.so.conf for paths */ 1980/* scan /etc/ld.so.conf for paths */
1562static void scanelf_ldpath(void) 1981static void scanelf_ldpath(void)
1563{ 1982{
1564 char scan_l, scan_ul, scan_ull; 1983 size_t n;
1565 int i = 0; 1984 const char *ldpath;
1566 1985
1567 if (!ldpaths[0]) 1986 array_for_each(ldpaths, n, ldpath)
1568 err("Unable to load any paths from ld.so.conf");
1569
1570 scan_l = scan_ul = scan_ull = 0;
1571
1572 while (ldpaths[i]) {
1573 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1574 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1575 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1576 scanelf_dir(ldpaths[i]); 1987 scanelf_dir(ldpath);
1577 ++i;
1578 }
1579
1580 if (!scan_l) scanelf_dir("/lib");
1581 if (!scan_ul) scanelf_dir("/usr/lib");
1582 if (!scan_ull) scanelf_dir("/usr/local/lib");
1583} 1988}
1584 1989
1585/* scan env PATH for paths */ 1990/* scan env PATH for paths */
1586static void scanelf_envpath(void) 1991static void scanelf_envpath(void)
1587{ 1992{
1598 } 2003 }
1599 2004
1600 free(path); 2005 free(path);
1601} 2006}
1602 2007
1603/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H J K P Q U W */ 2008/* usage / invocation handling functions */ /* Free Flags: c d j u w G H J K P Q U W */
1604#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZBhV" 2009#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZCBhV"
1605#define a_argument required_argument 2010#define a_argument required_argument
1606static struct option const long_opts[] = { 2011static struct option const long_opts[] = {
1607 {"path", no_argument, NULL, 'p'}, 2012 {"path", no_argument, NULL, 'p'},
1608 {"ldpath", no_argument, NULL, 'l'}, 2013 {"ldpath", no_argument, NULL, 'l'},
2014 {"use-ldpath",no_argument, NULL, 129},
2015 {"root", a_argument, NULL, 128},
1609 {"recursive", no_argument, NULL, 'R'}, 2016 {"recursive", no_argument, NULL, 'R'},
1610 {"mount", no_argument, NULL, 'm'}, 2017 {"mount", no_argument, NULL, 'm'},
1611 {"symlink", no_argument, NULL, 'y'}, 2018 {"symlink", no_argument, NULL, 'y'},
1612 {"archives", no_argument, NULL, 'A'}, 2019 {"archives", no_argument, NULL, 'A'},
1613 {"ldcache", no_argument, NULL, 'L'}, 2020 {"ldcache", no_argument, NULL, 'L'},
1637 {"quiet", no_argument, NULL, 'q'}, 2044 {"quiet", no_argument, NULL, 'q'},
1638 {"verbose", no_argument, NULL, 'v'}, 2045 {"verbose", no_argument, NULL, 'v'},
1639 {"format", a_argument, NULL, 'F'}, 2046 {"format", a_argument, NULL, 'F'},
1640 {"from", a_argument, NULL, 'f'}, 2047 {"from", a_argument, NULL, 'f'},
1641 {"file", a_argument, NULL, 'o'}, 2048 {"file", a_argument, NULL, 'o'},
2049 {"nocolor", no_argument, NULL, 'C'},
1642 {"nobanner", no_argument, NULL, 'B'}, 2050 {"nobanner", no_argument, NULL, 'B'},
1643 {"help", no_argument, NULL, 'h'}, 2051 {"help", no_argument, NULL, 'h'},
1644 {"version", no_argument, NULL, 'V'}, 2052 {"version", no_argument, NULL, 'V'},
1645 {NULL, no_argument, NULL, 0x0} 2053 {NULL, no_argument, NULL, 0x0}
1646}; 2054};
1647 2055
1648static const char *opts_help[] = { 2056static const char * const opts_help[] = {
1649 "Scan all directories in PATH environment", 2057 "Scan all directories in PATH environment",
1650 "Scan all directories in /etc/ld.so.conf", 2058 "Scan all directories in /etc/ld.so.conf",
2059 "Use ld.so.conf to show full path (use with -r/-n)",
2060 "Root directory (use with -l or -p)",
1651 "Scan directories recursively", 2061 "Scan directories recursively",
1652 "Don't recursively cross mount points", 2062 "Don't recursively cross mount points",
1653 "Don't scan symlinks", 2063 "Don't scan symlinks",
1654 "Scan archives (.a files)", 2064 "Scan archives (.a files)",
1655 "Utilize ld.so.cache information (use with -r/-n)", 2065 "Utilize ld.so.cache to show full path (use with -r/-n)",
1656 "Try and 'fix' bad things (use with -r/-e)", 2066 "Try and 'fix' bad things (use with -r/-e)",
1657 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n", 2067 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1658 "Print PaX markings", 2068 "Print PaX markings",
1659 "Print GNU_STACK/PT_LOAD markings", 2069 "Print GNU_STACK/PT_LOAD markings",
1660 "Print TEXTREL information", 2070 "Print TEXTREL information",
1664 "Print BIND information", 2074 "Print BIND information",
1665 "Print SONAME information", 2075 "Print SONAME information",
1666 "Find a specified symbol", 2076 "Find a specified symbol",
1667 "Find a specified section", 2077 "Find a specified section",
1668 "Find a specified library", 2078 "Find a specified library",
1669 "Use strncmp to match libraries. (use with -N)", 2079 "Use regex rather than string compare (with -s); specify twice for case insensitive",
1670 "Locate cause of TEXTREL", 2080 "Locate cause of TEXTREL",
1671 "Print only ELF files matching etype ET_DYN,ET_EXEC ...", 2081 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1672 "Print only ELF files matching numeric bits", 2082 "Print only ELF files matching numeric bits",
1673 "Print Endianness", 2083 "Print Endianness",
1674 "Print OSABI", 2084 "Print OSABI",
1675 "Print EABI (EM_ARM Only)", 2085 "Print EABI (EM_ARM Only)",
1676 "Print only ELF files matching octal permissions", 2086 "Print only ELF files matching octal permissions",
1677 "Print ELF file size", 2087 "Print ELF file size",
1678 "Print all scanned info (-x -e -t -r -b)\n", 2088 "Print all useful/simple info\n",
1679 "Only output 'bad' things", 2089 "Only output 'bad' things",
1680 "Be verbose (can be specified more than once)", 2090 "Be verbose (can be specified more than once)",
1681 "Use specified format for output", 2091 "Use specified format for output",
1682 "Read input stream from a filename", 2092 "Read input stream from a filename",
1683 "Write output stream to a filename", 2093 "Write output stream to a filename",
2094 "Don't emit color in output",
1684 "Don't display the header", 2095 "Don't display the header",
1685 "Print this help and exit", 2096 "Print this help and exit",
1686 "Print version and exit", 2097 "Print version and exit",
1687 NULL 2098 NULL
1688}; 2099};
1689 2100
1690/* display usage and exit */ 2101/* display usage and exit */
1691static void usage(int status) 2102static void usage(int status)
1692{ 2103{
1693 unsigned long i; 2104 const char a_arg[] = "<arg>";
2105 size_t a_arg_len = strlen(a_arg) + 2;
2106 size_t i;
2107 int optlen;
1694 printf("* Scan ELF binaries for stuff\n\n" 2108 printf("* Scan ELF binaries for stuff\n\n"
1695 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 2109 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1696 printf("Options: -[%s]\n", PARSE_FLAGS); 2110 printf("Options: -[%s]\n", PARSE_FLAGS);
2111
2112 /* prescan the --long opt length to auto-align */
2113 optlen = 0;
1697 for (i = 0; long_opts[i].name; ++i) 2114 for (i = 0; long_opts[i].name; ++i) {
2115 int l = strlen(long_opts[i].name);
2116 if (long_opts[i].has_arg == a_argument)
2117 l += a_arg_len;
2118 optlen = max(l, optlen);
2119 }
2120
2121 for (i = 0; long_opts[i].name; ++i) {
2122 /* first output the short flag if it has one */
2123 if (long_opts[i].val > '~')
2124 printf(" ");
2125 else
2126 printf(" -%c, ", long_opts[i].val);
2127
2128 /* then the long flag */
1698 if (long_opts[i].has_arg == no_argument) 2129 if (long_opts[i].has_arg == no_argument)
1699 printf(" -%c, --%-14s* %s\n", long_opts[i].val, 2130 printf("--%-*s", optlen, long_opts[i].name);
1700 long_opts[i].name, opts_help[i]);
1701 else 2131 else
1702 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val, 2132 printf("--%s %s %*s", long_opts[i].name, a_arg,
1703 long_opts[i].name, opts_help[i]); 2133 (int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
2134
2135 /* finally the help text */
2136 printf("* %s\n", opts_help[i]);
2137 }
1704 2138
1705 puts("\nFor more information, see the scanelf(1) manpage"); 2139 puts("\nFor more information, see the scanelf(1) manpage");
1706 exit(status); 2140 exit(status);
1707} 2141}
1708 2142
1713 flags |= PF_NO##flag; \ 2147 flags |= PF_NO##flag; \
1714 } else { \ 2148 } else { \
1715 flags &= ~PF_NO##flag; \ 2149 flags &= ~PF_NO##flag; \
1716 flags |= PF_##flag; \ 2150 flags |= PF_##flag; \
1717 } 2151 }
2152static void parse_delimited(array_t *arr, char *arg, const char *delim)
2153{
2154 char *ele = strtok(arg, delim);
2155 if (!ele) /* edge case: -s '' */
2156 xarraypush_str(arr, "");
2157 while (ele) {
2158 xarraypush_str(arr, ele);
2159 ele = strtok(NULL, delim);
2160 }
2161}
1718static int parseargs(int argc, char *argv[]) 2162static int parseargs(int argc, char *argv[])
1719{ 2163{
1720 int i; 2164 int i;
1721 const char *from_file = NULL; 2165 const char *from_file = NULL;
1722 int ret = 0; 2166 int ret = 0;
2167 char load_cache_config = 0;
1723 2168
1724 opterr = 0; 2169 opterr = 0;
1725 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 2170 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1726 switch (i) { 2171 switch (i) {
1727 2172
1735 case 'f': 2180 case 'f':
1736 if (from_file) warn("You prob don't want to specify -f twice"); 2181 if (from_file) warn("You prob don't want to specify -f twice");
1737 from_file = optarg; 2182 from_file = optarg;
1738 break; 2183 break;
1739 case 'E': 2184 case 'E':
1740 strncpy(match_etypes, optarg, sizeof(match_etypes)); 2185 /* historically, this was comma delimited */
2186 parse_delimited(match_etypes, optarg, ",");
1741 break; 2187 break;
1742 case 'M': 2188 case 'M':
1743 match_bits = atoi(optarg); 2189 match_bits = atoi(optarg);
1744 if (match_bits == 0) { 2190 if (match_bits == 0) {
1745 if (strcmp(optarg, "ELFCLASS32") == 0) 2191 if (strcmp(optarg, "ELFCLASS32") == 0)
1752 if (sscanf(optarg, "%o", &match_perms) == -1) 2198 if (sscanf(optarg, "%o", &match_perms) == -1)
1753 match_bits = 0; 2199 match_bits = 0;
1754 break; 2200 break;
1755 case 'o': { 2201 case 'o': {
1756 if (freopen(optarg, "w", stdout) == NULL) 2202 if (freopen(optarg, "w", stdout) == NULL)
1757 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 2203 errp("Could not freopen(%s)", optarg);
1758 break; 2204 break;
1759 } 2205 }
1760 case 'k': 2206 case 'k':
1761 if (find_section) warn("You prob don't want to specify -k twice"); 2207 xarraypush_str(find_section_arr, optarg);
1762 find_section = optarg;
1763 break; 2208 break;
1764 case 's': { 2209 case 's':
1765 if (find_sym) warn("You prob don't want to specify -s twice"); 2210 /* historically, this was comma delimited */
1766 find_sym = optarg; 2211 parse_delimited(find_sym_arr, optarg, ",");
1767 break; 2212 break;
1768 }
1769 case 'N': { 2213 case 'N':
1770 if (find_lib) warn("You prob don't want to specify -N twice"); 2214 xarraypush_str(find_lib_arr, optarg);
1771 find_lib = optarg;
1772 break; 2215 break;
1773 }
1774
1775 case 'F': { 2216 case 'F': {
1776 if (out_format) warn("You prob don't want to specify -F twice"); 2217 if (out_format) warn("You prob don't want to specify -F twice");
1777 out_format = optarg; 2218 out_format = optarg;
1778 break; 2219 break;
1779 } 2220 }
1819 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)))) 2260 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1820 setpax = flags; 2261 setpax = flags;
1821 break; 2262 break;
1822 } 2263 }
1823 case 'Z': show_size = 1; break; 2264 case 'Z': show_size = 1; break;
1824 case 'g': g_match = 1; break; 2265 case 'g': ++g_match; break;
1825 case 'L': use_ldcache = 1; break; 2266 case 'L': load_cache_config = use_ldcache = 1; break;
1826 case 'y': scan_symlink = 0; break; 2267 case 'y': scan_symlink = 0; break;
1827 case 'A': scan_archives = 1; break; 2268 case 'A': scan_archives = 1; break;
2269 case 'C': color_init(true); break;
1828 case 'B': show_banner = 0; break; 2270 case 'B': show_banner = 0; break;
1829 case 'l': scan_ldpath = 1; break; 2271 case 'l': load_cache_config = scan_ldpath = 1; break;
1830 case 'p': scan_envpath = 1; break; 2272 case 'p': scan_envpath = 1; break;
1831 case 'R': dir_recurse = 1; break; 2273 case 'R': dir_recurse = 1; break;
1832 case 'm': dir_crossmount = 0; break; 2274 case 'm': dir_crossmount = 0; break;
1833 case 'X': ++fix_elf; break; 2275 case 'X': ++fix_elf; break;
1834 case 'x': show_pax = 1; break; 2276 case 'x': show_pax = 1; break;
1838 case 'n': show_needed = 1; break; 2280 case 'n': show_needed = 1; break;
1839 case 'i': show_interp = 1; break; 2281 case 'i': show_interp = 1; break;
1840 case 'b': show_bind = 1; break; 2282 case 'b': show_bind = 1; break;
1841 case 'S': show_soname = 1; break; 2283 case 'S': show_soname = 1; break;
1842 case 'T': show_textrels = 1; break; 2284 case 'T': show_textrels = 1; break;
1843 case 'q': be_quiet = 1; break; 2285 case 'q': be_quiet = min(be_quiet, 20) + 1; break;
1844 case 'v': be_verbose = (be_verbose % 20) + 1; break; 2286 case 'v': be_verbose = min(be_verbose, 20) + 1; break;
1845 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break; 2287 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1846 case 'D': show_endian = 1; break; 2288 case 'D': show_endian = 1; break;
1847 case 'I': show_osabi = 1; break; 2289 case 'I': show_osabi = 1; break;
1848 case 'Y': show_eabi = 1; break; 2290 case 'Y': show_eabi = 1; break;
2291 case 128:
2292 root_fd = open(optarg, O_RDONLY|O_CLOEXEC);
2293 if (root_fd == -1)
2294 err("Could not open root: %s", optarg);
2295 break;
2296 case 129: load_cache_config = use_ldpath = 1; break;
1849 case ':': 2297 case ':':
1850 err("Option '%c' is missing parameter", optopt); 2298 err("Option '%c' is missing parameter", optopt);
1851 case '?': 2299 case '?':
1852 err("Unknown option '%c' or argument missing", optopt); 2300 err("Unknown option '%c' or argument missing", optopt);
1853 default: 2301 default:
1854 err("Unhandled option '%c'; please report this", i); 2302 err("Unhandled option '%c'; please report this", i);
1855 } 2303 }
1856 } 2304 }
1857 if (show_textrels && be_verbose) { 2305 if (show_textrels && be_verbose)
1858 if (which("objdump") != NULL) 2306 objdump = which("objdump", "OBJDUMP");
1859 has_objdump = 1; 2307 /* precompile all the regexes */
2308 if (g_match) {
2309 regex_t preg;
2310 const char *this_sym;
2311 size_t n;
2312 int flags = REG_EXTENDED | REG_NOSUB | (g_match > 1 ? REG_ICASE : 0);
2313
2314 array_for_each(find_sym_arr, n, this_sym) {
2315 /* see scanelf_match_symname for logic info */
2316 switch (this_sym[0]) {
2317 case '%':
2318 while (*(this_sym++))
2319 if (*this_sym == '%') {
2320 ++this_sym;
2321 break;
2322 }
2323 break;
2324 case '+':
2325 case '-':
2326 ++this_sym;
2327 break;
2328 }
2329 if (*this_sym == '*')
2330 ++this_sym;
2331
2332 ret = regcomp(&preg, this_sym, flags);
2333 if (ret) {
2334 char err[256];
2335 regerror(ret, &preg, err, sizeof(err));
2336 err("regcomp of %s failed: %s", this_sym, err);
2337 }
2338 xarraypush(find_sym_regex_arr, &preg, sizeof(preg));
1860 } 2339 }
2340 }
2341 /* flatten arrays for display */
2342 find_sym = array_flatten_str(find_sym_arr);
2343 find_lib = array_flatten_str(find_lib_arr);
2344 find_section = array_flatten_str(find_section_arr);
1861 /* let the format option override all other options */ 2345 /* let the format option override all other options */
1862 if (out_format) { 2346 if (out_format) {
1863 show_pax = show_phdr = show_textrel = show_rpath = \ 2347 show_pax = show_phdr = show_textrel = show_rpath = \
1864 show_needed = show_interp = show_bind = show_soname = \ 2348 show_needed = show_interp = show_bind = show_soname = \
1865 show_textrels = show_perms = show_endian = show_size = \ 2349 show_textrels = show_perms = show_endian = show_size = \
1893 case 'i': show_interp = 1; break; 2377 case 'i': show_interp = 1; break;
1894 case 'b': show_bind = 1; break; 2378 case 'b': show_bind = 1; break;
1895 case 'S': show_soname = 1; break; 2379 case 'S': show_soname = 1; break;
1896 case 'T': show_textrels = 1; break; 2380 case 'T': show_textrels = 1; break;
1897 default: 2381 default:
1898 err("Invalid format specifier '%c' (byte %i)", 2382 err("invalid format specifier '%c' (byte %i)",
1899 out_format[i], i+1); 2383 out_format[i], i+1);
1900 } 2384 }
1901 } 2385 }
1902 2386
1903 /* construct our default format */ 2387 /* construct our default format */
1926 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 2410 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1927 } 2411 }
1928 if (be_verbose > 2) printf("Format: %s\n", out_format); 2412 if (be_verbose > 2) printf("Format: %s\n", out_format);
1929 2413
1930 /* now lets actually do the scanning */ 2414 /* now lets actually do the scanning */
1931 if (scan_ldpath || use_ldcache) 2415 if (load_cache_config)
1932 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG); 2416 load_ld_cache_config(__PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1933 if (scan_ldpath) scanelf_ldpath(); 2417 if (scan_ldpath) scanelf_ldpath();
1934 if (scan_envpath) scanelf_envpath(); 2418 if (scan_envpath) scanelf_envpath();
1935 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath) 2419 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1936 from_file = "-"; 2420 from_file = "-";
1937 if (from_file) { 2421 if (from_file) {
1943 while (optind < argc) { 2427 while (optind < argc) {
1944 search_path = argv[optind++]; 2428 search_path = argv[optind++];
1945 ret = scanelf_dir(search_path); 2429 ret = scanelf_dir(search_path);
1946 } 2430 }
1947 2431
2432#ifdef __PAX_UTILS_CLEANUP
1948 /* clean up */ 2433 /* clean up */
1949 for (i = 0; ldpaths[i]; ++i)
1950 free(ldpaths[i]); 2434 xarrayfree(ldpaths);
2435 xarrayfree(find_sym_arr);
2436 xarrayfree(find_lib_arr);
2437 xarrayfree(find_section_arr);
2438 free(find_sym);
2439 free(find_lib);
2440 free(find_section);
2441 {
2442 size_t n;
2443 regex_t *preg;
2444 array_for_each(find_sym_regex_arr, n, preg)
2445 regfree(preg);
2446 xarrayfree(find_sym_regex_arr);
2447 }
1951 2448
1952 if (ldcache != 0) 2449 if (ldcache != 0)
1953 munmap(ldcache, ldcache_size); 2450 munmap(ldcache, ldcache_size);
2451#endif
2452
1954 return ret; 2453 return ret;
1955} 2454}
1956 2455
1957static char **get_split_env(const char *envvar) 2456static char **get_split_env(const char *envvar)
1958{ 2457{
1988 return envvals; 2487 return envvals;
1989} 2488}
1990 2489
1991static void parseenv(void) 2490static void parseenv(void)
1992{ 2491{
2492 color_init(false);
1993 qa_textrels = get_split_env("QA_TEXTRELS"); 2493 qa_textrels = get_split_env("QA_TEXTRELS");
1994 qa_execstack = get_split_env("QA_EXECSTACK"); 2494 qa_execstack = get_split_env("QA_EXECSTACK");
1995 qa_wx_load = get_split_env("QA_WX_LOAD"); 2495 qa_wx_load = get_split_env("QA_WX_LOAD");
1996} 2496}
1997 2497
2014 ret = parseargs(argc, argv); 2514 ret = parseargs(argc, argv);
2015 fclose(stdout); 2515 fclose(stdout);
2016#ifdef __PAX_UTILS_CLEANUP 2516#ifdef __PAX_UTILS_CLEANUP
2017 cleanup(); 2517 cleanup();
2018 warn("The calls to add/delete heap should be off:\n" 2518 warn("The calls to add/delete heap should be off:\n"
2019 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n" 2519 "\t- 1 due to the out_buffer not being freed in scanelf_fileat()\n"
2020 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD"); 2520 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
2021#endif 2521#endif
2022 return ret; 2522 return ret;
2023} 2523}
2024 2524

Legend:
Removed from v.1.206  
changed lines
  Added in v.1.269

  ViewVC Help
Powered by ViewVC 1.1.20