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

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

  ViewVC Help
Powered by ViewVC 1.1.20